diff --git a/class/config.php b/class/config.php
index cb9b7bd..8f02119 100644
--- a/class/config.php
+++ b/class/config.php
@@ -1,83 +1,74 @@
-foot';
-
- /**
- * Public Plugin name for dashboard heading
- *
- * After properly displaying in dashboard headings until WPv5.4, the above started
- * in WPv5.5 being torn apart as if the headline was text-align:justify and not
- * the last line. That ugly display bug badly affected the plugin’s communication.
- * The only working solution found so far is using position:fixed in one heading
- * that isn’t translated, and dropping the logo in another, translatable heading.
- *
- * @since 2.0.4
- * @var string
- */
- const C_STR_PLUGIN_HEADING_NAME = '';
-
- /**
- * Html tag for the LOVE symbol.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @var string
- */
- const C_STR_LOVE_SYMBOL = '♥';
-
- /**
- * HTML code for the 'love' symbol used in dashboard heading
- *
- * @since 2.0.4
- * @var string
- */
- const C_STR_LOVE_SYMBOL_HEADING = '';
-
- /**
- * Short code to DON'T display the 'LOVE ME' slug on certain pages.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @var string
- */
- const C_STR_NO_LOVE_SLUG = '[[no footnotes: love]]';
-}
+foot';
+
+ /**
+ * Public Plugin name for dashboard heading
+ *
+ * After properly displaying in dashboard headings until WPv5.4, the above started
+ * in WPv5.5 being torn apart as if the headline was text-align:justify and not
+ * the last line. That ugly display bug badly affected the plugin’s communication.
+ * The only working solution found so far is using position:fixed in one heading
+ * that isn’t translated, and dropping the logo in another, translatable heading.
+ *
+ * @since 2.0.4
+ * @var string
+ */
+ const C_STR_PLUGIN_HEADING_NAME = '';
+
+ /**
+ * Html tag for the LOVE symbol.
+ *
+ * @since 1.5.0
+ * @var string
+ */
+ const C_STR_LOVE_SYMBOL = '♥';
+
+ /**
+ * HTML code for the 'love' symbol used in dashboard heading
+ *
+ * @since 2.0.4
+ * @var string
+ */
+ const C_STR_LOVE_SYMBOL_HEADING = '';
+
+ /**
+ * Short code to DON'T display the 'LOVE ME' slug on certain pages.
+ *
+ * @since 1.5.0
+ * @var string
+ */
+ const C_STR_NO_LOVE_SLUG = '[[no footnotes: love]]';
+}
diff --git a/class/convert.php b/class/convert.php
index 767d25c..3adb313 100644
--- a/class/convert.php
+++ b/class/convert.php
@@ -1,229 +1,223 @@
- 26) {
- // increase offset and reduce counter
- $l_int_Offset++;
- $p_int_Value -= 26;
- }
- // if offset set (more then Z), then add a new letter in front
- if ($l_int_Offset > 0) {
- $l_str_Return = chr($l_int_Offset + 64);
- }
- // add the origin letter
- $l_str_Return .= chr($p_int_Value + 64);
- // return the latin character representing the integer
- if ($p_bool_UpperCase) {
- return strtoupper($l_str_Return);
- }
- return strtolower($l_str_Return);
- }
-
- /**
- * Converts an integer to a leading-0 integer.
- *
- * @author Stefan Herndler
- * @since 1.0-gamma
- * @param int $p_int_Value Value/Index to be converted.
- * @return string Value with a leading zero.
- */
- private static function toArabicLeading($p_int_Value) {
- // add a leading 0 if number lower then 10
- if ($p_int_Value < 10) {
- return "0" . $p_int_Value;
- }
- return $p_int_Value;
- }
-
- /**
- * Converts an integer to a romanic letter.
- *
- * @author Stefan Herndler
- * @since 1.0-gamma
- * @param int $p_int_Value Value/Index to be converted.
- * @return string
- *
- * Edited:
- * @since 2.2.0 optionally lowercase (code from Latin) 2020-12-12T1538+0100
- */
- private static function toRomanic($p_int_Value, $p_bool_UpperCase) {
- // table containing all necessary romanic letters
- $l_arr_RomanicLetters = array(
- 'M' => 1000,
- 'CM' => 900,
- 'D' => 500,
- 'CD' => 400,
- 'C' => 100,
- 'XC' => 90,
- 'L' => 50,
- 'XL' => 40,
- 'X' => 10,
- 'IX' => 9,
- 'V' => 5,
- 'IV' => 4,
- 'I' => 1
- );
- // return value
- $l_str_Return = '';
- // iterate through integer value until it is reduced to 0
- while ($p_int_Value > 0) {
- foreach ($l_arr_RomanicLetters as $l_str_Romanic => $l_int_Arabic) {
- if ($p_int_Value >= $l_int_Arabic) {
- $p_int_Value -= $l_int_Arabic;
- $l_str_Return .= $l_str_Romanic;
- break;
- }
- }
- }
- // return romanic letters as string
- if ($p_bool_UpperCase) {
- return strtoupper($l_str_Return);
- }
- return strtolower($l_str_Return);
- }
-
- /**
- * Converts a string depending on its value to a boolean.
- *
- * @author Stefan Herndler
- * @since 1.0-beta
- * @param string $p_str_Value String to be converted to boolean.
- * @return bool Boolean representing the string.
- */
- public static function toBool($p_str_Value) {
- // convert string to lower-case to make it easier
- $p_str_Value = strtolower($p_str_Value);
- // check if string seems to contain a "true" value
- switch ($p_str_Value) {
- case "checked":
- case "yes":
- case "true":
- case "on":
- case "1":
- return true;
- }
- // nothing found that says "true", so we return false
- return false;
- }
-
- /**
- * Get a html Array short code depending on Arrow-Array key index.
- *
- * @author Stefan Herndler
- * @since 1.3.2
- * @param int $p_int_Index Index representing the Arrow. If empty all Arrows are specified.
- * @return array|string Array of all Arrows if Index is empty otherwise html tag of a specific arrow.
- */
- public static function getArrow($p_int_Index = -1) {
- // define all possible arrows
- $l_arr_Arrows = array("↑", "↥", "↟", "↩", "↲", "↵", "⇑", "⇡", "⇧", "↑");
- // convert index to an integer
- if (!is_int($p_int_Index)) {
- $p_int_Index = intval($p_int_Index);
- }
- // return the whole arrow array
- if ($p_int_Index < 0 || $p_int_Index > count($l_arr_Arrows)) {
- return $l_arr_Arrows;
- }
- // return a single arrow
- return $l_arr_Arrows[$p_int_Index];
- }
-
- /**
- * Displays a Variable.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param mixed $p_mixed_Value
- */
- public static function debug($p_mixed_Value) {
- if (empty($p_mixed_Value)) {
- var_dump($p_mixed_Value);
-
- } else if (is_array($p_mixed_Value)) {
- printf("
");
- print_r($p_mixed_Value);
- printf("
");
-
- } else if (is_object($p_mixed_Value)) {
- printf("");
- print_r($p_mixed_Value);
- printf("
");
-
- } else if (is_numeric($p_mixed_Value) || is_int($p_mixed_Value)) {
- var_dump($p_mixed_Value);
-
- } else if (is_date($p_mixed_Value)) {
- var_dump($p_mixed_Value);
-
- } else {
- var_dump($p_mixed_Value);
- }
- echo "
";
- }
-}
+ 26 ) {
+ // Increase offset and reduce counter.
+ $l_int_offset++;
+ $p_int_value -= 26;
+ }
+ // If offset set (more then Z), then add a new letter in front.
+ if ( $l_int_offset > 0 ) {
+ $l_str_return = chr( $l_int_offset + 64 );
+ }
+ // Add the origin letter.
+ $l_str_return .= chr( $p_int_value + 64 );
+ // Return the latin character representing the integer.
+ if ( $p_bool_upper_case ) {
+ return strtoupper( $l_str_return );
+ }
+ return strtolower( $l_str_return );
+ }
+
+ /**
+ * Converts an integer to a leading-0 integer.
+ *
+ * @since 1.0-gamma
+ * @param int $p_int_value Value/Index to be converted.
+ * @return string Value with a leading zero.
+ */
+ private static function to_arabic_leading( $p_int_value ) {
+ // Add a leading 0 if number lower then 10.
+ if ( $p_int_value < 10 ) {
+ return '0' . $p_int_value;
+ }
+ return $p_int_value;
+ }
+
+ /**
+ * Converts an integer to a romanic letter.
+ *
+ * @since 1.0-gamma
+ * @param int $p_int_value Value/Index to be converted.
+ * @param bool $p_bool_upper_case Whether to uppercase.
+ * @return string
+ *
+ * Edited:
+ * @since 2.2.0 optionally lowercase (code from Latin) 2020-12-12T1538+0100
+ */
+ private static function to_romanic( $p_int_value, $p_bool_upper_case ) {
+ // Table containing all necessary romanic letters.
+ $l_arr_romanic_letters = array(
+ 'M' => 1000,
+ 'CM' => 900,
+ 'D' => 500,
+ 'CD' => 400,
+ 'C' => 100,
+ 'XC' => 90,
+ 'L' => 50,
+ 'XL' => 40,
+ 'X' => 10,
+ 'IX' => 9,
+ 'V' => 5,
+ 'IV' => 4,
+ 'I' => 1,
+ );
+ // Return value.
+ $l_str_return = '';
+ // Iterate through integer value until it is reduced to 0.
+ while ( $p_int_value > 0 ) {
+ foreach ( $l_arr_romanic_letters as $l_str_romanic => $l_int_arabic ) {
+ if ( $p_int_value >= $l_int_arabic ) {
+ $p_int_value -= $l_int_arabic;
+ $l_str_return .= $l_str_romanic;
+ break;
+ }
+ }
+ }
+ // Return romanic letters as string.
+ if ( $p_bool_upper_case ) {
+ return strtoupper( $l_str_return );
+ }
+ return strtolower( $l_str_return );
+ }
+
+ /**
+ * Converts a string depending on its value to a boolean.
+ *
+ * @since 1.0-beta
+ * @param string $p_str_value String to be converted to boolean.
+ * @return bool Boolean representing the string.
+ */
+ public static function to_bool( $p_str_value ) {
+ // Convert string to lower-case to make it easier.
+ $p_str_value = strtolower( $p_str_value );
+ // Check if string seems to contain a "true" value.
+ switch ( $p_str_value ) {
+ case 'checked':
+ case 'yes':
+ case 'true':
+ case 'on':
+ case '1':
+ return true;
+ }
+ // Nothing found that says "true", so we return false.
+ return false;
+ }
+
+ /**
+ * Get a html Array short code depending on Arrow-Array key index.
+ *
+ * @since 1.3.2
+ * @param int $p_int_index Index representing the Arrow. If empty all Arrows are specified.
+ * @return array|string Array of all Arrows if Index is empty otherwise html tag of a specific arrow.
+ */
+ public static function get_arrow( $p_int_index = -1 ) {
+ // Define all possible arrows.
+ $l_arr_arrows = array( '↑', '↥', '↟', '↩', '↲', '↵', '⇑', '⇡', '⇧', '↑' );
+ // Convert index to an integer.
+ if ( ! is_int( $p_int_index ) ) {
+ $p_int_index = intval( $p_int_index );
+ }
+ // Return the whole arrow array.
+ if ( $p_int_index < 0 || $p_int_index > count( $l_arr_arrows ) ) {
+ return $l_arr_arrows;
+ }
+ // Return a single arrow.
+ return $l_arr_arrows[ $p_int_index ];
+ }
+
+ // phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_var_dump
+ // phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_print_r
+ /**
+ * Displays a Variable.
+ *
+ * @since 1.5.0
+ * @param mixed $p_mixed_value The variable to display.
+ * @return void
+ */
+ public static function debug( $p_mixed_value ) {
+ if ( empty( $p_mixed_value ) ) {
+ var_dump( $p_mixed_value );
+
+ } elseif ( is_array( $p_mixed_value ) ) {
+ printf( '' );
+ print_r( $p_mixed_value );
+ printf( '
' );
+
+ } elseif ( is_object( $p_mixed_value ) ) {
+ printf( '' );
+ print_r( $p_mixed_value );
+ printf( '
' );
+
+ } elseif ( is_numeric( $p_mixed_value ) || is_int( $p_mixed_value ) ) {
+ var_dump( $p_mixed_value );
+
+ } elseif ( is_date( $p_mixed_value ) ) {
+ var_dump( $p_mixed_value );
+
+ } else {
+ var_dump( $p_mixed_value );
+ }
+ echo '
';
+ }
+ // phpcs:disable
+}
diff --git a/class/hooks.php b/class/hooks.php
index ceb7147..f5c90d1 100644
--- a/class/hooks.php
+++ b/class/hooks.php
@@ -1,94 +1,87 @@
-ClearAll();
- }
-
- /**
- * Add Links to the Plugin in the "installed Plugins" page.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param array $p_arr_Links Current Links.
- * @param string $p_str_PluginFileName Plugins init file name.
- * @return array
- */
- public static function PluginLinks($p_arr_Links, $p_str_PluginFileName) {
- // append link to the WordPress Plugin page
- $p_arr_Links[] = sprintf('%s', __('Support', MCI_Footnotes_Config::C_STR_PLUGIN_NAME));
- // append link to the Settings page
- $p_arr_Links[] = sprintf('%s', admin_url('admin.php?page=mfmmf-footnotes'), __('Settings', MCI_Footnotes_Config::C_STR_PLUGIN_NAME));
- // append link to the PlayPal Donate function
- $p_arr_Links[] = sprintf('%s', __('Donate', MCI_Footnotes_Config::C_STR_PLUGIN_NAME));
- // return new links
- return $p_arr_Links;
- }
-}
+%s', __( 'Support', 'footnotes' ) );
+ // Append link to the settings page.
+ $p_arr_links[] = sprintf( '%s', admin_url( 'admin.php?page=mfmmf-footnotes' ), __( 'Settings', 'footnotes' ) );
+ // Append link to the PayPal donate function.
+ $p_arr_links[] = sprintf( '%s', __( 'Donate', 'footnotes' ) );
+ // Return new links.
+ return $p_arr_links;
+ }
+}
diff --git a/class/init.php b/class/init.php
index 2eb6ff4..45cd4ec 100644
--- a/class/init.php
+++ b/class/init.php
@@ -1,373 +1,385 @@
-initializeDashboard();
- // initialize the Plugin Task
- $this->initializeTask();
-
- // Register all Public Stylesheets and Scripts
- add_action('init', array($this, 'registerPublic'));
- // Enqueue all Public Stylesheets and Scripts
- add_action('wp_enqueue_scripts', array($this, 'registerPublic'));
- // Register all Widgets of the Plugin.
- add_action('widgets_init', array($this, 'initializeWidgets'));
- }
-
- /**
- * Initializes all Widgets of the Plugin.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- *
- *
- * - Update: Fix for deprecated PHP function create_function(), thanks to @psykonevro @daliasued bug reports, thanks to @felipelavinz code contribution
- *
- * @since 1.6.5
- *
- * @contributor @felipelavinz
- * @link https://github.com/media-competence-institute/footnotes/commit/87173d2980c7ff90e12ffee94ca7153e11163793
- *
- * @reporter @psykonevro
- * @link https://wordpress.org/support/topic/bug-function-create_function-is-deprecated/
- * @link https://wordpress.org/support/topic/deprecated-function-create_function-14/
- *
- * @reporter @daliasued
- * @link https://wordpress.org/support/topic/deprecated-function-create_function-14/#post-13312853
- *
- * create_function() was deprecated in PHP 7.2.0 and removed in PHP 8.0.0.
- * @link https://www.php.net/manual/en/function.create-function.php
- *
- * The fix is to move add_action() above into run(),
- * and use the bare register_widget() here.
- * @see self::run()
- *
- * Also, the visibility of initializeWidgets() is not private any longer.
- */
- public function initializeWidgets() {
- register_widget( "MCI_Footnotes_Widget_ReferenceContainer" );
- }
-
- /**
- * Initializes the Dashboard of the Plugin and loads them.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- */
- private function initializeDashboard() {
- new MCI_Footnotes_Layout_Init();
- }
-
- /**
- * Initializes the Plugin Task and registers the Task hooks.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- */
- private function initializeTask() {
- $this->a_obj_Task = new MCI_Footnotes_Task();
- $this->a_obj_Task->registerHooks();
- }
-
- /**
- * Registers and enqueues scripts and stylesheets to the public pages.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- *
- * @since 2.0.0 Update: Tooltips: fix disabling bug by loading jQuery UI library, thanks to @rajinderverma @ericcorbett2 @honlapdavid @mmallett bug reports, thanks to @vonpiernik code contribution.
- * @since 2.0.3 add versioning of public.css for cache busting 2020-10-29T1413+0100
- * @since 2.0.4 add jQuery UI from WordPress 2020-11-01T1902+0100
- * @since 2.1.4 automate passing version number for cache busting 2020-11-30T0646+0100
- * @since 2.1.4 optionally enqueue an extra stylesheet 2020-12-04T2231+0100
- */
- public function registerPublic() {
-
- /**
- * Enqueues external scripts.
- *
- * - Bugfix: Libraries: optimize processes by loading external and internal scripts only if needed, thanks to @docteurfitness issue report.
- *
- * @since 2.5.5
- * @reporter @docteurfitness
- * @link https://wordpress.org/support/topic/simply-speed-optimisation/
- *
- * The condition about tooltips was missing, only the not-alternative-tooltips part was present.
- */
- // set conditions re-used for stylesheet enqueuing:
- self::$a_bool_TooltipsEnabled = MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED ) );
- self::$a_bool_AlternativeTooltipsEnabled = MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ALTERNATIVE ) );
- $l_str_ScriptMode = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE);
-
- /**
- * Enqueues the jQuery library registered by WordPress.
- *
- * - Bugfix: Reference container: optional alternative expanding and collapsing without jQuery for use with hard links, thanks to @hopper87it @pkverma99 issue reports.
- *
- * @since 2.5.6
- *
- * @reporter @hopper87it
- * @link https://wordpress.org/support/topic/footnotes-wp-rocket/
- *
- * jQuery is also used for animated scrolling, so it was loaded by default.
- * The function wp_enqueue_script() avoids loading the same library multiple times.
- * After adding the alternative reference container, jQuery has become optional,
- * but still enabled by default.
- */
- if ( $l_str_ScriptMode == 'jquery' || ( self::$a_bool_TooltipsEnabled && ! self::$a_bool_AlternativeTooltipsEnabled ) ) {
-
- wp_enqueue_script( 'jquery' );
-
- }
-
- if ( self::$a_bool_TooltipsEnabled && ! self::$a_bool_AlternativeTooltipsEnabled ) {
-
- /**
- * Enqueues the jQuery Tools library shipped with the plugin.
- *
- * redacted jQuery.browser, completed minification;
- * see full header in js/jquery.tools.js
- * added versioning 2020-11-18T2150+0100
- * not use '-js' in the handle, is appended automatically
- */
- wp_enqueue_script(
- 'mci-footnotes-jquery-tools',
- plugins_url('footnotes/js/jquery.tools.min.js'),
- array(),
- '1.2.7.redacted.2'
- );
-
- /**
- * Registers jQuery UI from the JavaScript Content Delivery Network.
- *
- * - Update: Tooltips: fix disabling bug by loading jQuery UI library, thanks to @rajinderverma @ericcorbett2 @honlapdavid @mmallett bug reports, thanks to @vonpiernik code contribution.
- *
- * @since 2.0.0
- * Alternatively, fetch jQuery UI from cdnjs.cloudflare.com:
- * @since 2.0.0 add jQueryUI from Cloudflare 2020-10-26T1907+0100
- * Used to add jQuery UI following @vonpiernik:
- * :
- *
- *
- * jQueryUI re-enables the tooltip infobox disabled when WPv5.5 was released.
- *
- * Updated for v2.0.4 by adding jQuery UI from WordPress following @check2020de:
- *
- * See
- *
- * This was enabled in Footnotes v2.0.0 through v2.0.3.
- * Re-added for 2.0.9d1 / 2.1.1d0 to look whether it can fix a broken tooltip display. 2020-11-07T1601+0100/2020-11-08T2246+0100
- */
- //wp_register_script( 'jQueryUI', 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js', null, null, false ); // in header 2020-11-09T2003+0100
- //wp_enqueue_script( 'jQueryUI' );
- /**
- * This is then needed instead of the above first instance:
- * Add jQuery Tools and finish adding jQueryUI: 2020-11-08T1638+0100/2020-11-08T2246+0100
- */
- //wp_enqueue_script('mci-footnotes-js-jquery-tools', plugins_url('../js/jquery.tools.min.js', __FILE__), ['jQueryUI']);
-
- /**
- * Enqueues some jQuery UI libraries registered by WordPress.
- *
- * @since 2.0.4 add jQuery UI from WordPress 2020-11-01T1902+0100
- * If alternative tooltips are enabled, these libraries are not needed.
- */
- wp_enqueue_script( 'jquery-ui-core' );
- wp_enqueue_script( 'jquery-ui-widget' );
- wp_enqueue_script( 'jquery-ui-position' );
- wp_enqueue_script( 'jquery-ui-tooltip' );
-
- }
-
- /**
- * Enables enqueuing a new-scheme stylesheet.
- *
- * @since 2.5.5
- * @date 2021-02-14T1512+0100
- *
- * Enables enqueuing the formatted individual stylesheets if false.
- * WARNING: This facility is designed for development and must NOT be used in production.
- *
- * The Boolean may be set at the bottom of the plugin’s main PHP file.
- * @see footnotes.php
- */
- if ( C_BOOL_CSS_PRODUCTION_MODE === true ) {
-
- /**
- * Enqueues a minified united external stylesheet in production.
- *
- * - Update: Stylesheets: increase speed and energy efficiency by tailoring stylesheets to the needs of the instance, thanks to @docteurfitness design contribution.
- * - Bugfix: Stylesheets: minify to shrink the carbon footprint, increase speed and implement best practice, thanks to @docteurfitness issue report.
- *
- * @since 2.5.5
- * @date 2021-02-14T1543+0100
- *
- * @contributor @docteurfitness
- * @link https://wordpress.org/support/topic/simply-speed-optimisation/
- *
- * @reporter @docteurfitness
- * @link https://wordpress.org/support/topic/simply-speed-optimisation/
- *
- * The dashboard stylesheet is minified as-is.
- * @see class/dashboard/layout.php
- *
- * @since 2.0.3 add versioning of public.css for cache busting.
- * @date 2020-10-29T1413+0100
- * Plugin version number is needed for busting browser caches after each plugin update.
- * @since 2.1.4 automate passing version number for cache busting.
- * @date 2020-11-30T0646+0100
- * The constant C_STR_FOOTNOTES_VERSION is defined at start of footnotes.php.
- *
- * The media scope argument 'all' is the default.
- * No need to use '-css' in the handle, as this is appended automatically.
- */
- // set tooltip mode for use in stylesheet name:
- if ( self::$a_bool_TooltipsEnabled ) {
- if ( self::$a_bool_AlternativeTooltipsEnabled ) {
- $l_str_TooltipMode = 'al';
- $l_str_TComplement = 'ternative-tooltips';
- } else {
- $l_str_TooltipMode = 'jq';
- $l_str_TComplement = 'uery-tooltips';
- }
- } else {
- $l_str_TooltipMode = 'no';
- $l_str_TComplement = '-tooltips';
- }
-
- // set basic responsive page layout mode for use in stylesheet name:
- $l_str_PageLayoutOption = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT);
- switch ( $l_str_PageLayoutOption ) {
- case "reference-container": $l_str_LayoutMode = '1'; break;
- case "entry-content" : $l_str_LayoutMode = '2'; break;
- case "main-content" : $l_str_LayoutMode = '3'; break;
- case "none": default: $l_str_LayoutMode = '0'; break;
- }
-
- // enqueue the tailored united minified stylesheet:
- wp_enqueue_style(
- 'mci-footnotes-' . $l_str_TooltipMode . $l_str_TComplement . '-pagelayout-' . $l_str_PageLayoutOption,
- plugins_url(
- MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/footnotes-' . $l_str_TooltipMode . 'ttbrpl' . $l_str_LayoutMode . '.min.css'
- ),
- array(),
- C_STR_FOOTNOTES_VERSION,
- 'all'
- );
-
- } else {
-
- /**
- * Enqueues external stylesheets, ONLY in development now.
- *
- * @since 2.1.4 optionally enqueue an extra stylesheet.
- * @date 2020-12-04T2231+0100
- *
- * This optional layout fix is useful by lack of layout support.
- */
- wp_enqueue_style( 'mci-footnotes-common', plugins_url( MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-common.css' ), array(), C_STR_FOOTNOTES_VERSION );
- wp_enqueue_style( 'mci-footnotes-tooltips', plugins_url( MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-tooltips.css' ), array(), C_STR_FOOTNOTES_VERSION );
- wp_enqueue_style( 'mci-footnotes-alternative', plugins_url( MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-tooltips-alternative.css' ), array(), C_STR_FOOTNOTES_VERSION );
-
- $l_str_PageLayoutOption = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT);
- if ($l_str_PageLayoutOption != 'none') {
- wp_enqueue_style(
- 'mci-footnotes-layout-' . $l_str_PageLayoutOption,
- plugins_url(
- MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-layout-' . $l_str_PageLayoutOption . '.css'
- ),
- array(),
- C_STR_FOOTNOTES_VERSION,
- 'all'
- );
- }
- }
- }
-}
+initialize_dashboard();
+ // Initialize the Plugin Task.
+ $this->initialize_task();
+
+ // Register all Public Stylesheets and Scripts.
+ add_action( 'init', array( $this, 'register_public' ) );
+ // Enqueue all Public Stylesheets and Scripts.
+ add_action( 'wp_enqueue_scripts', array( $this, 'register_public' ) );
+ // Register all Widgets of the Plugin..
+ add_action( 'widgets_init', array( $this, 'initialize_widgets' ) );
+ }
+
+ /**
+ * Initializes all Widgets of the Plugin.
+ *
+ * @since 1.5.0
+ *
+ * - Update: Fix for deprecated PHP function create_function(), thanks to @psykonevro @daliasued bug reports, thanks to @felipelavinz code contribution
+ *
+ * @since 1.6.5
+ *
+ * @contributor @felipelavinz
+ * @link https://github.com/media-competence-institute/footnotes/commit/87173d2980c7ff90e12ffee94ca7153e11163793
+ *
+ * @reporter @psykonevro
+ * @link https://wordpress.org/support/topic/bug-function-create_function-is-deprecated/
+ * @link https://wordpress.org/support/topic/deprecated-function-create_function-14/
+ *
+ * @reporter @daliasued
+ * @link https://wordpress.org/support/topic/deprecated-function-create_function-14/#post-13312853
+ *
+ * create_function() was deprecated in PHP 7.2.0 and removed in PHP 8.0.0.
+ * @link https://www.php.net/manual/en/function.create-function.php
+ *
+ * The fix is to move add_action() above into run(),
+ * and use the bare register_widget() here.
+ * @see self::run()
+ *
+ * Also, the visibility of initialize_widgets() is not private any longer.
+ */
+ public function initialize_widgets() {
+ register_widget( 'MCI_Footnotes_Widget_Reference_container' );
+ }
+
+ /**
+ * Initializes the Dashboard of the Plugin and loads them.
+ *
+ * @since 1.5.0
+ */
+ private function initialize_dashboard() {
+ new MCI_Footnotes_Layout_Init();
+ }
+
+ /**
+ * Initializes the Plugin Task and registers the Task hooks.
+ *
+ * @since 1.5.0
+ */
+ private function initialize_task() {
+ $this->a_obj_task = new MCI_Footnotes_Task();
+ $this->a_obj_task->register_hooks();
+ }
+
+ /**
+ * Registers and enqueues scripts and stylesheets to the public pages.
+ *
+ * @since 1.5.0
+ *
+ * @since 2.0.0 Update: Tooltips: fix disabling bug by loading jQuery UI library, thanks to @rajinderverma @ericcorbett2 @honlapdavid @mmallett bug reports, thanks to @vonpiernik code contribution.
+ * @since 2.0.3 add versioning of public.css for cache busting 2020-10-29T1413+0100
+ * @since 2.0.4 add jQuery UI from WordPress 2020-11-01T1902+0100
+ * @since 2.1.4 automate passing version number for cache busting 2020-11-30T0646+0100
+ * @since 2.1.4 optionally enqueue an extra stylesheet 2020-12-04T2231+0100
+ */
+ public function register_public() {
+
+ /**
+ * Enqueues external scripts.
+ *
+ * - Bugfix: Libraries: optimize processes by loading external and internal scripts only if needed, thanks to @docteurfitness issue report.
+ *
+ * @since 2.5.5
+ * @reporter @docteurfitness
+ * @link https://wordpress.org/support/topic/simply-speed-optimisation/
+ *
+ * The condition about tooltips was missing, only the not-alternative-tooltips part was present.
+ */
+ // Set conditions re-used for stylesheet enqueuing.
+ self::$a_bool_tooltips_enabled = MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_ENABLED ) );
+ self::$a_bool_alternative_tooltips_enabled = MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_ALTERNATIVE ) );
+ $l_str_script_mode = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE );
+
+ /**
+ * Enqueues the jQuery library registered by WordPress.
+ *
+ * - Bugfix: Reference container: optional alternative expanding and collapsing without jQuery for use with hard links, thanks to @hopper87it @pkverma99 issue reports.
+ *
+ * @since 2.5.6
+ *
+ * @reporter @hopper87it
+ * @link https://wordpress.org/support/topic/footnotes-wp-rocket/
+ *
+ * jQuery is also used for animated scrolling, so it was loaded by default.
+ * The function wp_enqueue_script() avoids loading the same library multiple times.
+ * After adding the alternative reference container, jQuery has become optional,
+ * but still enabled by default.
+ */
+ if ( 'jquery' === $l_str_script_mode || ( self::$a_bool_tooltips_enabled && ! self::$a_bool_alternative_tooltips_enabled ) ) {
+
+ wp_enqueue_script( 'jquery' );
+
+ }
+
+ if ( self::$a_bool_tooltips_enabled && ! self::$a_bool_alternative_tooltips_enabled ) {
+
+ /**
+ * Enqueues the jQuery Tools library shipped with the plugin.
+ *
+ * Redacted jQuery.browser, completed minification;
+ * see full header in js/jquery.tools.js.
+ *
+ * Add versioning.
+ *
+ * @since 2.1.2
+ * @date 2020-11-18T2150+0100
+ *
+ * No '-js' in the handle, is appended automatically.
+ *
+ * Deferring to the footer breaks jQuery tooltip display.
+ * @date 2021-02-23T1105+0100
+ */
+ wp_enqueue_script(
+ 'mci-footnotes-jquery-tools',
+ plugins_url( 'footnotes/js/jquery.tools.min.js' ),
+ array(),
+ '1.2.7.redacted.2',
+ false
+ );
+
+ /**
+ * Enqueues some jQuery UI libraries registered by WordPress.
+ *
+ * - Update: Tooltips: fix disabling bug by loading jQuery UI library, thanks to @rajinderverma @ericcorbett2 @honlapdavid @mmallett bug reports, thanks to @vonpiernik code contribution.
+ *
+ * @since 2.0.0
+ *
+ * @reporter @rajinderverma
+ * @link https://wordpress.org/support/topic/tooltip-hover-not-showing/
+ *
+ * @reporter @ericcorbett2
+ * @link https://wordpress.org/support/topic/tooltip-hover-not-showing/#post-13324142
+ *
+ * @reporter @honlapdavid
+ * @link https://wordpress.org/support/topic/tooltip-hover-not-showing/#post-13355421
+ *
+ * @reporter @mmallett
+ * @link https://wordpress.org/support/topic/tooltip-hover-not-showing/#post-13445437
+ *
+ * Fetch jQuery UI from cdnjs.cloudflare.com.
+ * @since 2.0.0
+ * @date 2020-10-26T1907+0100
+ * @contributor @vonpiernik
+ * @link https://wordpress.org/support/topic/tooltip-hover-not-showing/#post-13456762
+ *
+ * jQueryUI re-enables the tooltip infobox disabled when WPv5.5 was released. * @since 2.1.2
+ *
+ * - Update: Libraries: Load jQuery UI from WordPress, thanks to @check2020de issue report.
+ *
+ * @since 2.0.4
+ * @date 2020-11-01T1902+0100
+ * @reporter @check2020de
+ * @link https://wordpress.org/support/topic/gdpr-issue-with-jquery/
+ * @link https://wordpress.stackexchange.com/questions/273986/correct-way-to-enqueue-jquery-ui
+ *
+ * If alternative tooltips are enabled, these libraries are not needed.
+ */
+ wp_enqueue_script( 'jquery-ui-core' );
+ wp_enqueue_script( 'jquery-ui-widget' );
+ wp_enqueue_script( 'jquery-ui-position' );
+ wp_enqueue_script( 'jquery-ui-tooltip' );
+
+ }
+
+ /**
+ * Enables enqueuing a new-scheme stylesheet.
+ *
+ * @since 2.5.5
+ * @date 2021-02-14T1512+0100
+ *
+ * Enables enqueuing the formatted individual stylesheets if false.
+ * WARNING: This facility is designed for development and must NOT be used in production.
+ *
+ * The Boolean may be set at the bottom of the plugin’s main PHP file.
+ * @see footnotes.php
+ */
+ if ( C_BOOL_CSS_PRODUCTION_MODE === true ) {
+
+ /**
+ * Enqueues a minified united external stylesheet in production.
+ *
+ * - Update: Stylesheets: increase speed and energy efficiency by tailoring stylesheets to the needs of the instance, thanks to @docteurfitness design contribution.
+ * - Bugfix: Stylesheets: minify to shrink the carbon footprint, increase speed and implement best practice, thanks to @docteurfitness issue report.
+ *
+ * @since 2.5.5
+ * @date 2021-02-14T1543+0100
+ *
+ * @contributor @docteurfitness
+ * @link https://wordpress.org/support/topic/simply-speed-optimisation/
+ *
+ * @reporter @docteurfitness
+ * @link https://wordpress.org/support/topic/simply-speed-optimisation/
+ *
+ * The dashboard stylesheet is minified as-is.
+ * @see class/dashboard/layout.php
+ *
+ * @since 2.0.3 add versioning of public.css for cache busting.
+ * @date 2020-10-29T1413+0100
+ * Plugin version number is needed for busting browser caches after each plugin update.
+ * @since 2.1.4 automate passing version number for cache busting.
+ * @date 2020-11-30T0646+0100
+ * The constant C_STR_FOOTNOTES_VERSION is defined at start of footnotes.php.
+ *
+ * The media scope argument 'all' is the default.
+ * No need to use '-css' in the handle, as this is appended automatically.
+ */
+ // Set tooltip mode for use in stylesheet name.
+ if ( self::$a_bool_tooltips_enabled ) {
+ if ( self::$a_bool_alternative_tooltips_enabled ) {
+ $l_str_tooltip_mode_short = 'al';
+ $l_str_tooltip_mode_rest = 'ternative-tooltips';
+ } else {
+ $l_str_tooltip_mode_short = 'jq';
+ $l_str_tooltip_mode_rest = 'uery-tooltips';
+ }
+ } else {
+ $l_str_tooltip_mode_short = 'no';
+ $l_str_tooltip_mode_rest = '-tooltips';
+ }
+
+ // Set basic responsive page layout mode for use in stylesheet name.
+ $l_str_page_layout_option = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT );
+ switch ( $l_str_page_layout_option ) {
+ case 'reference-container':
+ $l_str_layout_mode = '1';
+ break;
+ case 'entry-content':
+ $l_str_layout_mode = '2';
+ break;
+ case 'main-content':
+ $l_str_layout_mode = '3';
+ break;
+ case 'none':
+ default:
+ $l_str_layout_mode = '0';
+ break;
+ }
+
+ // Enqueue the tailored united minified stylesheet.
+ wp_enqueue_style(
+ 'mci-footnotes-' . $l_str_tooltip_mode_short . $l_str_tooltip_mode_rest . '-pagelayout-' . $l_str_page_layout_option,
+ plugins_url(
+ MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/footnotes-' . $l_str_tooltip_mode_short . 'ttbrpl' . $l_str_layout_mode . '.min.css'
+ ),
+ array(),
+ C_STR_FOOTNOTES_VERSION,
+ 'all'
+ );
+
+ } else {
+
+ /**
+ * Enqueues external stylesheets, ONLY in development now.
+ *
+ * @since 2.1.4 optionally enqueue an extra stylesheet.
+ * @date 2020-12-04T2231+0100
+ *
+ * This optional layout fix is useful by lack of layout support.
+ */
+ wp_enqueue_style( 'mci-footnotes-common', plugins_url( MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-common.css' ), array(), C_STR_FOOTNOTES_VERSION );
+ wp_enqueue_style( 'mci-footnotes-tooltips', plugins_url( MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-tooltips.css' ), array(), C_STR_FOOTNOTES_VERSION );
+ wp_enqueue_style( 'mci-footnotes-alternative', plugins_url( MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-tooltips-alternative.css' ), array(), C_STR_FOOTNOTES_VERSION );
+
+ $l_str_page_layout_option = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT );
+ if ( 'none' !== $l_str_page_layout_option ) {
+ wp_enqueue_style(
+ 'mci-footnotes-layout-' . $l_str_page_layout_option,
+ plugins_url(
+ MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/dev-layout-' . $l_str_page_layout_option . '.css'
+ ),
+ array(),
+ C_STR_FOOTNOTES_VERSION,
+ 'all'
+ );
+ }
+ }
+ }
+}
diff --git a/class/language.php b/class/language.php
index 6172cdf..fd86a8c 100644
--- a/class/language.php
+++ b/class/language.php
@@ -1,108 +1,100 @@
- 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_BOOL_FOOTNOTE_SHORTCODE_SYNTAX_VALIDATION_ENABLE => 'yes',
-
- self::C_STR_FOOTNOTES_COUNTER_STYLE => 'arabic_plain',
- self::C_BOOL_COMBINE_IDENTICAL_FOOTNOTES => 'yes',
-
- self::C_BOOL_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_BOOL_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_BOOL_REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER => 'yes',
- self::C_BOOL_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_BOOL_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_BOOL_REFERENCE_CONTAINER_ROW_BORDERS_ENABLE => 'no',
-
- // backlink symbol:
- self::C_BOOL_REFERENCE_CONTAINER_3COLUMN_LAYOUT_ENABLE => 'no',
- self::C_BOOL_REFERENCE_CONTAINER_BACKLINK_SYMBOL_ENABLE => 'yes',
- self::C_BOOL_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_BOOL_BACKLINKS_SEPARATOR_ENABLED => 'yes',
- self::C_STR_BACKLINKS_SEPARATOR_OPTION => 'comma',
- self::C_STR_BACKLINKS_SEPARATOR_CUSTOM => '',
- self::C_BOOL_BACKLINKS_TERMINATOR_ENABLED => 'no',
- self::C_STR_BACKLINKS_TERMINATOR_OPTION => 'full_stop',
- self::C_STR_BACKLINKS_TERMINATOR_CUSTOM => '',
-
- // set backlinks column width:
- self::C_BOOL_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_BOOL_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_BOOL_BACKLINKS_LINE_BREAKS_ENABLED => 'no',
-
- // whether to enable URL line wrapping:
- self::C_BOOL_FOOTNOTE_URL_WRAP_ENABLED => 'yes',
-
- // whether to use link elements:
- self::C_BOOL_LINK_ELEMENT_ENABLED => 'yes',
-
- // excerpt should be disabled:
- self::C_BOOL_FOOTNOTES_IN_EXCERPT => 'no',
-
- self::C_BOOL_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_BOOL_FOOTNOTES_REFERRER_SUPERSCRIPT_TAGS => 'yes',
-
- self::C_STR_FOOTNOTES_STYLING_BEFORE => '[',
- self::C_STR_FOOTNOTES_STYLING_AFTER => ']',
-
- self::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED => 'yes',
-
- self::C_BOOL_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_BOOL_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_BOOL_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_BOOL_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_BOOL_EXPERT_LOOKUP_THE_TITLE => '',
-
- self::C_BOOL_EXPERT_LOOKUP_THE_CONTENT => 'checked',
-
- // And the_excerpt is disabled by default following @nikelaos in
- //
- //
- self::C_BOOL_EXPERT_LOOKUP_THE_EXCERPT => '',
-
- self::C_BOOL_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_BOOL_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_BOOL_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.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @var array
- */
- private $a_arr_Settings = array();
-
- /**
- * Class Constructor. Loads all Settings from each WordPress Settings container.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- */
- private function __construct() {
- $this->loadAll();
- }
-
- /**
- * Returns a singleton of this class.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @return MCI_Footnotes_Settings
- */
- public static function instance() {
- // no instance defined yet, load it
- if (self::$a_obj_Instance === null) {
- 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.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param int $p_int_Index Settings Container Array Key Index.
- * @return str Settings Container name.
- */
- public function getContainer($p_int_Index) {
- return $this->a_arr_Container[$p_int_Index];
- }
-
- /**
- * Returns the default values of a specific Settings Container.
- *
- * @author Stefan Herndler
- * @since 1.5.6
- * @param int $p_int_Index Settings Container Aray Key Index.
- * @return array
- */
- public function getDefaults($p_int_Index) {
- return $this->a_arr_Default[$this->a_arr_Container[$p_int_Index]];
- }
-
- /**
- * Loads all Settings from each Settings container.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- */
- private function loadAll() {
- // clear current settings
- $this->a_arr_Settings = array();
- for ($i = 0; $i < count($this->a_arr_Container); $i++) {
- // load settings
- $this->a_arr_Settings = array_merge($this->a_arr_Settings, $this->Load($i));
- }
- }
-
- /**
- * Loads all Settings from specified Settings Container.
- *
- * @author Stefan Herndler
- * @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->getContainer($p_int_Index));
- // load all default settings
- $l_arr_Default = $this->a_arr_Default[$this->getContainer($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.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param int $p_int_Index Index of the Settings container.
- * @param array $p_arr_newValues new Settings.
- * @return bool
- */
- public function saveOptions($p_int_Index, $p_arr_newValues) {
- if (update_option($this->getContainer($p_int_Index), $p_arr_newValues)) {
- $this->loadAll();
- return true;
- }
- return false;
- }
-
- /**
- * Returns the value of specified Settings name.
- *
- * @author Stefan Herndler
- * @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.
- *
- * @author Stefan Herndler
- * @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 ClearAll() {
- // iterate through each Settings Container
- for ($i = 0; $i < count($this->a_arr_Container); $i++) {
- // delete the settings container
- delete_option($this->getContainer($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.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- */
- public function RegisterSettings() {
- // register all settings
- for ($i = 0; $i < count($this->a_arr_Container); $i++) {
- register_setting($this->getContainer($i), $this->getContainer($i));
- }
- }
-}
+ 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 ) );
+ }
+ }
+}
diff --git a/class/task.php b/class/task.php
index 2f40d9a..e39a7e4 100644
--- a/class/task.php
+++ b/class/task.php
@@ -1,2354 +1,2459 @@
-get(MCI_Footnotes_Settings::C_INT_EXPERT_LOOKUP_THE_TITLE_PRIORITY_LEVEL));
- $l_int_TheContentPriority = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_EXPERT_LOOKUP_THE_CONTENT_PRIORITY_LEVEL));
- $l_int_TheExcerptPriority = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_EXPERT_LOOKUP_THE_EXCERPT_PRIORITY_LEVEL));
- $l_int_WidgetTitlePriority = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_EXPERT_LOOKUP_WIDGET_TITLE_PRIORITY_LEVEL));
- $l_int_WidgetTextPriority = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_EXPERT_LOOKUP_WIDGET_TEXT_PRIORITY_LEVEL));
-
- // PHP_INT_MAX can be set by -1:
- $l_int_TheTitlePriority = ($l_int_TheTitlePriority == -1) ? PHP_INT_MAX : $l_int_TheTitlePriority ;
- $l_int_TheContentPriority = ($l_int_TheContentPriority == -1) ? PHP_INT_MAX : $l_int_TheContentPriority ;
- $l_int_TheExcerptPriority = ($l_int_TheExcerptPriority == -1) ? PHP_INT_MAX : $l_int_TheExcerptPriority ;
- $l_int_WidgetTitlePriority = ($l_int_WidgetTitlePriority == -1) ? PHP_INT_MAX : $l_int_WidgetTitlePriority;
- $l_int_WidgetTextPriority = ($l_int_WidgetTextPriority == -1) ? PHP_INT_MAX : $l_int_WidgetTextPriority ;
-
-
- // append custom css to the header
- add_filter('wp_head', array($this, "wp_head"), PHP_INT_MAX);
-
- // append the love and share me slug to the footer
- add_filter('wp_footer', array($this, "wp_footer"), PHP_INT_MAX);
-
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_TITLE))) {
- add_filter('the_title', array($this, "the_title"), $l_int_TheTitlePriority);
- }
-
- // configurable priority level for reference container relative positioning; default 98:
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_CONTENT))) {
- add_filter('the_content', array($this, "the_content"), $l_int_TheContentPriority);
-
- /**
- * Hook for category pages
- *
- * - Bugfix: Hooks: support footnotes on category pages, thanks to @vitaefit bug report, thanks to @misfist code contribution.
- *
- * @since 2.5.0
- * @date 2021-01-05T1402+0100
- *
- * @contributor @misfist
- * @link https://wordpress.org/support/topic/footnote-doesntwork-on-category-page/#post-13864859
- *
- * @reporter @vitaefit
- * @link https://wordpress.org/support/topic/footnote-doesntwork-on-category-page/
- *
- * Category pages can have rich HTML content in a term description with article status.
- * For this to happen, WordPress’ built-in partial HTML blocker needs to be disabled.
- * @link https://docs.woocommerce.com/document/allow-html-in-term-category-tag-descriptions/
- */
- add_filter('term_description', array($this, "the_content"), $l_int_TheContentPriority);
-
- /**
- * Hook for popup maker popups
- *
- * - Bugfix: Hooks: support footnotes in Popup Maker popups, thanks to @squatcher bug report.
- *
- * @since 2.5.1
- * @date 2021-01-18T2038+0100
- *
- * @reporter @squatcher
- * @link https://wordpress.org/support/topic/footnotes-use-in-popup-maker/
- */
- add_filter('pum_popup_content', array($this, "the_content"), $l_int_TheContentPriority);
- }
-
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_EXCERPT))) {
- add_filter('the_excerpt', array($this, "the_excerpt"), $l_int_TheExcerptPriority);
- }
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_WIDGET_TITLE))) {
- add_filter('widget_title', array($this, "widget_title"), $l_int_WidgetTitlePriority);
- }
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_WIDGET_TEXT))) {
- add_filter('widget_text', array($this, "widget_text"), $l_int_WidgetTextPriority);
- }
-
-
- /**
- * The the_post hook
- *
- * - Adding: Hooks: support 'the_post' in response to user request for custom post types.
- *
- * @since 1.5.4
- * @accountable @aricura
- * @link https://wordpress.org/support/topic/doesnt-work-in-custon-post-types/#post-5339110
- *
- *
- * - Update: Hooks: Default-enable all hooks to prevent footnotes from seeming broken in some parts.
- *
- * @since 2.0.5
- * @accountable @pewgeuges
- *
- *
- * - BUGFIX: Hooks: Default-disable 'the_post', thanks to @spaceling @markcheret @nyamachi @whichgodsaves @spiralofhope2 @mmallett @andreasra @widecast @ymorin007 @tashi1es bug reports.
- *
- * @since 2.0.7
- * @accountable @pewgeuges
- * @link https://wordpress.org/support/topic/change-the-position-5/page/2/#post-13630114
- * @link https://wordpress.org/support/topic/footnotes-appearing-in-header/#post-13630303
- * @link https://wordpress.org/support/topic/footnotes-appearing-in-header/page/2/#post-13630799
- * @link https://wordpress.org/support/topic/no-footnotes-anymore/#post-13813233
- *
- * @reporter @spaceling
- * @link https://wordpress.org/support/topic/change-the-position-5/#post-13612697
- *
- * @reporter @markcheret on behalf of W. Beinert
- * @link https://wordpress.org/support/topic/footnotes-now-appear-in-summaries-even-though-this-is-marked-no/
- *
- * @reporter @nyamachi
- * @link https://wordpress.org/support/topic/footnotes-appearing-in-header/
- *
- * @reporter @whichgodsaves
- * @link https://wordpress.org/support/topic/footnotes-appearing-in-header/#post-13622694
- *
- * @reporter @spiralofhope2
- * @link https://wordpress.org/support/topic/2-0-5-broken/
- *
- * @reporter @mmallett
- * @link https://wordpress.org/support/topic/2-0-5-broken/#post-13623208
- *
- * @reporter @andreasra
- * @link https://wordpress.org/support/topic/footnotes-appearing-in-header/#post-13624091
- *
- * @reporter @widecast
- * @link https://wordpress.org/support/topic/2-0-5-broken/#post-13626222
- *
- * @reporter @ymorin007
- * @link https://wordpress.org/support/topic/footnotes-appearing-in-header/#post-13627050
- *
- * @reporter @markcheret on behalf of L. Smith
- * @link https://wordpress.org/support/topic/footnotes-appear-in-random-places-on-academic-website/
- *
- * @reporter @tashi1es
- * @link https://wordpress.org/support/topic/footnotes-appear-in-random-places-on-academic-website/#post-13630495
- *
- *
- * - UPDATE: Hooks: remove 'the_post', the plugin stops supporting this hook.
- *
- * @since 2.1.0
- * @date 2020-11-08T1839+0100
- * @accountable @pewgeuges
- */
-
- // reset stored footnotes when displaying the header
- self::$a_arr_Footnotes = array();
- self::$a_bool_AllowLoveMe = true;
- }
-
- /**
- * Outputs the custom css to the header of the public page.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- *
- *
- * @since 2.1.1 Bugfix: Reference container: fix start pages by making its display optional, thanks to @dragon013 bug report.
- * @since 2.1.1 Bugfix: Tooltips: optional alternative JS implementation with CSS transitions to fix configuration-related outage, thanks to @andreasra feedback.
- * @since 2.1.3 raise settings priority to override theme stylesheets
- * @since 2.1.4 Bugfix: Tooltips: Styling: fix font size issue by adding font size to settings with legacy as default.
- * @since 2.1.4 Bugfix: Reference container: fix layout issues by moving backlink column width to settings.
- * @since 2.2.5 Bugfix: Reference container: Label: make bottom border an option, thanks to @markhillyer issue report.
- * @since 2.2.5 Bugfix: Reference container: Label: option to select paragraph or heading element, thanks to @markhillyer issue report.
- * @since 2.3.0 Bugfix: Reference container: convert top padding to margin and make it a setting, thanks to @hamshe bug report.
- * @since 2.5.4 Bugfix: Referrers: optional fixes to vertical alignment, font size and position (static) for in-theme consistency and cross-theme stability, thanks to @tomturowski bug report.
- */
- public function wp_head() {
-
- // insert start tag without switching out of PHP:
- echo "\r\n\r\n";
-
- /**
- * Alternative tooltip implementation relying on plain JS and CSS transitions.
- *
- * - Bugfix: Tooltips: optional alternative JS implementation with CSS transitions to fix configuration-related outage, thanks to @andreasra feedback.
- *
- * @since 2.1.1
- *
- * @reporter @andreasra
- * @link https://wordpress.org/support/topic/footnotes-appearing-in-header/page/2/#post-13632566
- *
- * The script for alternative tooltips is printed formatted, not minified:
- */
- if ( self::$a_bool_AlternativeTooltipsEnabled ) {
- ?>
-
-get(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION) == "footer") {
- echo $this->ReferenceContainer();
- }
- // get setting for love and share this plugin
- $l_str_LoveMeIndex = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_LOVE);
- // check if the admin allows to add a link to the footer
- if (empty($l_str_LoveMeIndex) || strtolower($l_str_LoveMeIndex) == "no" || !self::$a_bool_AllowLoveMe) {
- return;
- }
- // set a hyperlink to the word "footnotes" in the Love slug
- $l_str_LinkedName = sprintf('%s', MCI_Footnotes_Config::C_STR_PLUGIN_PUBLIC_NAME);
- // get random love me text
- if (strtolower($l_str_LoveMeIndex) == "random") {
- $l_str_LoveMeIndex = "text-" . rand(1,7);
- }
- switch ($l_str_LoveMeIndex) {
- // options named wrt backcompat, simplest is default:
- case "text-1": $l_str_LoveMeText = sprintf(__('I %2$s %1$s', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), $l_str_LinkedName, MCI_Footnotes_Config::C_STR_LOVE_SYMBOL); break;
- case "text-2": $l_str_LoveMeText = sprintf(__('This website uses the awesome %s plugin.', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), $l_str_LinkedName); break;
- case "text-4": $l_str_LoveMeText = sprintf('%s %s', $l_str_LinkedName, MCI_Footnotes_Config::C_STR_LOVE_SYMBOL); break;
- case "text-5": $l_str_LoveMeText = sprintf('%s %s', MCI_Footnotes_Config::C_STR_LOVE_SYMBOL, $l_str_LinkedName); break;
- case "text-6": $l_str_LoveMeText = sprintf(__('This website uses %s.', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), $l_str_LinkedName); break;
- case "text-7": $l_str_LoveMeText = sprintf(__('This website uses the %s plugin.', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), $l_str_LinkedName); break;
- case "text-3": default: $l_str_LoveMeText = sprintf('%s', $l_str_LinkedName); break;
- }
- echo sprintf('%s
', $l_str_LoveMeText);
- }
-
- /**
- * Replaces footnotes in the post/page title.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param string $p_str_Content Widget content.
- * @return string Content with replaced footnotes.
- */
- public function the_title($p_str_Content) {
- // appends the reference container if set to "post_end"
- return $this->exec($p_str_Content, false);
- }
-
- /**
- * Replaces footnotes in the content of the current page/post.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param string $p_str_Content Page/Post content.
- * @return string Content with replaced footnotes.
- */
- public function the_content($p_str_Content) {
-
- /**
- * Empties the footnotes list every time Footnotes is run when the_content hook is called.
- *
- * - Bugfix: Process: fix footnote duplication by emptying the footnotes list every time the search algorithm is run on the content, thanks to @inoruhana bug report.
- *
- * @since 2.5.7
- *
- * @reporter @inoruhana
- * @link https://wordpress.org/support/topic/footnote-duplicated-in-the-widget/
- *
- * Under certain circumstances, footnotes were duplicated, because the footnotes list was
- * not emptied every time before the search algorithm was run. That happened eg when both
- * the reference container resides in the widget area, and the YOAST SEO plugin is active
- * and calls the hook the_content to generate the Open Graph description, while Footnotes
- * is set to avoid missing out on the footnotes (in the content) by hooking in as soon as
- * the_content is called, whereas at post end Footnotes seems to hook in the_content only
- * the time it’s the blog engine processing the post for display and appending the refs.
- */
- self::$a_arr_Footnotes = array();
- // appends the reference container if set to "post_end"
- return $this->exec($p_str_Content, MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION) == "post_end" ? true : false);
- }
-
- /**
- * Replaces footnotes in the excerpt of the current page/post.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param string $p_str_Content Page/Post content.
- * @return string Content with replaced footnotes.
- */
- public function the_excerpt($p_str_Content) {
- return $this->exec($p_str_Content, false, !MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_IN_EXCERPT)));
- }
-
- /**
- * Replaces footnotes in the widget title.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param string $p_str_Content Widget content.
- * @return string Content with replaced footnotes.
- */
- public function widget_title($p_str_Content) {
- // appends the reference container if set to "post_end"
- return $this->exec($p_str_Content, false);
- }
-
- /**
- * Replaces footnotes in the content of the current widget.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param string $p_str_Content Widget content.
- * @return string Content with replaced footnotes.
- */
- public function widget_text($p_str_Content) {
- // appends the reference container if set to "post_end"
- return $this->exec($p_str_Content, MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION) == "post_end" ? true : false);
- }
-
- /**
- * Replaces footnotes in each Content var of the current Post object.
- *
- * @author Stefan Herndler
- * @since 1.5.4
- * @param array|WP_Post $p_mixed_Posts
- */
- public function the_post(&$p_mixed_Posts) {
- // single WP_Post object received
- if (!is_array($p_mixed_Posts)) {
- $p_mixed_Posts = $this->replacePostObject($p_mixed_Posts);
- return;
- }
- // array of WP_Post objects received
- for($l_int_Index = 0; $l_int_Index < count($p_mixed_Posts); $l_int_Index++) {
- $p_mixed_Posts[$l_int_Index] = $this->replacePostObject($p_mixed_Posts[$l_int_Index]);
- }
- }
-
- /**
- * Replace all Footnotes in a WP_Post object.
- *
- * @author Stefan Herndler
- * @since 1.5.6
- * @param WP_Post $p_obj_Post
- * @return WP_Post
- */
- private function replacePostObject($p_obj_Post) {
- //MCI_Footnotes_Convert::debug($p_obj_Post);
- $p_obj_Post->post_content = $this->exec($p_obj_Post->post_content);
- $p_obj_Post->post_content_filtered = $this->exec($p_obj_Post->post_content_filtered);
- $p_obj_Post->post_excerpt = $this->exec($p_obj_Post->post_excerpt);
- return $p_obj_Post;
- }
-
- /**
- * Replaces all footnotes that occur in the given content.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param string $p_str_Content Any string that may contain footnotes to be replaced.
- * @param bool $p_bool_OutputReferences Appends the Reference Container to the output if set to true, default true.
- * @param bool $p_bool_HideFootnotesText Hide footnotes found in the string.
- * @return string
- *
- *
- * @since 2.2.0 Adding: Reference container: support for custom position shortcode, thanks to @hamshe issue report.
- * @since 2.2.5 Bugfix: Reference container: delete position shortcode if unused because position may be widget or footer, thanks to @hamshe bug report.
- */
- public function exec($p_str_Content, $p_bool_OutputReferences = false, $p_bool_HideFootnotesText = false) {
-
- // replace all footnotes in the content, settings are converted to html characters
- $p_str_Content = $this->search($p_str_Content, true, $p_bool_HideFootnotesText);
- // replace all footnotes in the content, settings are NOT converted to html characters
- $p_str_Content = $this->search($p_str_Content, false, $p_bool_HideFootnotesText);
-
- /**
- * Reference container customized positioning through shortcode
- *
- * - Adding: Reference container: support for custom position shortcode, thanks to @hamshe issue report.
- *
- * @since 2.2.0
- * @date 2020-12-13T2057+0100
- *
- * @reporter @hamshe
- * @link https://wordpress.org/support/topic/reference-container-in-elementor/
- *
- *
- * - Bugfix: Reference container: delete position shortcode if unused because position may be widget or footer, thanks to @hamshe bug report.
- *
- * @since 2.2.5
- * @date 2020-12-18T1434+0100
- *
- * @reporter @hamshe
- * @link https://wordpress.org/support/topic/reference-container-in-elementor/#post-13784126
- *
- */
- // append the reference container or insert at shortcode:
- $l_str_ReferenceContainerPositionShortcode = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION_SHORTCODE);
- if ( empty( $l_str_ReferenceContainerPositionShortcode ) ) {
- $l_str_ReferenceContainerPositionShortcode = '[[references]]';
- }
-
- if ( $p_bool_OutputReferences ) {
-
- if ( strpos( $p_str_Content, $l_str_ReferenceContainerPositionShortcode ) !== false ) {
-
- $p_str_Content = str_replace( $l_str_ReferenceContainerPositionShortcode, $this->ReferenceContainer(), $p_str_Content );
-
- } else {
-
- $p_str_Content .= $this->ReferenceContainer();
-
- }
-
- // increment the container ID:
- self::$a_int_ReferenceContainerId++;
- }
-
- // delete position shortcode should any remain:
- $p_str_Content = str_replace( $l_str_ReferenceContainerPositionShortcode, '', $p_str_Content );
-
- // take a look if the LOVE ME slug should NOT be displayed on this page/post, remove the short code if found
- if (strpos($p_str_Content, MCI_Footnotes_Config::C_STR_NO_LOVE_SLUG) !== false) {
- self::$a_bool_AllowLoveMe = false;
- $p_str_Content = str_replace(MCI_Footnotes_Config::C_STR_NO_LOVE_SLUG, "", $p_str_Content);
- }
- // return the content with replaced footnotes and optional reference container appended:
- return $p_str_Content;
- }
-
- /**
- * Replaces all footnotes in the given content and appends them to the static property.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @param string $p_str_Content Content to be searched for footnotes.
- * @param bool $p_bool_ConvertHtmlChars html encode settings, default true.
- * @param bool $p_bool_HideFootnotesText Hide footnotes found in the string.
- * @return string
- *
- * @since 2.0.0 various.
- * @since 2.4.0 Adding: Footnote delimiters: syntax validation for balanced footnote start and end tag short codes.
- * @since 2.5.0 Bugfix: Footnote delimiters: Syntax validation: exclude certain cases involving scripts, thanks to @andreasra bug report.
- * @since 2.5.0 Bugfix: Footnote delimiters: Syntax validation: complete message with hint about setting, thanks to @andreasra bug report.
- * @since 2.5.0 Bugfix: Footnote delimiters: Syntax validation: limit length of quoted string to 300 characters, thanks to @andreasra bug report.
- */
- public function search($p_str_Content, $p_bool_ConvertHtmlChars, $p_bool_HideFootnotesText) {
-
- // post ID to make everything unique wrt infinite scroll and archive view
- self::$a_int_PostId = get_the_id();
-
- // contains the index for the next footnote on this page
- $l_int_FootnoteIndex = count(self::$a_arr_Footnotes) + 1;
-
- // contains the starting position for the lookup of a footnote
- $l_int_PosStart = 0;
-
- // get start and end tag for the footnotes short code
- $l_str_StartingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START);
- $l_str_EndingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END);
- if ($l_str_StartingTag == "userdefined" || $l_str_EndingTag == "userdefined") {
- $l_str_StartingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED);
- $l_str_EndingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED);
- }
- // decode html special chars
- if ($p_bool_ConvertHtmlChars) {
- $l_str_StartingTag = htmlspecialchars($l_str_StartingTag);
- $l_str_EndingTag = htmlspecialchars($l_str_EndingTag);
- }
-
- // if footnotes short code is empty, return the content without changes
- if (empty($l_str_StartingTag) || empty($l_str_EndingTag)) {
- return $p_str_Content;
- }
-
- /**
- * Footnote delimiter syntax validation
- *
- * - Adding: Footnote delimiters: syntax validation for balanced footnote start and end tag short codes.
- *
- * @since 2.4.0
- *
- *
- * - Bugfix: Footnote delimiters: Syntax validation: exclude certain cases involving scripts, thanks to @andreasra bug report.
- * - Bugfix: Footnote delimiters: Syntax validation: complete message with hint about setting, thanks to @andreasra bug report.
- * - Bugfix: Footnote delimiters: Syntax validation: limit length of quoted string to 300 characters, thanks to @andreasra bug report.
- *
- * @since 2.5.0
- * @date 2021-01-07T0824+0100
- *
- * @reporter @andreasra
- * @link https://wordpress.org/support/topic/warning-unbalanced-footnote-start-tag-short-code-before/
- *
- *
- * If footnotes short codes are unbalanced, and syntax validation is not disabled,
- * prepend a warning to the content; displays de facto beneath the post title.
- */
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTE_SHORTCODE_SYNTAX_VALIDATION_ENABLE))) {
-
- // make shortcodes conform to regex syntax:
- $l_str_StartTagRegex = preg_replace( '#([\(\)\{\}\[\]\*\.\?\!])#', '\\\\$1', $l_str_StartingTag );
- $l_str_EndTagRegex = preg_replace( '#([\(\)\{\}\[\]\*\.\?\!])#', '\\\\$1', $l_str_EndingTag );
-
- // apply different regex depending on whether start shortcode is double/triple opening parenthesis:
- if ( $l_str_StartingTag == '((' || $l_str_StartingTag == '(((' ) {
-
- // this prevents from catching a script containing e.g. a double opening parenthesis:
- $l_str_ValidationRegex = '#' . $l_str_StartTagRegex . '(((?!' . $l_str_EndTagRegex . ')[^\{\}])*?)(' . $l_str_StartTagRegex . '|$)#s';
-
- } else {
-
- // catch all only if the start shortcode is not double/triple opening parenthesis, i.e. is unlikely to occur in scripts:
- $l_str_ValidationRegex = '#' . $l_str_StartTagRegex . '(((?!' . $l_str_EndTagRegex . ').)*?)(' . $l_str_StartTagRegex . '|$)#s';
- }
-
- // check syntax and get error locations:
- preg_match( $l_str_ValidationRegex, $p_str_Content, $p_arr_ErrorLocation );
- if ( empty( $p_arr_ErrorLocation ) ) {
- self::$a_bool_SyntaxErrorFlag = false;
- }
-
- // prevent generating and inserting the warning multiple times:
- if ( self::$a_bool_SyntaxErrorFlag ) {
-
- // get plain text string for error location:
- $l_str_ErrorSpotString = strip_tags( $p_arr_ErrorLocation[1] );
-
- // limit string length to 300 characters:
- if ( strlen( $l_str_ErrorSpotString ) > 300 ) {
- $l_str_ErrorSpotString = substr( $l_str_ErrorSpotString, 0, 299 ) . '…';
- }
-
- // compose warning box:
- $l_str_SyntaxErrorWarning = '';
-
- // prepend the warning box to the content:
- $p_str_Content = $l_str_SyntaxErrorWarning . $p_str_Content;
-
- // checked, set flag to false to prevent duplicate warning:
- self::$a_bool_SyntaxErrorFlag = false;
-
- return $p_str_Content;
- }
- }
-
-
- // load referrer templates if footnotes text not hidden:
- if (!$p_bool_HideFootnotesText) {
-
- // load footnote referrer template file:
- if (self::$a_bool_AlternativeTooltipsEnabled) {
- $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "footnote-alternative");
- } else {
- $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "footnote");
- }
-
- /**
- * Call Boolean again for robustness when priority levels don’t match any longer.
- *
- * - Bugfix: Tooltips: fix display in Popup Maker popups by correcting a coding error.
- *
- * @since 2.5.4
- * @see self::add_filter('pum_popup_content', array($this, "the_content"), $l_int_TheContentPriority)
- */
- self::$a_bool_TooltipsEnabled = MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED));
- self::$a_bool_AlternativeTooltipsEnabled = MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ALTERNATIVE));
-
- // load tooltip inline script if jQuery tooltips are enabled:
- if (self::$a_bool_TooltipsEnabled && ! self::$a_bool_AlternativeTooltipsEnabled) {
- $l_obj_TemplateTooltip = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "tooltip");
- }
-
- } else {
- $l_obj_Template = null;
- $l_obj_TemplateTooltip = null;
- }
-
- // search footnotes short codes in the content
- do {
- // get first occurrence of the footnote start tag short code:
- $i_int_LenContent = strlen($p_str_Content);
- if ($l_int_PosStart > $i_int_LenContent) $l_int_PosStart = $i_int_LenContent;
- $l_int_PosStart = strpos($p_str_Content, $l_str_StartingTag, $l_int_PosStart);
- // no short code found, stop here
- if ($l_int_PosStart === false) {
- break;
- }
- // get first occurrence of the footnote end tag short code:
- $l_int_PosEnd = strpos($p_str_Content, $l_str_EndingTag, $l_int_PosStart);
- // no short code found, stop here
- if ($l_int_PosEnd === false) {
- break;
- }
- // calculate the length of the footnote
- $l_int_Length = $l_int_PosEnd - $l_int_PosStart;
-
- // get footnote text
- $l_str_FootnoteText = substr($p_str_Content, $l_int_PosStart + strlen($l_str_StartingTag), $l_int_Length - strlen($l_str_StartingTag));
-
- // get tooltip text if present:
- self::$a_str_TooltipShortcode = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_TOOLTIP_EXCERPT_DELIMITER);
- self::$a_int_TooltipShortcodeLength = strlen( self::$a_str_TooltipShortcode );
- $l_int_TooltipTextLength = strpos( $l_str_FootnoteText, self::$a_str_TooltipShortcode );
- $l_bool_HasTooltipText = $l_int_TooltipTextLength === false ? false : true;
- if ( $l_bool_HasTooltipText ) {
- $l_str_TooltipText = substr( $l_str_FootnoteText, 0, $l_int_TooltipTextLength );
- } else {
- $l_str_TooltipText = '';
- }
-
- /**
- * URL line wrapping for Unicode non conformant browsers
- *
- * @since 2.1.1 (CSS)
- * @since 2.1.4 (PHP)
- *
- * Despite Unicode recommends to line-wrap URLs at slashes, and Firefox follows
- * the Unicode standard, Chrome does not, making long URLs hang out of tooltips
- * or extend reference containers, so that the end is hidden outside the window
- * and may eventually be viewed after we scroll horizontally or zoom out. It is
- * up to the web page to make URLs breaking anywhere by wrapping them in a span
- * that is assigned appropriate CSS properties and values.
- * @see css/public.css
- *
- * - Bugfix: Tooltips: fix line breaking for hyperlinked URLs in Unicode-non-compliant user agents, thanks to @andreasra bug report.
- *
- * @since 2.1.1
- *
- * @reporter @andreasra
- * @link https://wordpress.org/support/topic/footnotes-appearing-in-header/page/3/#post-13657398
- *
- *
- * - Bugfix: Reference container: fix width in mobile view by URL wrapping for Unicode-non-conformant browsers, thanks to @karolszakiel bug report.
- *
- * @since 2.1.3
- * @date 2020-11-23
- *
- * @reporter @karolszakiel
- * @link https://wordpress.org/support/topic/footnotes-on-mobile-phones/
- *
- *
- * - Bugfix: Reference container, tooltips: fix line wrapping of URLs (hyperlinked or not) based on pattern, not link element.
- *
- * @since 2.1.4
- * @date 2020-11-25T0837+0100
- * @link https://wordpress.org/support/topic/footnotes-on-mobile-phones/#post-13710682
- *
- *
- * - Bugfix: Reference container, tooltips: URL wrap: exclude image source too, thanks to @bjrnet21 bug report.
- *
- * @since 2.1.5
- *
- * @reporter @bjrnet21
- * @link https://wordpress.org/support/topic/2-1-4-breaks-on-my-site-images-dont-show/
- *
- *
- * - Bugfix: Reference container, tooltips: URL wrap: fix regex, thanks to @a223123131 bug report.
- *
- * @since 2.1.6
- * @date 2020-12-09T1921+0100
- *
- * @reporter @a223123131
- * @link https://wordpress.org/support/topic/broken-layout-starting-version-2-1-4/
- *
- * Even ARIA labels may take a URL as value, so use \w=[\'"] as a catch-all 2020-12-10T1005+0100
- *
- * - Bugfix: Dashboard: URL wrap: add option to properly enable/disable URL wrap.
- *
- * @since 2.1.6
- * @date 2020-12-09T1606+0100
- *
- *
- * - Bugfix: Reference container, tooltips: URL wrap: make the quotation mark optional wrt query parameters, thanks to @spiralofhope2 bug report.
- *
- * @since 2.2.6
- * @date 2020-12-23T0409+0100
- *
- * @reporter @spiralofhope2
- * @link https://wordpress.org/support/topic/two-links-now-breaks-footnotes-with-blogtext/
- *
- *
- * - Bugfix: Reference container, tooltips: URL wrap: remove a bug introduced in the regex, thanks to @rjl20 @spaceling @lukashuggenberg @klusik @friedrichnorth @bernardzit bug reports.
- *
- * @since 2.2.7
- * @date 2020-12-23T1046+0100
- *
- * @reporter @rjl20
- * @link https://wordpress.org/support/topic/two-links-now-breaks-footnotes-with-blogtext/#post-13825479
- *
- * @reporter @spaceling
- * @link https://wordpress.org/support/topic/two-links-now-breaks-footnotes-with-blogtext/#post-13825532
- *
- * @reporter @lukashuggenberg
- * @link https://wordpress.org/support/topic/2-2-6-breaks-all-footnotes/
- *
- * @reporter @klusik
- * @link https://wordpress.org/support/topic/2-2-6-breaks-all-footnotes/#post-13825885
- *
- * @reporter @friedrichnorth
- * @link https://wordpress.org/support/topic/footnotes-dont-show-after-update-to-2-2-6/
- *
- * @reporter @bernardzit
- * @link https://wordpress.org/support/topic/footnotes-dont-show-after-update-to-2-2-6/#post-13826029
- *
- *
- * @since 2.2.8 Bugfix: Reference container, tooltips: URL wrap: correctly make the quotation mark optional wrt query parameters, thanks to @spiralofhope2 bug report.
- * @date 2020-12-23T1107+0100
- *
- * Correct is duplicating the negative lookbehind w/o quotes: '(?get( MCI_Footnotes_Settings::C_BOOL_FOOTNOTE_URL_WRAP_ENABLED ) ) ) {
-
- $l_str_FootnoteText = preg_replace(
- '#(?$1',
- $l_str_FootnoteText
- );
- }
-
- // Text to be displayed instead of the footnote
- $l_str_FootnoteReplaceText = "";
-
- // whether hard links are enabled:
- if (self::$a_bool_HardLinksEnable) {
-
- // get the configurable parts:
- self::$a_str_ReferrerLinkSlug = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_REFERRER_FRAGMENT_ID_SLUG);
- self::$a_str_FootnoteLinkSlug = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTE_FRAGMENT_ID_SLUG);
- self::$a_str_LinkIdsSeparator = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_HARD_LINK_IDS_SEPARATOR);
-
- // streamline ID concatenation:
- self::$a_str_PostContainerIdCompound = self::$a_str_LinkIdsSeparator;
- self::$a_str_PostContainerIdCompound .= self::$a_int_PostId;
- self::$a_str_PostContainerIdCompound .= self::$a_str_LinkIdsSeparator;
- self::$a_str_PostContainerIdCompound .= self::$a_int_ReferenceContainerId;
- self::$a_str_PostContainerIdCompound .= self::$a_str_LinkIdsSeparator;
-
- }
-
- // display the footnote referrers and the tooltips:
- if (!$p_bool_HideFootnotesText) {
- $l_int_Index = MCI_Footnotes_Convert::Index($l_int_FootnoteIndex, MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_COUNTER_STYLE));
-
- // display only a truncated footnote text if option enabled:
- $l_bool_EnableExcerpt = MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_ENABLED));
- $l_int_MaxLength = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_LENGTH));
-
- // define excerpt text as footnote text by default:
- $l_str_ExcerptText = $l_str_FootnoteText;
-
- /**
- * Tooltip truncation
- *
- * - Adding: Tooltips: Read-on button: Label: configurable instead of localizable, thanks to @rovanov example provision.
- *
- * @since 2.1.0
- * @date 2020-11-08T2146+0100
- *
- * @reporter @rovanov
- * @link https://wordpress.org/support/topic/offset-x-axis-and-offset-y-axis-does-not-working/
- *
- * If the tooltip truncation option is enabled, it’s done based on character count,
- * and a trailing incomplete word is cropped.
- * This is equivalent to the WordPress default excerpt generation, i.e. without a
- * custom excerpt and without a delimiter. But WordPress does word count, usually 55.
- */
- if (self::$a_bool_TooltipsEnabled && $l_bool_EnableExcerpt) {
- $l_str_DummyText = strip_tags($l_str_FootnoteText);
- if (is_int($l_int_MaxLength) && strlen($l_str_DummyText) > $l_int_MaxLength) {
- $l_str_ExcerptText = substr($l_str_DummyText, 0, $l_int_MaxLength);
- $l_str_ExcerptText = substr($l_str_ExcerptText, 0, strrpos($l_str_ExcerptText, ' '));
- $l_str_ExcerptText .= ' … <';
- $l_str_ExcerptText .= self::$a_bool_HardLinksEnable ? 'a' : 'span';
- $l_str_ExcerptText .= ' class="footnote_tooltip_continue" ';
- $l_str_ExcerptText .= 'onclick="footnote_moveToAnchor_' . self::$a_int_PostId;
- $l_str_ExcerptText .= '_' . self::$a_int_ReferenceContainerId;
- $l_str_ExcerptText .= '(\'footnote_plugin_reference_' . self::$a_int_PostId;
- $l_str_ExcerptText .= '_' . self::$a_int_ReferenceContainerId;
- $l_str_ExcerptText .= "_$l_int_Index');\"";
-
- // if enabled, add the hard link fragment ID:
- if (self::$a_bool_HardLinksEnable) {
-
- $l_str_ExcerptText .= ' href="#';
- $l_str_ExcerptText .= self::$a_str_FootnoteLinkSlug;
- $l_str_ExcerptText .= self::$a_str_PostContainerIdCompound;
- $l_str_ExcerptText .= $l_int_Index;
- $l_str_ExcerptText .= '"';
- }
-
- $l_str_ExcerptText .= '>';
-
- /**
- * Configurable read-on button label
- *
- * - Adding: Tooltips: Read-on button: Label: configurable instead of localizable, thanks to @rovanov example provision.
- *
- * @since 2.1.0
- * @date 2020-11-08T2146+0100
- *
- * @reporter @rovanov
- * @link https://wordpress.org/support/topic/offset-x-axis-and-offset-y-axis-does-not-working/
- */
- $l_str_ExcerptText .= MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_TOOLTIP_READON_LABEL);
-
- $l_str_ExcerptText .= self::$a_bool_HardLinksEnable ? '' : '';
- }
- }
-
- /**
- * Referrers element superscript or baseline
- *
- * Referrers: new setting for vertical align: superscript (default) or baseline (optional), thanks to @cwbayer bug report
- * @since 2.1.1
- *
- * @reporter @cwbayer
- * @link https://wordpress.org/support/topic/footnote-number-in-text-superscript-disrupts-leading/
- *
- * define the HTML element to use for the referrers:
- */
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_REFERRER_SUPERSCRIPT_TAGS))) {
-
- $l_str_SupSpan = 'sup';
-
- } else {
-
- $l_str_SupSpan = 'span';
- }
-
- // whether hard links are enabled:
- if (self::$a_bool_HardLinksEnable) {
-
- self::$a_str_LinkSpan = 'a';
- self::$a_str_LinkCloseTag = '';
- // self::$a_str_LinkOpenTag will be defined as needed
-
- // compose hyperlink address (leading space is in template):
- $l_str_FootnoteLinkArgument = 'href="#';
- $l_str_FootnoteLinkArgument .= self::$a_str_FootnoteLinkSlug;
- $l_str_FootnoteLinkArgument .= self::$a_str_PostContainerIdCompound;
- $l_str_FootnoteLinkArgument .= $l_int_Index;
- $l_str_FootnoteLinkArgument .= '" class="footnote_hard_link"';
-
- /**
- * Compose fragment ID anchor with offset, for use in reference container.
- * Empty span, child of empty span, to avoid tall dotted rectangles in browser.
- */
- $l_str_ReferrerAnchorElement = '';
-
- } else {
-
- /**
- * Initialize hard link variables when hard links are disabled.
- *
- * - Bugfix: Process: initialize hard link address variables to empty string to fix 'undefined variable' bug, thanks to @a223123131 bug report.
- *
- * @since 2.4.0
- * @date 2021-01-04T1622+0100
- *
- * @reporter @a223123131
- * @link https://wordpress.org/support/topic/wp_debug-php-notice/
- *
- * If no hyperlink nor offset anchor is needed, initialize as empty.
- */
- $l_str_FootnoteLinkArgument = '';
- $l_str_ReferrerAnchorElement = '';
-
- // The link element is set independently as it may be needed for styling:
- if ( MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_LINK_ELEMENT_ENABLED)) ) {
-
- self::$a_str_LinkSpan = 'a';
- self::$a_str_LinkOpenTag = '';
- self::$a_str_LinkCloseTag = '';
-
- }
- }
-
- // determine tooltip content:
- if ( self::$a_bool_TooltipsEnabled ) {
- $l_str_TooltipContent = $l_bool_HasTooltipText ? $l_str_TooltipText : $l_str_ExcerptText;
- } else {
- $l_str_TooltipContent = '';
- }
-
- /**
- * Determine shrink width if alternative tooltips are enabled.
- *
- * @since 2.5.6
- */
- $l_str_TooltipStyle = '';
- if ( self::$a_bool_AlternativeTooltipsEnabled && self::$a_bool_TooltipsEnabled ) {
- $l_int_TooltipLength = strlen( strip_tags( $l_str_TooltipContent ) );
- if ( $l_int_TooltipLength < 70 ) {
- $l_str_TooltipStyle = ' style="width: ';
- $l_str_TooltipStyle .= ( $l_int_TooltipLength * .7 );
- $l_str_TooltipStyle .= 'em;"';
- }
- }
-
- // fill in 'templates/public/footnote.html':
- $l_obj_Template->replace(
- array(
- "link-span" => self::$a_str_LinkSpan,
- "post_id" => self::$a_int_PostId,
- "container_id" => self::$a_int_ReferenceContainerId,
- "note_id" => $l_int_Index,
- "hard-link" => $l_str_FootnoteLinkArgument,
- "sup-span" => $l_str_SupSpan,
- "before" => MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_STYLING_BEFORE),
- "index" => $l_int_Index,
- "after" => MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_STYLING_AFTER),
- "anchor-element" => $l_str_ReferrerAnchorElement,
- "style" => $l_str_TooltipStyle,
- "text" => $l_str_TooltipContent,
- )
- );
- $l_str_FootnoteReplaceText = $l_obj_Template->getContent();
-
- // reset the template
- $l_obj_Template->reload();
-
- // if standard tooltips are enabled but alternative are not:
- if (self::$a_bool_TooltipsEnabled && ! self::$a_bool_AlternativeTooltipsEnabled) {
-
- $l_int_OffsetY = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_Y));
- $l_int_OffsetX = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_X));
- $l_int_FadeInDelay = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_MOUSE_OVER_BOX_FADE_IN_DELAY ));
- $l_int_FadeInDuration = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_MOUSE_OVER_BOX_FADE_IN_DURATION ));
- $l_int_FadeOutDelay = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_MOUSE_OVER_BOX_FADE_OUT_DELAY ));
- $l_int_FadeOutDuration = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_MOUSE_OVER_BOX_FADE_OUT_DURATION));
-
- // fill in 'templates/public/tooltip.html':
- $l_obj_TemplateTooltip->replace(
- array(
- "post_id" => self::$a_int_PostId,
- "container_id" => self::$a_int_ReferenceContainerId,
- "note_id" => $l_int_Index,
- "position" => MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_POSITION),
- "offset-y" => !empty($l_int_OffsetY) ? $l_int_OffsetY : 0,
- "offset-x" => !empty($l_int_OffsetX) ? $l_int_OffsetX : 0,
- "fade-in-delay" => !empty($l_int_FadeInDelay ) ? $l_int_FadeInDelay : 0,
- "fade-in-duration" => !empty($l_int_FadeInDuration ) ? $l_int_FadeInDuration : 0,
- "fade-out-delay" => !empty($l_int_FadeOutDelay ) ? $l_int_FadeOutDelay : 0,
- "fade-out-duration" => !empty($l_int_FadeOutDuration) ? $l_int_FadeOutDuration : 0,
- )
- );
- $l_str_FootnoteReplaceText .= $l_obj_TemplateTooltip->getContent();
- $l_obj_TemplateTooltip->reload();
- }
- }
- // replace the footnote with the template
- $p_str_Content = substr_replace($p_str_Content, $l_str_FootnoteReplaceText, $l_int_PosStart, $l_int_Length + strlen($l_str_EndingTag));
-
- // add footnote only if not empty
- if (!empty($l_str_FootnoteText)) {
- // set footnote to the output box at the end
- self::$a_arr_Footnotes[] = $l_str_FootnoteText;
- // increase footnote index
- $l_int_FootnoteIndex++;
- }
-
- /**
- * Fixes a footnotes numbering bug (happening under de facto rare circumstances).
- *
- * - Bugfix: Fixed occasional bug where footnote ordering could be out of sequence
- *
- * @since 1.6.4
- * @date 2016-06-29T0054+0000
- * @committer @dartiss
- * @link https://plugins.trac.wordpress.org/browser/footnotes/trunk/class/task.php?rev=1445718 @dartiss’ class/task.php
- * @link https://plugins.trac.wordpress.org/log/footnotes/trunk/class/task.php?rev=1445718 @dartiss re-added class/task.php
- * @link https://plugins.trac.wordpress.org/browser/footnotes/trunk/class?rev=1445711 class/ w/o task.php
- * @link https://plugins.trac.wordpress.org/changeset/1445711/footnotes/trunk/class @dartiss deleted class/task.php
- * @link https://plugins.trac.wordpress.org/browser/footnotes/trunk/class/task.php?rev=1026210 @aricura’s latest class/task.php
- *
- *
- * - Bugfix: Process: fix numbering bug impacting footnote #2 with footnote #1 close to start, thanks to @rumperuu bug report, thanks to @lolzim code contribution.
- *
- * @since 2.5.5
- *
- * @contributor @lolzim
- * @link https://wordpress.org/support/topic/footnotes-numbered-incorrectly/#post-14062032
- *
- * @reporter @rumperuu
- * @link https://wordpress.org/support/topic/footnotes-numbered-incorrectly/
- *
- * This assignment was overridden by another one, causing the algorithm to jump back
- * near the post start to a position calculated as the sum of the length of the last
- * footnote and the length of the last footnote replace text.
- * A bug disturbing the order of the footnotes depending on the text before the first
- * footnote, the length of the first footnote and the length of the templates for the
- * footnote and the tooltip. Moreover, it was causing non-trivial process garbage.
- */
- // add offset to the new starting position
- $l_int_PosStart += $l_int_Length + strlen($l_str_EndingTag);
-
- } while (true);
-
- // return content
- return $p_str_Content;
- }
-
- /**
- * Generates the reference container.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- * @return string
- *
- * @since 2.0.0 Update: remove backlink symbol along with column 2 of the reference container
- * @since 2.0.3 Bugfix: prepend an arrow on user request
- * @since 2.0.6 Bugfix: Reference container: fix line breaking behavior in footnote number clusters.
- * @since 2.0.4 Bugfix: restore the arrow select and backlink symbol input settings
- * @since 2.1.1 Bugfix: Referrers, reference container: Combining identical footnotes: fix dead links and ensure referrer-backlink bijectivity, thanks to @happyches bug report.
- * @since 2.1.1 Bugfix: Reference container: Backlink symbol: make optional, not suggest configuring it to invisible, thanks to @spaceling feedback.
- */
- public function ReferenceContainer() {
-
- // no footnotes have been replaced on this page:
- if (empty(self::$a_arr_Footnotes)) {
- return "";
- }
-
-
- /**
- * Footnote index backlink symbol
- *
- * - Bugfix: Reference container: Backlink symbol: make optional, not suggest configuring it to invisible, thanks to @spaceling feedback.
- *
- * @since 2.1.1
- *
- * @reporter @spaceling
- * @link https://wordpress.org/support/topic/change-the-position-5/page/2/#post-13671138
- *
- * If the backlink symbol is enabled:
- */
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_REFERENCE_CONTAINER_BACKLINK_SYMBOL_ENABLE))) {
-
- // get html arrow
- $l_str_Arrow = MCI_Footnotes_Convert::getArrow(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_HYPERLINK_ARROW));
- // set html arrow to the first one if invalid index defined
- if (is_array($l_str_Arrow)) {
- $l_str_Arrow = MCI_Footnotes_Convert::getArrow(0);
- }
- // get user defined arrow
- $l_str_ArrowUserDefined = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_HYPERLINK_ARROW_USER_DEFINED);
- if (!empty($l_str_ArrowUserDefined)) {
- $l_str_Arrow = $l_str_ArrowUserDefined;
- }
-
- // wrap the arrow in a @media print { display:hidden } span:
- $l_str_FootnoteArrow = '';
-
- } else {
-
- // If the backlink symbol isn’t enabled, set it to empty:
- $l_str_Arrow = '';
- $l_str_FootnoteArrow = '';
-
- }
-
-
- /**
- * Backlink separator
- *
- * - Bugfix: Reference container: make separating and terminating punctuation optional and configurable, thanks to @docteurfitness issue report and code contribution.
- *
- * @since 2.1.4
- * @date 2020-11-28T1048+0100
- *
- * @contributor @docteurfitness
- * @link https://wordpress.org/support/topic/update-2-1-3/#post-13704194
- *
- * @reporter @docteurfitness
- * @link https://wordpress.org/support/topic/update-2-1-3/
- *
- * Initially a comma was appended in this algorithm for enumerations.
- * The comma in enumerations is not generally preferred.
- */
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_BACKLINKS_SEPARATOR_ENABLED))) {
-
- // check if it is input-configured:
- $l_str_Separator = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_BACKLINKS_SEPARATOR_CUSTOM);
-
- if (empty($l_str_Separator)) {
-
- // if it is not, check which option is on:
- $l_str_SeparatorOption = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_BACKLINKS_SEPARATOR_OPTION);
- switch ($l_str_SeparatorOption) {
- case 'comma' : $l_str_Separator = ','; break;
- case 'semicolon': $l_str_Separator = ';'; break;
- case 'en_dash' : $l_str_Separator = ' –'; break;
- }
- }
-
- } else {
-
- $l_str_Separator = '';
- }
-
- /**
- * Backlink terminator
- *
- * Initially a dot was appended in the table row template.
- * @since 2.0.6 a dot after footnote numbers is discarded as not localizable;
- * making it optional was envisaged.
- * @since 2.1.4 the terminator is optional, has options, and is configurable:
- */
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_BACKLINKS_TERMINATOR_ENABLED))) {
-
- // check if it is input-configured:
- $l_str_Terminator = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_BACKLINKS_TERMINATOR_CUSTOM);
-
- if (empty($l_str_Terminator)) {
-
- // if it is not, check which option is on:
- $l_str_TerminatorOption = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_BACKLINKS_TERMINATOR_OPTION);
- switch ($l_str_TerminatorOption) {
- case 'period' : $l_str_Terminator = '.'; break;
- case 'parenthesis': $l_str_Terminator = ')'; break;
- case 'colon' : $l_str_Terminator = ':'; break;
- }
- }
-
- } else {
-
- $l_str_Terminator = '';
- }
-
-
- /**
- * Line breaks
- *
- * - Bugfix: Reference container: Backlinks: fix stacked enumerations by adding optional line breaks.
- *
- * @since 2.1.4
- * @date 2020-11-28T1049+0100
- *
- * The backlinks of combined footnotes are generally preferred in an enumeration.
- * But when few footnotes are identical, stacking the items in list form is better.
- * Variable number length and proportional character width require explicit line breaks.
- * Otherwise, an ordinary space character offering a line break opportunity is inserted.
- */
- $l_str_LineBreak = MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_BACKLINKS_LINE_BREAKS_ENABLED)) ? '
' : ' ';
-
- /**
- * For maintenance and support, table rows in the reference container should be
- * separated by an empty line. So we add these line breaks for source readability.
- * Before the first table row (breaks between rows are ~200 lines below):
- */
- $l_str_Body = "\r\n\r\n";
-
-
- /**
- * Reference container table row template load
- *
- * - Bugfix: Reference container: option to restore pre-2.0.0 layout with the backlink symbol in an extra column.
- *
- * @since 2.1.1
- * @date 2020-11-16T2024+0100
- */
-
- // when combining identical footnotes is turned on, another template is needed:
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_COMBINE_IDENTICAL_FOOTNOTES))) {
- // the combining template allows for backlink clusters and supports cell clicking for single notes:
- $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "reference-container-body-combi");
-
- } else {
-
- // when 3-column layout is turned on (only available if combining is turned off):
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_REFERENCE_CONTAINER_3COLUMN_LAYOUT_ENABLE))) {
- $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "reference-container-body-3column");
-
- } else {
-
- // when switch symbol and index is turned on, and combining and 3-columns are off:
- if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_REFERENCE_CONTAINER_BACKLINK_SYMBOL_SWITCH))) {
- $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "reference-container-body-switch");
-
- } else {
-
- // default is the standard template:
- $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "reference-container-body");
-
- }
- }
- }
-
- /**
- * Switch backlink symbol and footnote number
- *
- * - Bugfix: Reference container: option to append symbol (prepended by default), thanks to @spaceling code contribution.
- *
- * @since 2.1.1
- * @date 2020-11-16T2024+0100
- *
- * @contributor @spaceling
- * @link https://wordpress.org/support/topic/change-the-position-5/#post-13615994
- *
- *
- * - Bugfix: Reference container: Backlink symbol: support for appending when combining identicals is on.
- *
- * @since 2.1.4
- * @date 2020-11-26T1633+0100
- */
- $l_bool_SymbolSwitch = MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_REFERENCE_CONTAINER_BACKLINK_SYMBOL_SWITCH));
-
- // loop through all footnotes found in the page
- for ($l_int_Index = 0; $l_int_Index < count(self::$a_arr_Footnotes); $l_int_Index++) {
-
- // get footnote text
- $l_str_FootnoteText = self::$a_arr_Footnotes[$l_int_Index];
-
- // if footnote is empty, go to the next one;
- // With combine identicals turned on, identicals will be deleted and are skipped:
- if (empty($l_str_FootnoteText)) {
- continue;
- }
-
- // generate content of footnote index cell
- $l_int_FirstFootnoteIndex = ($l_int_Index + 1);
-
- // get the footnote index string and
- // keep supporting legacy index placeholder:
- $l_str_FootnoteId = MCI_Footnotes_Convert::Index(($l_int_Index + 1), MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_COUNTER_STYLE));
-
- /**
- * Case of only one backlink per table row
- *
- * If enabled, and for the case the footnote is single, compose hard link:
- */
- // define anyway:
- $l_str_HardLinkAddress = '';
-
- if (self::$a_bool_HardLinksEnable) {
-
- /**
- * Use-Backbutton-Hint tooltip, optional and configurable.
- *
- * - Update: Reference container: Hard backlinks (optional): optional configurable tooltip hinting to use the backbutton instead, thanks to @theroninjedi47 bug report.
- *
- * @since 2.5.4
- *
- * @reporter @theroninjedi47
- * @link https://wordpress.org/support/topic/hyperlinked-footnotes-creating-excessive-back-history/
- *
- * When hard links are enabled, clicks on the backlinks are logged in the browsing history.
- * This tooltip hints to use the backbutton instead, so the history gets streamlined again.
- * @link https://wordpress.org/support/topic/making-it-amp-compatible/#post-13837359
- */
- if ( MCI_Footnotes_Convert::toBool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_BACKLINK_TOOLTIP_ENABLE ) ) ) {
- $l_str_UseBackbuttonHint = ' title="';
- $l_str_UseBackbuttonHint .= MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_BACKLINK_TOOLTIP_TEXT);
- $l_str_UseBackbuttonHint .= '"';
- } else {
- $l_str_UseBackbuttonHint = '';
- }
-
- /**
- * Compose fragment ID anchor with offset, for use in reference container.
- * Empty span, child of empty span, to avoid tall dotted rectangles in browser.
- */
- $l_str_FootnoteAnchorElement = '';
-
- // compose optional hard link address:
- $l_str_HardLinkAddress = ' href="#';
- $l_str_HardLinkAddress .= self::$a_str_ReferrerLinkSlug;
- $l_str_HardLinkAddress .= self::$a_str_PostContainerIdCompound;
- $l_str_HardLinkAddress .= $l_str_FootnoteId . '"';
- $l_str_HardLinkAddress .= $l_str_UseBackbuttonHint;
-
- // compose optional opening link tag with optional hard link, mandatory for instance:
- self::$a_str_LinkOpenTag = '%s', MCI_Footnotes_Config::C_STR_PLUGIN_PUBLIC_NAME );
+ // Get random love me text.
+ if ( 'random' === strtolower( $l_str_love_me_index ) ) {
+ $l_str_love_me_index = 'text-' . wp_rand( 1, 7 );
+ }
+ switch ( $l_str_love_me_index ) {
+ // Options named wrt backcompat, simplest is default.
+ case 'text-1':
+ /* Translators: 2: Link to plugin page 1: Love heart symbol */
+ $l_str_love_me_text = sprintf( __( 'I %2$s %1$s', 'footnotes' ), $l_str_linked_name, MCI_Footnotes_Config::C_STR_LOVE_SYMBOL );
+ break;
+ case 'text-2':
+ /* Translators: %s: Link to plugin page */
+ $l_str_love_me_text = sprintf( __( 'This website uses the awesome %s plugin.', 'footnotes' ), $l_str_linked_name );
+ break;
+ case 'text-4':
+ /* Translators: 1: Link to plugin page 2: Love heart symbol */
+ $l_str_love_me_text = sprintf( '%1$s %2$s', $l_str_linked_name, MCI_Footnotes_Config::C_STR_LOVE_SYMBOL );
+ break;
+ case 'text-5':
+ /* Translators: 1: Love heart symbol 2: Link to plugin page */
+ $l_str_love_me_text = sprintf( '%1$s %2$s', MCI_Footnotes_Config::C_STR_LOVE_SYMBOL, $l_str_linked_name );
+ break;
+ case 'text-6':
+ /* Translators: %s: Link to plugin page */
+ $l_str_love_me_text = sprintf( __( 'This website uses %s.', 'footnotes' ), $l_str_linked_name );
+ break;
+ case 'text-7':
+ /* Translators: %s: Link to plugin page */
+ $l_str_love_me_text = sprintf( __( 'This website uses the %s plugin.', 'footnotes' ), $l_str_linked_name );
+ break;
+ case 'text-3':
+ default:
+ /* Translators: %s: Link to plugin page */
+ $l_str_love_me_text = sprintf( '%s', $l_str_linked_name );
+ break;
+ }
+ echo sprintf( '%s
', $l_str_love_me_text );
+ }
+
+ /**
+ * Replaces footnotes in the post/page title.
+ *
+ * @since 1.5.0
+ * @param string $p_str_content Widget content.
+ * @return string Content with replaced footnotes.
+ */
+ public function the_title( $p_str_content ) {
+ // Appends the reference container if set to "post_end".
+ return $this->exec( $p_str_content, false );
+ }
+
+ /**
+ * Replaces footnotes in the content of the current page/post.
+ *
+ * @since 1.5.0
+ * @param string $p_str_content Page/Post content.
+ * @return string Content with replaced footnotes.
+ */
+ public function the_content( $p_str_content ) {
+ /**
+ * Empties the footnotes list every time Footnotes is run when the_content hook is called.
+ *
+ * - Bugfix: Process: fix footnote duplication by emptying the footnotes list every time the search algorithm is run on the content, thanks to @inoruhana bug report.
+ *
+ * @since 2.5.7
+ *
+ * @reporter @inoruhana
+ * @link https://wordpress.org/support/topic/footnote-duplicated-in-the-widget/
+ *
+ * Under certain circumstances, footnotes were duplicated, because the footnotes list was
+ * not emptied every time before the search algorithm was run. That happened eg when both
+ * the reference container resides in the widget area, and the YOAST SEO plugin is active
+ * and calls the hook the_content to generate the Open Graph description, while Footnotes
+ * is set to avoid missing out on the footnotes (in the content) by hooking in as soon as
+ * the_content is called, whereas at post end Footnotes seems to hook in the_content only
+ * the time it’s the blog engine processing the post for display and appending the refs.
+ */
+ self::$a_arr_footnotes = array();
+
+ // phpcs:disable WordPress.PHP.YodaConditions.NotYoda
+ // Appends the reference container if set to "post_end".
+ return $this->exec( $p_str_content, 'post_end' === MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION ) );
+ // phpcs:enable WordPress.PHP.YodaConditions.NotYoda
+ }
+
+ /**
+ * Replaces footnotes in the excerpt of the current page/post.
+ *
+ * @since 1.5.0
+ * @param string $p_str_content Page/Post content.
+ * @return string Content with replaced footnotes.
+ */
+ public function the_excerpt( $p_str_content ) {
+ return $this->exec( $p_str_content, false, ! MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_IN_EXCERPT ) ) );
+ }
+
+ /**
+ * Replaces footnotes in the widget title.
+ *
+ * @since 1.5.0
+ * @param string $p_str_content Widget content.
+ * @return string Content with replaced footnotes.
+ */
+ public function widget_title( $p_str_content ) {
+ // Appends the reference container if set to "post_end".
+ return $this->exec( $p_str_content, false );
+ }
+
+ /**
+ * Replaces footnotes in the content of the current widget.
+ *
+ * @since 1.5.0
+ * @param string $p_str_content Widget content.
+ * @return string Content with replaced footnotes.
+ */
+ public function widget_text( $p_str_content ) {
+ // phpcs:disable WordPress.PHP.YodaConditions.NotYoda
+ // Appends the reference container if set to "post_end".
+ return $this->exec( $p_str_content, 'post_end' === MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION ) ? true : false );
+ // phpcs:enable WordPress.PHP.YodaConditions.NotYoda
+ }
+
+ /**
+ * Replaces footnotes in each Content var of the current Post object.
+ *
+ * @since 1.5.4
+ * @param array|WP_Post $p_mixed_posts The current Post object.
+ */
+ public function the_post( &$p_mixed_posts ) {
+ // Single WP_Post object received.
+ if ( ! is_array( $p_mixed_posts ) ) {
+ $p_mixed_posts = $this->replace_post_object( $p_mixed_posts );
+ return;
+ }
+ $num_posts = count( $p_mixed_posts );
+ // Array of WP_Post objects received.
+ for ( $l_int_index = 0; $l_int_index < $num_posts; $l_int_index++ ) {
+ $p_mixed_posts[ $l_int_index ] = $this->replace_post_object( $p_mixed_posts[ $l_int_index ] );
+ }
+ }
+
+ /**
+ * Replace all Footnotes in a WP_Post object.
+ *
+ * @since 1.5.6
+ * @param WP_Post $p_obj_post The Post object.
+ * @return WP_Post
+ */
+ private function replace_post_object( $p_obj_post ) {
+ $p_obj_post->post_content = $this->exec( $p_obj_post->post_content );
+ $p_obj_post->post_content_filtered = $this->exec( $p_obj_post->post_content_filtered );
+ $p_obj_post->post_excerpt = $this->exec( $p_obj_post->post_excerpt );
+ return $p_obj_post;
+ }
+
+ /**
+ * Replaces all footnotes that occur in the given content.
+ *
+ * @since 1.5.0
+ * @param string $p_str_content Any string that may contain footnotes to be replaced.
+ * @param bool $p_bool_output_references Appends the Reference Container to the output if set to true, default true.
+ * @param bool $p_bool_hide_footnotes_text Hide footnotes found in the string.
+ * @return string
+ *
+ * @since 2.2.0 Adding: Reference container: support for custom position shortcode, thanks to @hamshe issue report.
+ * @since 2.2.5 Bugfix: Reference container: delete position shortcode if unused because position may be widget or footer, thanks to @hamshe bug report.
+ */
+ public function exec( $p_str_content, $p_bool_output_references = false, $p_bool_hide_footnotes_text = false ) {
+
+ // Replace all footnotes in the content, settings are converted to html characters.
+ $p_str_content = $this->search( $p_str_content, true, $p_bool_hide_footnotes_text );
+ // Replace all footnotes in the content, settings are NOT converted to html characters.
+ $p_str_content = $this->search( $p_str_content, false, $p_bool_hide_footnotes_text );
+
+ /**
+ * Reference container customized positioning through shortcode.
+ *
+ * - Adding: Reference container: support for custom position shortcode, thanks to @hamshe issue report.
+ *
+ * @since 2.2.0
+ * @date 2020-12-13T2057+0100
+ *
+ * @reporter @hamshe
+ * @link https://wordpress.org/support/topic/reference-container-in-elementor/
+ *
+ *
+ * - Bugfix: Reference container: delete position shortcode if unused because position may be widget or footer, thanks to @hamshe bug report.
+ *
+ * @since 2.2.5
+ * @date 2020-12-18T1434+0100
+ *
+ * @reporter @hamshe
+ * @link https://wordpress.org/support/topic/reference-container-in-elementor/#post-13784126
+ */
+ // Append the reference container or insert at shortcode.
+ $l_str_reference_container_position_shortcode = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION_SHORTCODE );
+ if ( empty( $l_str_reference_container_position_shortcode ) ) {
+ $l_str_reference_container_position_shortcode = '[[references]]';
+ }
+
+ if ( $p_bool_output_references ) {
+
+ if ( strpos( $p_str_content, $l_str_reference_container_position_shortcode ) ) {
+
+ $p_str_content = str_replace( $l_str_reference_container_position_shortcode, $this->reference_container(), $p_str_content );
+
+ } else {
+
+ $p_str_content .= $this->reference_container();
+
+ }
+
+ // Increment the container ID.
+ self::$a_int_reference_container_id++;
+ }
+
+ // Delete position shortcode should any remain.
+ $p_str_content = str_replace( $l_str_reference_container_position_shortcode, '', $p_str_content );
+
+ // Take a look if the LOVE ME slug should NOT be displayed on this page/post, remove the short code if found.
+ if ( strpos( $p_str_content, MCI_Footnotes_Config::C_STR_NO_LOVE_SLUG ) ) {
+ self::$a_bool_allow_love_me = false;
+ $p_str_content = str_replace( MCI_Footnotes_Config::C_STR_NO_LOVE_SLUG, '', $p_str_content );
+ }
+ // Return the content with replaced footnotes and optional reference container appended.
+ return $p_str_content;
+ }
+
+ /**
+ * Replaces all footnotes in the given content and appends them to the static property.
+ *
+ * @since 1.5.0
+ * @param string $p_str_content Content to be searched for footnotes.
+ * @param bool $p_bool_convert_html_chars html encode settings, default true.
+ * @param bool $p_bool_hide_footnotes_text Hide footnotes found in the string.
+ * @return string
+ *
+ * @since 2.0.0 various.
+ * @since 2.4.0 Adding: Footnote delimiters: syntax validation for balanced footnote start and end tag short codes.
+ * @since 2.5.0 Bugfix: Footnote delimiters: Syntax validation: exclude certain cases involving scripts, thanks to @andreasra bug report.
+ * @since 2.5.0 Bugfix: Footnote delimiters: Syntax validation: complete message with hint about setting, thanks to @andreasra bug report.
+ * @since 2.5.0 Bugfix: Footnote delimiters: Syntax validation: limit length of quoted string to 300 characters, thanks to @andreasra bug report.
+ */
+ public function search( $p_str_content, $p_bool_convert_html_chars, $p_bool_hide_footnotes_text ) {
+
+ // Post ID to make everything unique wrt infinite scroll and archive view.
+ self::$a_int_post_id = get_the_id();
+
+ // Contains the index for the next footnote on this page.
+ $l_int_footnote_index = count( self::$a_arr_footnotes ) + 1;
+
+ // Contains the starting position for the lookup of a footnote.
+ $l_int_pos_start = 0;
+
+ // Get start and end tag for the footnotes short code.
+ $l_str_starting_tag = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START );
+ $l_str_ending_tag = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END );
+ if ( 'userdefined' === $l_str_starting_tag || 'userdefined' === $l_str_ending_tag ) {
+ $l_str_starting_tag = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED );
+ $l_str_ending_tag = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED );
+ }
+ // Decode html special chars.
+ if ( $p_bool_convert_html_chars ) {
+ $l_str_starting_tag = htmlspecialchars( $l_str_starting_tag );
+ $l_str_ending_tag = htmlspecialchars( $l_str_ending_tag );
+ }
+
+ // If footnotes short code is empty, return the content without changes.
+ if ( empty( $l_str_starting_tag ) || empty( $l_str_ending_tag ) ) {
+ return $p_str_content;
+ }
+
+ /**
+ * Footnote delimiter syntax validation.
+ *
+ * - Adding: Footnote delimiters: syntax validation for balanced footnote start and end tag short codes.
+ *
+ * @since 2.4.0
+ *
+ *
+ * - Bugfix: Footnote delimiters: Syntax validation: exclude certain cases involving scripts, thanks to @andreasra bug report.
+ * - Bugfix: Footnote delimiters: Syntax validation: complete message with hint about setting, thanks to @andreasra bug report.
+ * - Bugfix: Footnote delimiters: Syntax validation: limit length of quoted string to 300 characters, thanks to @andreasra bug report.
+ *
+ * @since 2.5.0
+ * @date 2021-01-07T0824+0100
+ *
+ * @reporter @andreasra
+ * @link https://wordpress.org/support/topic/warning-unbalanced-footnote-start-tag-short-code-before/
+ *
+ *
+ * If footnotes short codes are unbalanced, and syntax validation is not disabled,
+ * prepend a warning to the content; displays de facto beneath the post title.
+ */
+ if ( MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTE_SHORTCODE_SYNTAX_VALIDATION_ENABLE ) ) ) {
+
+ // Make shortcodes conform to regex syntax.
+ $l_str_start_tag_regex = preg_replace( '#([\(\)\{\}\[\]\*\.\?\!])#', '\\\\$1', $l_str_starting_tag );
+ $l_str_end_tag_regex = preg_replace( '#([\(\)\{\}\[\]\*\.\?\!])#', '\\\\$1', $l_str_ending_tag );
+
+ // Apply different regex depending on whether start shortcode is double/triple opening parenthesis.
+ if ( '((' === $l_str_starting_tag || '(((' === $l_str_starting_tag ) {
+
+ // This prevents from catching a script containing e.g. a double opening parenthesis.
+ $l_str_validation_regex = '#' . $l_str_start_tag_regex . '(((?!' . $l_str_end_tag_regex . ')[^\{\}])*?)(' . $l_str_start_tag_regex . '|$)#s';
+
+ } else {
+
+ // Catch all only if the start shortcode is not double/triple opening parenthesis, i.e. is unlikely to occur in scripts.
+ $l_str_validation_regex = '#' . $l_str_start_tag_regex . '(((?!' . $l_str_end_tag_regex . ').)*?)(' . $l_str_start_tag_regex . '|$)#s';
+ }
+
+ // Check syntax and get error locations.
+ preg_match( $l_str_validation_regex, $p_str_content, $p_arr_error_location );
+ if ( empty( $p_arr_error_location ) ) {
+ self::$a_bool_syntax_error_flag = false;
+ }
+
+ // Prevent generating and inserting the warning multiple times.
+ if ( self::$a_bool_syntax_error_flag ) {
+
+ // Get plain text string for error location.
+ $l_str_error_spot_string = wp_strip_all_tags( $p_arr_error_location[1] );
+
+ // Limit string length to 300 characters.
+ if ( strlen( $l_str_error_spot_string ) > 300 ) {
+ $l_str_error_spot_string = substr( $l_str_error_spot_string, 0, 299 ) . '…';
+ }
+
+ // Compose warning box.
+ $l_str_syntax_error_warning = '';
+
+ // Prepend the warning box to the content.
+ $p_str_content = $l_str_syntax_error_warning . $p_str_content;
+
+ // Checked, set flag to false to prevent duplicate warning.
+ self::$a_bool_syntax_error_flag = false;
+
+ return $p_str_content;
+ }
+ }
+
+ // Load referrer templates if footnotes text not hidden.
+ if ( ! $p_bool_hide_footnotes_text ) {
+
+ // Load footnote referrer template file.
+ if ( self::$a_bool_alternative_tooltips_enabled ) {
+ $l_obj_template = new MCI_Footnotes_Template( MCI_Footnotes_Template::C_STR_PUBLIC, 'footnote-alternative' );
+ } else {
+ $l_obj_template = new MCI_Footnotes_Template( MCI_Footnotes_Template::C_STR_PUBLIC, 'footnote' );
+ }
+
+ /**
+ * Call Boolean again for robustness when priority levels don’t match any longer.
+ *
+ * - Bugfix: Tooltips: fix display in Popup Maker popups by correcting a coding error.
+ *
+ * @since 2.5.4
+ * @see self::add_filter('pum_popup_content', array($this, "the_content"), $l_int_the_content_priority)
+ */
+ self::$a_bool_tooltips_enabled = MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_ENABLED ) );
+ self::$a_bool_alternative_tooltips_enabled = MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_ALTERNATIVE ) );
+
+ // Load tooltip inline script if jQuery tooltips are enabled.
+ if ( self::$a_bool_tooltips_enabled && ! self::$a_bool_alternative_tooltips_enabled ) {
+ $l_obj_template_tooltip = new MCI_Footnotes_Template( MCI_Footnotes_Template::C_STR_PUBLIC, 'tooltip' );
+ }
+ } else {
+ $l_obj_template = null;
+ $l_obj_template_tooltip = null;
+ }
+
+ // Search footnotes short codes in the content.
+ do {
+ // Get first occurrence of the footnote start tag short code.
+ $i_int_len_content = strlen( $p_str_content );
+ if ( $l_int_pos_start > $i_int_len_content ) {
+ $l_int_pos_start = $i_int_len_content;
+ }
+ $l_int_pos_start = strpos( $p_str_content, $l_str_starting_tag, $l_int_pos_start );
+ // No short code found, stop here.
+ if ( ! $l_int_pos_start ) {
+ break;
+ }
+ // Get first occurrence of the footnote end tag short code.
+ $l_int_pos_end = strpos( $p_str_content, $l_str_ending_tag, $l_int_pos_start );
+ // No short code found, stop here.
+ if ( ! $l_int_pos_end ) {
+ break;
+ }
+ // Calculate the length of the footnote.
+ $l_int_length = $l_int_pos_end - $l_int_pos_start;
+
+ // Get footnote text.
+ $l_str_footnote_text = substr( $p_str_content, $l_int_pos_start + strlen( $l_str_starting_tag ), $l_int_length - strlen( $l_str_starting_tag ) );
+
+ // Get tooltip text if present.
+ self::$a_str_tooltip_shortcode = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_TOOLTIP_EXCERPT_DELIMITER );
+ self::$a_int_tooltip_shortcode_length = strlen( self::$a_str_tooltip_shortcode );
+ $l_int_tooltip_text_length = strpos( $l_str_footnote_text, self::$a_str_tooltip_shortcode );
+ $l_bool_has_tooltip_text = ! $l_int_tooltip_text_length ? false : true;
+ if ( $l_bool_has_tooltip_text ) {
+ $l_str_tooltip_text = substr( $l_str_footnote_text, 0, $l_int_tooltip_text_length );
+ } else {
+ $l_str_tooltip_text = '';
+ }
+
+ /**
+ * URL line wrapping for Unicode non conformant browsers.
+ *
+ * @since 2.1.1 (CSS)
+ * @since 2.1.4 (PHP)
+ *
+ * Despite Unicode recommends to line-wrap URLs at slashes, and Firefox follows
+ * the Unicode standard, Chrome does not, making long URLs hang out of tooltips
+ * or extend reference containers, so that the end is hidden outside the window
+ * and may eventually be viewed after we scroll horizontally or zoom out. It is
+ * up to the web page to make URLs breaking anywhere by wrapping them in a span
+ * that is assigned appropriate CSS properties and values.
+ * @see css/public.css
+ *
+ * - Bugfix: Tooltips: fix line breaking for hyperlinked URLs in Unicode-non-compliant user agents, thanks to @andreasra bug report.
+ *
+ * @since 2.1.1
+ *
+ * @reporter @andreasra
+ * @link https://wordpress.org/support/topic/footnotes-appearing-in-header/page/3/#post-13657398
+ *
+ *
+ * - Bugfix: Reference container: fix width in mobile view by URL wrapping for Unicode-non-conformant browsers, thanks to @karolszakiel bug report.
+ *
+ * @since 2.1.3
+ * @date 2020-11-23
+ *
+ * @reporter @karolszakiel
+ * @link https://wordpress.org/support/topic/footnotes-on-mobile-phones/
+ *
+ *
+ * - Bugfix: Reference container, tooltips: fix line wrapping of URLs (hyperlinked or not) based on pattern, not link element.
+ *
+ * @since 2.1.4
+ * @date 2020-11-25T0837+0100
+ * @link https://wordpress.org/support/topic/footnotes-on-mobile-phones/#post-13710682
+ *
+ *
+ * - Bugfix: Reference container, tooltips: URL wrap: exclude image source too, thanks to @bjrnet21 bug report.
+ *
+ * @since 2.1.5
+ *
+ * @reporter @bjrnet21
+ * @link https://wordpress.org/support/topic/2-1-4-breaks-on-my-site-images-dont-show/
+ *
+ *
+ * - Bugfix: Reference container, tooltips: URL wrap: fix regex, thanks to @a223123131 bug report.
+ *
+ * @since 2.1.6
+ * @date 2020-12-09T1921+0100
+ *
+ * @reporter @a223123131
+ * @link https://wordpress.org/support/topic/broken-layout-starting-version-2-1-4/
+ *
+ * Even ARIA labels may take a URL as value, so use \w=[\'"] as a catch-all 2020-12-10T1005+0100
+ *
+ * - Bugfix: Dashboard: URL wrap: add option to properly enable/disable URL wrap.
+ *
+ * @since 2.1.6
+ * @date 2020-12-09T1606+0100
+ *
+ *
+ * - Bugfix: Reference container, tooltips: URL wrap: make the quotation mark optional wrt query parameters, thanks to @spiralofhope2 bug report.
+ *
+ * @since 2.2.6
+ * @date 2020-12-23T0409+0100
+ *
+ * @reporter @spiralofhope2
+ * @link https://wordpress.org/support/topic/two-links-now-breaks-footnotes-with-blogtext/
+ *
+ *
+ * - Bugfix: Reference container, tooltips: URL wrap: remove a bug introduced in the regex, thanks to @rjl20 @spaceling @lukashuggenberg @klusik @friedrichnorth @bernardzit bug reports.
+ *
+ * @since 2.2.7
+ * @date 2020-12-23T1046+0100
+ *
+ * @reporter @rjl20
+ * @link https://wordpress.org/support/topic/two-links-now-breaks-footnotes-with-blogtext/#post-13825479
+ *
+ * @reporter @spaceling
+ * @link https://wordpress.org/support/topic/two-links-now-breaks-footnotes-with-blogtext/#post-13825532
+ *
+ * @reporter @lukashuggenberg
+ * @link https://wordpress.org/support/topic/2-2-6-breaks-all-footnotes/
+ *
+ * @reporter @klusik
+ * @link https://wordpress.org/support/topic/2-2-6-breaks-all-footnotes/#post-13825885
+ *
+ * @reporter @friedrichnorth
+ * @link https://wordpress.org/support/topic/footnotes-dont-show-after-update-to-2-2-6/
+ *
+ * @reporter @bernardzit
+ * @link https://wordpress.org/support/topic/footnotes-dont-show-after-update-to-2-2-6/#post-13826029
+ *
+ * @since 2.2.8 Bugfix: Reference container, tooltips: URL wrap: correctly make the quotation mark optional wrt query parameters, thanks to @spiralofhope2 bug report.
+ * @date 2020-12-23T1107+0100
+ *
+ * Correct is duplicating the negative lookbehind w/o quotes: '(?get( MCI_Footnotes_Settings::C_STR_FOOTNOTE_URL_WRAP_ENABLED ) ) ) {
+
+ $l_str_footnote_text = preg_replace(
+ '#(?$1',
+ $l_str_footnote_text
+ );
+ }
+
+ // Text to be displayed instead of the footnote.
+ $l_str_footnote_replace_text = '';
+
+ // Whether hard links are enabled.
+ if ( self::$a_bool_hard_links_enable ) {
+
+ // Get the configurable parts.
+ self::$a_str_referrer_link_slug = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_REFERRER_FRAGMENT_ID_SLUG );
+ self::$a_str_footnote_link_slug = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTE_FRAGMENT_ID_SLUG );
+ self::$a_str_link_ids_separator = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_HARD_LINK_IDS_SEPARATOR );
+
+ // Streamline ID concatenation.
+ self::$a_str_post_container_id_compound = self::$a_str_link_ids_separator;
+ self::$a_str_post_container_id_compound .= self::$a_int_post_id;
+ self::$a_str_post_container_id_compound .= self::$a_str_link_ids_separator;
+ self::$a_str_post_container_id_compound .= self::$a_int_reference_container_id;
+ self::$a_str_post_container_id_compound .= self::$a_str_link_ids_separator;
+
+ }
+
+ // Display the footnote referrers and the tooltips.
+ if ( ! $p_bool_hide_footnotes_text ) {
+ $l_int_index = MCI_Footnotes_Convert::index( $l_int_footnote_index, MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_COUNTER_STYLE ) );
+
+ // Display only a truncated footnote text if option enabled.
+ $l_bool_enable_excerpt = MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_ENABLED ) );
+ $l_int_max_length = intval( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_LENGTH ) );
+
+ // Define excerpt text as footnote text by default.
+ $l_str_excerpt_text = $l_str_footnote_text;
+
+ /**
+ * Tooltip truncation.
+ *
+ * - Adding: Tooltips: Read-on button: Label: configurable instead of localizable, thanks to @rovanov example provision.
+ *
+ * @since 2.1.0
+ * @date 2020-11-08T2146+0100
+ *
+ * @reporter @rovanov
+ * @link https://wordpress.org/support/topic/offset-x-axis-and-offset-y-axis-does-not-working/
+ *
+ * If the tooltip truncation option is enabled, it’s done based on character count,
+ * and a trailing incomplete word is cropped.
+ * This is equivalent to the WordPress default excerpt generation, i.e. without a
+ * custom excerpt and without a delimiter. But WordPress does word count, usually 55.
+ */
+ if ( self::$a_bool_tooltips_enabled && $l_bool_enable_excerpt ) {
+ $l_str_dummy_text = wp_strip_all_tags( $l_str_footnote_text );
+ if ( is_int( $l_int_max_length ) && strlen( $l_str_dummy_text ) > $l_int_max_length ) {
+ $l_str_excerpt_text = substr( $l_str_dummy_text, 0, $l_int_max_length );
+ $l_str_excerpt_text = substr( $l_str_excerpt_text, 0, strrpos( $l_str_excerpt_text, ' ' ) );
+ $l_str_excerpt_text .= ' … <';
+ $l_str_excerpt_text .= self::$a_bool_hard_links_enable ? 'a' : 'span';
+ $l_str_excerpt_text .= ' class="footnote_tooltip_continue" ';
+ $l_str_excerpt_text .= 'onclick="footnote_move_to_anchor_' . self::$a_int_post_id;
+ $l_str_excerpt_text .= '_' . self::$a_int_reference_container_id;
+ $l_str_excerpt_text .= '(\'footnote_plugin_reference_' . self::$a_int_post_id;
+ $l_str_excerpt_text .= '_' . self::$a_int_reference_container_id;
+ $l_str_excerpt_text .= "_$l_int_index');\"";
+
+ // If enabled, add the hard link fragment ID.
+ if ( self::$a_bool_hard_links_enable ) {
+
+ $l_str_excerpt_text .= ' href="#';
+ $l_str_excerpt_text .= self::$a_str_footnote_link_slug;
+ $l_str_excerpt_text .= self::$a_str_post_container_id_compound;
+ $l_str_excerpt_text .= $l_int_index;
+ $l_str_excerpt_text .= '"';
+ }
+
+ $l_str_excerpt_text .= '>';
+
+ /**
+ * Configurable read-on button label.
+ *
+ * - Adding: Tooltips: Read-on button: Label: configurable instead of localizable, thanks to @rovanov example provision.
+ *
+ * @since 2.1.0
+ * @date 2020-11-08T2146+0100
+ *
+ * @reporter @rovanov
+ * @link https://wordpress.org/support/topic/offset-x-axis-and-offset-y-axis-does-not-working/
+ */
+ $l_str_excerpt_text .= MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_TOOLTIP_READON_LABEL );
+
+ $l_str_excerpt_text .= self::$a_bool_hard_links_enable ? '' : '';
+ }
+ }
+
+ /**
+ * Referrers element superscript or baseline.
+ *
+ * Referrers: new setting for vertical align: superscript (default) or baseline (optional), thanks to @cwbayer bug report
+ *
+ * @since 2.1.1
+ *
+ * @reporter @cwbayer
+ * @link https://wordpress.org/support/topic/footnote-number-in-text-superscript-disrupts-leading/
+ *
+ * define the HTML element to use for the referrers.
+ */
+ if ( MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_REFERRER_SUPERSCRIPT_TAGS ) ) ) {
+
+ $l_str_sup_span = 'sup';
+
+ } else {
+
+ $l_str_sup_span = 'span';
+ }
+
+ // Whether hard links are enabled.
+ if ( self::$a_bool_hard_links_enable ) {
+
+ self::$a_str_link_span = 'a';
+ self::$a_str_link_close_tag = '';
+ // Self::$a_str_link_open_tag will be defined as needed.
+
+ // Compose hyperlink address (leading space is in template).
+ $l_str_footnote_link_argument = 'href="#';
+ $l_str_footnote_link_argument .= self::$a_str_footnote_link_slug;
+ $l_str_footnote_link_argument .= self::$a_str_post_container_id_compound;
+ $l_str_footnote_link_argument .= $l_int_index;
+ $l_str_footnote_link_argument .= '" class="footnote_hard_link"';
+
+ /**
+ * Compose fragment ID anchor with offset, for use in reference container.
+ * Empty span, child of empty span, to avoid tall dotted rectangles in browser.
+ */
+ $l_str_referrer_anchor_element = '';
+
+ } else {
+
+ /**
+ * Initialize hard link variables when hard links are disabled.
+ *
+ * - Bugfix: Process: initialize hard link address variables to empty string to fix 'undefined variable' bug, thanks to @a223123131 bug report.
+ *
+ * @since 2.4.0
+ * @date 2021-01-04T1622+0100
+ *
+ * @reporter @a223123131
+ * @link https://wordpress.org/support/topic/wp_debug-php-notice/
+ *
+ * If no hyperlink nor offset anchor is needed, initialize as empty.
+ */
+ $l_str_footnote_link_argument = '';
+ $l_str_referrer_anchor_element = '';
+
+ // The link element is set independently as it may be needed for styling.
+ if ( MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_LINK_ELEMENT_ENABLED ) ) ) {
+
+ self::$a_str_link_span = 'a';
+ self::$a_str_link_open_tag = '';
+ self::$a_str_link_close_tag = '';
+
+ }
+ }
+
+ // Determine tooltip content.
+ if ( self::$a_bool_tooltips_enabled ) {
+ $l_str_tooltip_content = $l_bool_has_tooltip_text ? $l_str_tooltip_text : $l_str_excerpt_text;
+ } else {
+ $l_str_tooltip_content = '';
+ }
+
+ /**
+ * Determine shrink width if alternative tooltips are enabled.
+ *
+ * @since 2.5.6
+ */
+ $l_str_tooltip_style = '';
+ if ( self::$a_bool_alternative_tooltips_enabled && self::$a_bool_tooltips_enabled ) {
+ $l_int_tooltip_length = strlen( wp_strip_all_tags( $l_str_tooltip_content ) );
+ if ( $l_int_tooltip_length < 70 ) {
+ $l_str_tooltip_style = ' style="width: ';
+ $l_str_tooltip_style .= ( $l_int_tooltip_length * .7 );
+ $l_str_tooltip_style .= 'em;"';
+ }
+ }
+
+ // Fill in 'templates/public/footnote.html'.
+ $l_obj_template->replace(
+ array(
+ 'link-span' => self::$a_str_link_span,
+ 'post_id' => self::$a_int_post_id,
+ 'container_id' => self::$a_int_reference_container_id,
+ 'note_id' => $l_int_index,
+ 'hard-link' => $l_str_footnote_link_argument,
+ 'sup-span' => $l_str_sup_span,
+ 'before' => MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_STYLING_BEFORE ),
+ 'index' => $l_int_index,
+ 'after' => MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_STYLING_AFTER ),
+ 'anchor-element' => $l_str_referrer_anchor_element,
+ 'style' => $l_str_tooltip_style,
+ 'text' => $l_str_tooltip_content,
+ )
+ );
+ $l_str_footnote_replace_text = $l_obj_template->get_content();
+
+ // Reset the template.
+ $l_obj_template->reload();
+
+ // If standard tooltips are enabled but alternative are not.
+ if ( self::$a_bool_tooltips_enabled && ! self::$a_bool_alternative_tooltips_enabled ) {
+
+ $l_int_offset_y = intval( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_Y ) );
+ $l_int_offset_x = intval( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_X ) );
+ $l_int_fade_in_delay = intval( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_INT_MOUSE_OVER_BOX_FADE_IN_DELAY ) );
+ $l_int_fade_in_duration = intval( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_INT_MOUSE_OVER_BOX_FADE_IN_DURATION ) );
+ $l_int_fade_out_delay = intval( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_INT_MOUSE_OVER_BOX_FADE_OUT_DELAY ) );
+ $l_int_fade_out_duration = intval( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_INT_MOUSE_OVER_BOX_FADE_OUT_DURATION ) );
+
+ // Fill in 'templates/public/tooltip.html'.
+ $l_obj_template_tooltip->replace(
+ array(
+ 'post_id' => self::$a_int_post_id,
+ 'container_id' => self::$a_int_reference_container_id,
+ 'note_id' => $l_int_index,
+ 'position' => MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_POSITION ),
+ 'offset-y' => ! empty( $l_int_offset_y ) ? $l_int_offset_y : 0,
+ 'offset-x' => ! empty( $l_int_offset_x ) ? $l_int_offset_x : 0,
+ 'fade-in-delay' => ! empty( $l_int_fade_in_delay ) ? $l_int_fade_in_delay : 0,
+ 'fade-in-duration' => ! empty( $l_int_fade_in_duration ) ? $l_int_fade_in_duration : 0,
+ 'fade-out-delay' => ! empty( $l_int_fade_out_delay ) ? $l_int_fade_out_delay : 0,
+ 'fade-out-duration' => ! empty( $l_int_fade_out_duration ) ? $l_int_fade_out_duration : 0,
+ )
+ );
+ $l_str_footnote_replace_text .= $l_obj_template_tooltip->get_content();
+ $l_obj_template_tooltip->reload();
+ }
+ }
+ // Replace the footnote with the template.
+ $p_str_content = substr_replace( $p_str_content, $l_str_footnote_replace_text, $l_int_pos_start, $l_int_length + strlen( $l_str_ending_tag ) );
+
+ // Add footnote only if not empty.
+ if ( ! empty( $l_str_footnote_text ) ) {
+ // Set footnote to the output box at the end.
+ self::$a_arr_footnotes[] = $l_str_footnote_text;
+ // Increase footnote index.
+ $l_int_footnote_index++;
+ }
+
+ /**
+ * Fixes a footnotes numbering bug (happening under de facto rare circumstances).
+ *
+ * - Bugfix: Fixed occasional bug where footnote ordering could be out of sequence
+ *
+ * @since 1.6.4
+ * @date 2016-06-29T0054+0000
+ * @committer @dartiss
+ * @link https://plugins.trac.wordpress.org/browser/footnotes/trunk/class/task.php?rev=1445718 @dartiss’ class/task.php
+ * @link https://plugins.trac.wordpress.org/log/footnotes/trunk/class/task.php?rev=1445718 @dartiss re-added class/task.php
+ * @link https://plugins.trac.wordpress.org/browser/footnotes/trunk/class?rev=1445711 class/ w/o task.php
+ * @link https://plugins.trac.wordpress.org/changeset/1445711/footnotes/trunk/class @dartiss deleted class/task.php
+ * @link https://plugins.trac.wordpress.org/browser/footnotes/trunk/class/task.php?rev=1026210 @aricura’s latest class/task.php
+ *
+ *
+ * - Bugfix: Process: fix numbering bug impacting footnote #2 with footnote #1 close to start, thanks to @rumperuu bug report, thanks to @lolzim code contribution.
+ *
+ * @since 2.5.5
+ *
+ * @contributor @lolzim
+ * @link https://wordpress.org/support/topic/footnotes-numbered-incorrectly/#post-14062032
+ *
+ * @reporter @rumperuu
+ * @link https://wordpress.org/support/topic/footnotes-numbered-incorrectly/
+ *
+ * This assignment was overridden by another one, causing the algorithm to jump back
+ * near the post start to a position calculated as the sum of the length of the last
+ * footnote and the length of the last footnote replace text.
+ * A bug disturbing the order of the footnotes depending on the text before the first
+ * footnote, the length of the first footnote and the length of the templates for the
+ * footnote and the tooltip. Moreover, it was causing non-trivial process garbage.
+ */
+ // Add offset to the new starting position.
+ $l_int_pos_start += $l_int_length + strlen( $l_str_ending_tag );
+
+ } while ( true );
+
+ // Return content.
+ return $p_str_content;
+ }
+
+ /**
+ * Generates the reference container.
+ *
+ * @since 1.5.0
+ * @return string
+ *
+ * @since 2.0.0 Update: remove backlink symbol along with column 2 of the reference container
+ * @since 2.0.3 Bugfix: prepend an arrow on user request
+ * @since 2.0.6 Bugfix: Reference container: fix line breaking behavior in footnote number clusters.
+ * @since 2.0.4 Bugfix: restore the arrow select and backlink symbol input settings
+ * @since 2.1.1 Bugfix: Referrers, reference container: Combining identical footnotes: fix dead links and ensure referrer-backlink bijectivity, thanks to @happyches bug report.
+ * @since 2.1.1 Bugfix: Reference container: Backlink symbol: make optional, not suggest configuring it to invisible, thanks to @spaceling feedback.
+ */
+ public function reference_container() {
+
+ // No footnotes have been replaced on this page.
+ if ( empty( self::$a_arr_footnotes ) ) {
+ return '';
+ }
+
+ /**
+ * Footnote index backlink symbol.
+ *
+ * - Bugfix: Reference container: Backlink symbol: make optional, not suggest configuring it to invisible, thanks to @spaceling feedback.
+ *
+ * @since 2.1.1
+ *
+ * @reporter @spaceling
+ * @link https://wordpress.org/support/topic/change-the-position-5/page/2/#post-13671138
+ *
+ * If the backlink symbol is enabled.
+ */
+ if ( MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_BACKLINK_SYMBOL_ENABLE ) ) ) {
+
+ // Get html arrow.
+ $l_str_arrow = MCI_Footnotes_Convert::get_arrow( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_HYPERLINK_ARROW ) );
+ // Set html arrow to the first one if invalid index defined.
+ if ( is_array( $l_str_arrow ) ) {
+ $l_str_arrow = MCI_Footnotes_Convert::get_arrow( 0 );
+ }
+ // Get user defined arrow.
+ $l_str_arrow_user_defined = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_HYPERLINK_ARROW_USER_DEFINED );
+ if ( ! empty( $l_str_arrow_user_defined ) ) {
+ $l_str_arrow = $l_str_arrow_user_defined;
+ }
+
+ // Wrap the arrow in a @media print { display:hidden } span.
+ $l_str_footnote_arrow = '';
+
+ } else {
+
+ // If the backlink symbol isn’t enabled, set it to empty.
+ $l_str_arrow = '';
+ $l_str_footnote_arrow = '';
+
+ }
+
+ /**
+ * Backlink separator.
+ *
+ * - Bugfix: Reference container: make separating and terminating punctuation optional and configurable, thanks to @docteurfitness issue report and code contribution.
+ *
+ * @since 2.1.4
+ * @date 2020-11-28T1048+0100
+ *
+ * @contributor @docteurfitness
+ * @link https://wordpress.org/support/topic/update-2-1-3/#post-13704194
+ *
+ * @reporter @docteurfitness
+ * @link https://wordpress.org/support/topic/update-2-1-3/
+ *
+ * Initially a comma was appended in this algorithm for enumerations.
+ * The comma in enumerations is not generally preferred.
+ */
+ if ( MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_BACKLINKS_SEPARATOR_ENABLED ) ) ) {
+
+ // Check if it is input-configured.
+ $l_str_separator = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_BACKLINKS_SEPARATOR_CUSTOM );
+
+ if ( empty( $l_str_separator ) ) {
+
+ // If it is not, check which option is on.
+ $l_str_separator_option = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_BACKLINKS_SEPARATOR_OPTION );
+ switch ( $l_str_separator_option ) {
+ case 'comma':
+ $l_str_separator = ',';
+ break;
+ case 'semicolon':
+ $l_str_separator = ';';
+ break;
+ case 'en_dash':
+ $l_str_separator = ' –';
+ break;
+ }
+ }
+ } else {
+
+ $l_str_separator = '';
+ }
+
+ /**
+ * Backlink terminator.
+ *
+ * Initially a dot was appended in the table row template.
+ *
+ * @since 2.0.6 a dot after footnote numbers is discarded as not localizable;
+ * making it optional was envisaged.
+ * @since 2.1.4 the terminator is optional, has options, and is configurable.
+ */
+ if ( MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_BACKLINKS_TERMINATOR_ENABLED ) ) ) {
+
+ // Check if it is input-configured.
+ $l_str_terminator = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_BACKLINKS_TERMINATOR_CUSTOM );
+
+ if ( empty( $l_str_terminator ) ) {
+
+ // If it is not, check which option is on.
+ $l_str_terminator_option = MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_BACKLINKS_TERMINATOR_OPTION );
+ switch ( $l_str_terminator_option ) {
+ case 'period':
+ $l_str_terminator = '.';
+ break;
+ case 'parenthesis':
+ $l_str_terminator = ')';
+ break;
+ case 'colon':
+ $l_str_terminator = ':';
+ break;
+ }
+ }
+ } else {
+
+ $l_str_terminator = '';
+ }
+
+ /**
+ * Line breaks.
+ *
+ * - Bugfix: Reference container: Backlinks: fix stacked enumerations by adding optional line breaks.
+ *
+ * @since 2.1.4
+ * @date 2020-11-28T1049+0100
+ *
+ * The backlinks of combined footnotes are generally preferred in an enumeration.
+ * But when few footnotes are identical, stacking the items in list form is better.
+ * Variable number length and proportional character width require explicit line breaks.
+ * Otherwise, an ordinary space character offering a line break opportunity is inserted.
+ */
+ $l_str_line_break = MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_BACKLINKS_LINE_BREAKS_ENABLED ) ) ? '
' : ' ';
+
+ /**
+ * Line breaks for source readability.
+ *
+ * For maintenance and support, table rows in the reference container should be
+ * separated by an empty line. So we add these line breaks for source readability.
+ * Before the first table row (breaks between rows are ~200 lines below).
+ */
+ $l_str_body = "\r\n\r\n";
+
+ /**
+ * Reference container table row template load.
+ *
+ * - Bugfix: Reference container: option to restore pre-2.0.0 layout with the backlink symbol in an extra column.
+ *
+ * @since 2.1.1
+ * @date 2020-11-16T2024+0100
+ */
+
+ // When combining identical footnotes is turned on, another template is needed.
+ if ( MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_COMBINE_IDENTICAL_FOOTNOTES ) ) ) {
+ // The combining template allows for backlink clusters and supports cell clicking for single notes.
+ $l_obj_template = new MCI_Footnotes_Template( MCI_Footnotes_Template::C_STR_PUBLIC, 'reference-container-body-combi' );
+
+ } else {
+
+ // When 3-column layout is turned on (only available if combining is turned off).
+ if ( MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_3COLUMN_LAYOUT_ENABLE ) ) ) {
+ $l_obj_template = new MCI_Footnotes_Template( MCI_Footnotes_Template::C_STR_PUBLIC, 'reference-container-body-3column' );
+
+ } else {
+
+ // When switch symbol and index is turned on, and combining and 3-columns are off.
+ if ( MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_BACKLINK_SYMBOL_SWITCH ) ) ) {
+ $l_obj_template = new MCI_Footnotes_Template( MCI_Footnotes_Template::C_STR_PUBLIC, 'reference-container-body-switch' );
+
+ } else {
+
+ // Default is the standard template.
+ $l_obj_template = new MCI_Footnotes_Template( MCI_Footnotes_Template::C_STR_PUBLIC, 'reference-container-body' );
+
+ }
+ }
+ }
+
+ /**
+ * Switch backlink symbol and footnote number.
+ *
+ * - Bugfix: Reference container: option to append symbol (prepended by default), thanks to @spaceling code contribution.
+ *
+ * @since 2.1.1
+ * @date 2020-11-16T2024+0100
+ *
+ * @contributor @spaceling
+ * @link https://wordpress.org/support/topic/change-the-position-5/#post-13615994
+ *
+ *
+ * - Bugfix: Reference container: Backlink symbol: support for appending when combining identicals is on.
+ *
+ * @since 2.1.4
+ * @date 2020-11-26T1633+0100
+ */
+ $l_bool_symbol_switch = MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_BACKLINK_SYMBOL_SWITCH ) );
+
+ // Loop through all footnotes found in the page.
+ $num_footnotes = count( self::$a_arr_footnotes );
+ for ( $l_int_index = 0; $l_int_index < $num_footnotes; $l_int_index++ ) {
+
+ // Get footnote text.
+ $l_str_footnote_text = self::$a_arr_footnotes[ $l_int_index ];
+
+ // If footnote is empty, go to the next one;.
+ // With combine identicals turned on, identicals will be deleted and are skipped.
+ if ( empty( $l_str_footnote_text ) ) {
+ continue;
+ }
+
+ // Generate content of footnote index cell.
+ $l_int_first_footnote_index = ( $l_int_index + 1 );
+
+ // Get the footnote index string and.
+ // Keep supporting legacy index placeholder.
+ $l_str_footnote_id = MCI_Footnotes_Convert::index( ( $l_int_index + 1 ), MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_COUNTER_STYLE ) );
+
+ /**
+ * Case of only one backlink per table row.
+ *
+ * If enabled, and for the case the footnote is single, compose hard link.
+ */
+ // Define anyway.
+ $l_str_hard_link_address = '';
+
+ if ( self::$a_bool_hard_links_enable ) {
+
+ /**
+ * Use-Backbutton-Hint tooltip, optional and configurable.
+ *
+ * - Update: Reference container: Hard backlinks (optional): optional configurable tooltip hinting to use the backbutton instead, thanks to @theroninjedi47 bug report.
+ *
+ * @since 2.5.4
+ *
+ * @reporter @theroninjedi47
+ * @link https://wordpress.org/support/topic/hyperlinked-footnotes-creating-excessive-back-history/
+ *
+ * When hard links are enabled, clicks on the backlinks are logged in the browsing history.
+ * This tooltip hints to use the backbutton instead, so the history gets streamlined again.
+ * @link https://wordpress.org/support/topic/making-it-amp-compatible/#post-13837359
+ */
+ if ( MCI_Footnotes_Convert::to_bool( MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_BACKLINK_TOOLTIP_ENABLE ) ) ) {
+ $l_str_use_backbutton_hint = ' title="';
+ $l_str_use_backbutton_hint .= MCI_Footnotes_Settings::instance()->get( MCI_Footnotes_Settings::C_STR_FOOTNOTES_BACKLINK_TOOLTIP_TEXT );
+ $l_str_use_backbutton_hint .= '"';
+ } else {
+ $l_str_use_backbutton_hint = '';
+ }
+
+ /**
+ * Compose fragment ID anchor with offset, for use in reference container.
+ * Empty span, child of empty span, to avoid tall dotted rectangles in browser.
+ */
+ $l_str_footnote_anchor_element = '';
+
+ // Compose optional hard link address.
+ $l_str_hard_link_address = ' href="#';
+ $l_str_hard_link_address .= self::$a_str_referrer_link_slug;
+ $l_str_hard_link_address .= self::$a_str_post_container_id_compound;
+ $l_str_hard_link_address .= $l_str_footnote_id . '"';
+ $l_str_hard_link_address .= $l_str_use_backbutton_hint;
+
+ // Compose optional opening link tag with optional hard link, mandatory for instance.
+ self::$a_str_link_open_tag = '