array(
self::C_STR_FOOTNOTES_SHORT_CODE_START => '((',
self::C_STR_FOOTNOTES_SHORT_CODE_END => '))',
self::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED => '',
self::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED => '',
self::C_STR_FOOTNOTE_SHORTCODE_SYNTAX_VALIDATION_ENABLE => 'yes',
self::C_STR_FOOTNOTES_COUNTER_STYLE => 'arabic_plain',
self::C_STR_COMBINE_IDENTICAL_FOOTNOTES => 'yes',
self::C_STR_FOOTNOTES_HARD_LINKS_ENABLE => 'no',
self::C_STR_REFERRER_FRAGMENT_ID_SLUG => 'r',
self::C_STR_FOOTNOTE_FRAGMENT_ID_SLUG => 'f',
self::C_STR_HARD_LINK_IDS_SEPARATOR => '+',
self::C_INT_FOOTNOTES_SCROLL_OFFSET => 20,
self::C_INT_FOOTNOTES_SCROLL_DURATION => 380,
// 2.5.4 fast-tracked.
self::C_STR_FOOTNOTES_BACKLINK_TOOLTIP_ENABLE => 'yes',
self::C_STR_FOOTNOTES_BACKLINK_TOOLTIP_TEXT => 'Alt+ ←',
self::C_STR_REFERENCE_CONTAINER_NAME => 'References',
self::C_STR_REFERENCE_CONTAINER_LABEL_ELEMENT => 'p',
self::C_STR_REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER => 'yes',
self::C_STR_REFERENCE_CONTAINER_COLLAPSE => 'no',
self::C_STR_FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE => 'jquery',
self::C_STR_REFERENCE_CONTAINER_POSITION => 'post_end',
self::C_STR_REFERENCE_CONTAINER_POSITION_SHORTCODE => '[[references]]',
self::C_STR_REFERENCE_CONTAINER_START_PAGE_ENABLE => 'yes',
// Whether to enqueue additional stylesheet.
self::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT => 'none',
// Top and bottom margins.
self::C_INT_REFERENCE_CONTAINER_TOP_MARGIN => 24,
self::C_INT_REFERENCE_CONTAINER_BOTTOM_MARGIN => 0,
// Table cell borders.
self::C_STR_REFERENCE_CONTAINER_ROW_BORDERS_ENABLE => 'no',
// Backlink symbol.
self::C_STR_REFERENCE_CONTAINER_3COLUMN_LAYOUT_ENABLE => 'no',
self::C_STR_REFERENCE_CONTAINER_BACKLINK_SYMBOL_ENABLE => 'yes',
self::C_STR_REFERENCE_CONTAINER_BACKLINK_SYMBOL_SWITCH => 'no',
// Backlink separators and terminators are often not preferred..
// But a choice must be provided along with the ability to customize.
self::C_STR_BACKLINKS_SEPARATOR_ENABLED => 'yes',
self::C_STR_BACKLINKS_SEPARATOR_OPTION => 'comma',
self::C_STR_BACKLINKS_SEPARATOR_CUSTOM => '',
self::C_STR_BACKLINKS_TERMINATOR_ENABLED => 'no',
self::C_STR_BACKLINKS_TERMINATOR_OPTION => 'full_stop',
self::C_STR_BACKLINKS_TERMINATOR_CUSTOM => '',
// Set backlinks column width.
self::C_STR_BACKLINKS_COLUMN_WIDTH_ENABLED => 'no',
self::C_INT_BACKLINKS_COLUMN_WIDTH_SCALAR => '50',
self::C_STR_BACKLINKS_COLUMN_WIDTH_UNIT => 'px',
// Set backlinks column max. width.
self::C_STR_BACKLINKS_COLUMN_MAX_WIDTH_ENABLED => 'no',
self::C_INT_BACKLINKS_COLUMN_MAX_WIDTH_SCALAR => '140',
self::C_STR_BACKLINKS_COLUMN_MAX_WIDTH_UNIT => 'px',
// Whether a
tag is inserted.
self::C_STR_BACKLINKS_LINE_BREAKS_ENABLED => 'no',
// Whether to enable URL line wrapping.
self::C_STR_FOOTNOTE_URL_WRAP_ENABLED => 'yes',
// Whether to use link elements.
self::C_STR_LINK_ELEMENT_ENABLED => 'yes',
// Excerpt should be disabled.
self::C_STR_FOOTNOTES_IN_EXCERPT => 'no',
self::C_STR_FOOTNOTES_EXPERT_MODE => 'yes',
self::C_STR_FOOTNOTES_LOVE => 'no',
),
'footnotes_storage_custom' => array(
self::C_STR_HYPERLINK_ARROW => '↑',
self::C_STR_HYPERLINK_ARROW_USER_DEFINED => '',
self::C_STR_FOOTNOTES_TOOLTIP_READON_LABEL => 'Continue reading',
self::C_STR_FOOTNOTES_REFERRER_SUPERSCRIPT_TAGS => 'yes',
self::C_STR_FOOTNOTES_STYLING_BEFORE => '[',
self::C_STR_FOOTNOTES_STYLING_AFTER => ']',
self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_ENABLED => 'yes',
self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_ALTERNATIVE => 'no',
// The mouse over content truncation should be enabled by default.
// To raise awareness of the functionality and to prevent the screen.
// From being filled at mouse-over, and to allow the Continue reading.
self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_ENABLED => 'yes',
// The truncation length is raised from 150 to 200 chars.
self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_LENGTH => 200,
// 2.5.4 fast-tracked.
self::C_STR_FOOTNOTES_TOOLTIP_EXCERPT_DELIMITER => '[[/tooltip]]',
self::C_STR_FOOTNOTES_TOOLTIP_EXCERPT_MIRROR_ENABLE => 'no',
self::C_STR_FOOTNOTES_TOOLTIP_EXCERPT_MIRROR_SEPARATOR => ' — ',
self::C_STR_FOOTNOTE_REFERRERS_NORMAL_SUPERSCRIPT => 'no',
// The default position should not be lateral because of the risk.
// The box gets squeezed between note anchor at line end and window edge,.
// And top because reading at the bottom of the window is more likely.
self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_POSITION => 'top center',
self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_X => 0,
// The vertical offset must be negative for the box not to cover.
// The current line of text (web coordinates origin is top left).
self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_Y => -7,
// The width should be limited to start with, for the box to have shape.
self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_MAX_WIDTH => 450,
// Fixed width is for alternative tooltips, cannot reuse max-width nor offsets.
self::C_STR_FOOTNOTES_ALTERNATIVE_MOUSE_OVER_BOX_POSITION => 'top right',
self::C_INT_FOOTNOTES_ALTERNATIVE_MOUSE_OVER_BOX_OFFSET_X => -50,
self::C_INT_FOOTNOTES_ALTERNATIVE_MOUSE_OVER_BOX_OFFSET_Y => 24,
self::C_INT_FOOTNOTES_ALTERNATIVE_MOUSE_OVER_BOX_WIDTH => 400,
// Tooltip display durations.
// Called mouse over box not tooltip for consistency.
self::C_INT_MOUSE_OVER_BOX_FADE_IN_DELAY => 0,
self::C_INT_MOUSE_OVER_BOX_FADE_IN_DURATION => 200,
self::C_INT_MOUSE_OVER_BOX_FADE_OUT_DELAY => 400,
self::C_INT_MOUSE_OVER_BOX_FADE_OUT_DURATION => 200,
// Tooltip font size reset to legacy by default since 2.1.4;.
// Was set to inherit since 2.1.1 as it overrode custom CSS,.
// Is moved to settings since 2.1.4 2020-12-04T1023+0100.
self::C_STR_MOUSE_OVER_BOX_FONT_SIZE_ENABLED => 'yes',
self::C_FLO_MOUSE_OVER_BOX_FONT_SIZE_SCALAR => 13,
self::C_STR_MOUSE_OVER_BOX_FONT_SIZE_UNIT => 'px',
self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_COLOR => '',
// The mouse over box shouldn’t feature a colored background.
// By default, due to diverging user preferences. White is neutral.
self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BACKGROUND => '#ffffff',
self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_WIDTH => 1,
self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BORDER_COLOR => '#cccc99',
// The mouse over box corners mustn’t be rounded as that is outdated.
self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_RADIUS => 0,
self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_SHADOW_COLOR => '#666666',
// Custom CSS migrates to a dedicated tab.
self::C_STR_CUSTOM_CSS => '',
),
'footnotes_storage_expert' => array(
// These are checkboxes; keyword 'checked' is converted to Boolean true,.
// Empty string to false (default).
// Titles should all be enabled by default to prevent users from.
// Thinking at first that the feature is broken in post titles..
// See .
// Yet in titles, footnotes are still buggy, because WordPress.
// Uses the title string in menus and in the title element..
self::C_STR_EXPERT_LOOKUP_THE_TITLE => '',
self::C_STR_EXPERT_LOOKUP_THE_CONTENT => 'checked',
// And the_excerpt is disabled by default following @nikelaos in.
// .
// .
self::C_STR_EXPERT_LOOKUP_THE_EXCERPT => '',
self::C_STR_EXPERT_LOOKUP_WIDGET_TITLE => '',
// The widget_text hook must be disabled by default, because it causes.
// Multiple reference containers to appear in Elementor accordions, but.
// It must be enabled if multiple reference containers are desired, as.
// In Elementor toggles..
self::C_STR_EXPERT_LOOKUP_WIDGET_TEXT => '',
// Initially hard-coded default.
// Shows "9223372036854780000" instead of 9223372036854775807 in the numbox.
// Empty should be interpreted as PHP_INT_MAX, but a numbox cannot be set to empty.
// .
// Interpret -1 as PHP_INT_MAX instead.
self::C_INT_EXPERT_LOOKUP_THE_TITLE_PRIORITY_LEVEL => PHP_INT_MAX,
// Priority level of the_content and of widget_text as the only relevant.
// Hooks must be less than 99 because social buttons may yield scripts.
// That contain the strings '((' and '))', i.e. the default footnote.
// Start and end short codes, causing issues with fake footnotes..
self::C_INT_EXPERT_LOOKUP_THE_CONTENT_PRIORITY_LEVEL => 98,
self::C_INT_EXPERT_LOOKUP_THE_EXCERPT_PRIORITY_LEVEL => PHP_INT_MAX,
self::C_INT_EXPERT_LOOKUP_WIDGET_TITLE_PRIORITY_LEVEL => PHP_INT_MAX,
self::C_INT_EXPERT_LOOKUP_WIDGET_TEXT_PRIORITY_LEVEL => 98,
),
'footnotes_storage_custom_css' => array(
self::C_STR_CUSTOM_CSS_LEGACY_ENABLE => 'yes',
self::C_STR_CUSTOM_CSS_NEW => '',
),
);
/**
* Contains all Settings from each Settings container as soon as this class is initialized.
*
* @since 1.5.0
* @var array
*/
private $a_arr_settings = array();
/**
* Class Constructor. Loads all Settings from each WordPress Settings container.
*
* @since 1.5.0
*/
private function __construct() {
$this->load_all();
}
/**
* Returns a singleton of this class.
*
* @since 1.5.0
* @return MCI_Footnotes_Settings
*/
public static function instance() {
// No instance defined yet, load it.
if ( ! self::$a_obj_instance ) {
self::$a_obj_instance = new self();
}
// Return a singleton of this class.
return self::$a_obj_instance;
}
/**
* Returns the name of a specified Settings Container.
*
* @since 1.5.0
* @param int $p_int_index Settings Container Array Key Index.
* @return str Settings Container name.
*/
public function get_container( $p_int_index ) {
return $this->a_arr_container[ $p_int_index ];
}
/**
* Returns the default values of a specific Settings Container.
*
* @since 1.5.6
* @param int $p_int_index Settings Container Aray Key Index.
* @return array
*/
public function get_defaults( $p_int_index ) {
return $this->a_arr_default[ $this->a_arr_container[ $p_int_index ] ];
}
/**
* Loads all Settings from each Settings container.
*
* @since 1.5.0
*/
private function load_all() {
// Clear current settings.
$this->a_arr_settings = array();
$num_settings = count( $this->a_arr_container );
for ( $i = 0; $i < $num_settings; $i++ ) {
// Load settings.
$this->a_arr_settings = array_merge( $this->a_arr_settings, $this->load( $i ) );
}
}
/**
* Loads all Settings from specified Settings Container.
*
* @since 1.5.0
* @param int $p_int_index Settings Container Array Key Index.
* @return array Settings loaded from Container of Default Settings if Settings Container is empty (first usage).
*
* @since ditched trimming whitespace from text box content in response to user request.
* @link https://wordpress.org/support/topic/leading-space-in-footnotes-tag/#post-5347966
*/
private function load( $p_int_index ) {
// Load all settings from container.
$l_arr_options = get_option( $this->get_container( $p_int_index ) );
// Load all default settings.
$l_arr_default = $this->a_arr_default[ $this->get_container( $p_int_index ) ];
// No settings found, set them to their default value.
if ( empty( $l_arr_options ) ) {
return $l_arr_default;
}
// Iterate through all available settings ( = default values).
foreach ( $l_arr_default as $l_str_key => $l_str_value ) {
// Available setting not found in the container.
if ( ! array_key_exists( $l_str_key, $l_arr_options ) ) {
// Define the setting with its default value.
$l_arr_options[ $l_str_key ] = $l_str_value;
}
}
// Iterate through each setting in the container.
foreach ( $l_arr_options as $l_str_key => $l_str_value ) {
// Remove all whitespace at the beginning and end of a setting.
// Trimming whitespace is ditched.
// $l_str_value = trim($l_str_value);.
// Write the sanitized value back to the setting container.
$l_arr_options[ $l_str_key ] = $l_str_value;
}
// Return settings loaded from Container.
return $l_arr_options;
}
/**
* Updates a whole Settings container.
*
* @since 1.5.0
* @param int $p_int_index Index of the Settings container.
* @param array $p_arr_new_values new Settings.
* @return bool
*/
public function save_options( $p_int_index, $p_arr_new_values ) {
if ( update_option( $this->get_container( $p_int_index ), $p_arr_new_values ) ) {
$this->load_all();
return true;
}
return false;
}
/**
* Returns the value of specified Settings name.
*
* @since 1.5.0
* @param string $p_str_key Settings Array Key name.
* @return mixed Value of the Setting on Success or Null in Settings name is invalid.
*/
public function get( $p_str_key ) {
return array_key_exists( $p_str_key, $this->a_arr_settings ) ? $this->a_arr_settings[ $p_str_key ] : null;
}
/**
* Deletes each Settings Container and loads the default values for each Settings Container.
*
* @since 1.5.0
*
* Edit: This didn’t actually work.
* @since 2.2.0 this function is not called any longer when deleting the plugin,
* to protect user data against loss, since manually updating a plugin is safer
* done by deleting and reinstalling (see the warning about database backup).
* 2020-12-13T1353+0100
*/
public function clear_all() {
// Iterate through each Settings Container.
$num_settings = count( $this->a_arr_container );
for ( $i = 0; $i < $num_settings; $i++ ) {
// Delete the settings container.
delete_option( $this->get_container( $i ) );
}
// Set settings back to the default values.
$this->a_arr_settings = $this->a_arr_default;
}
/**
* Register all Settings Container for the Plugin Settings Page in the Dashboard.
* Settings Container Label will be the same as the Settings Container Name.
*
* @since 1.5.0
*/
public function register_settings() {
// Register all settings.
$num_settings = count( $this->a_arr_container );
for ( $i = 0; $i < $num_settings; $i++ ) {
register_setting( $this->get_container( $i ), $this->get_container( $i ) );
}
}
}