' );
-
- printf( '' );
- }
-
- /**
- * AJAX call. returns a JSON string containing meta information about a specific WordPress Plugin.
- *
- * @author Stefan Herndler
- * @since 1.5.0
- */
- public function getPluginMetaInformation() {
- // get plugin internal name from POST data
- $l_str_PluginName = array_key_exists( 'plugin', $_POST ) ? $_POST['plugin'] : null;
- if ( empty( $l_str_PluginName ) ) {
- echo json_encode( array( 'error' => 'Plugin name invalid.' ) );
- exit;
- }
- $l_str_Url = 'https://api.wordpress.org/plugins/info/1.0/' . $l_str_PluginName . '.json';
- // call URL and collect data
- $l_arr_Response = wp_remote_get( $l_str_Url );
- // check if response is valid
- if ( is_wp_error( $l_arr_Response ) ) {
- echo json_encode( array( 'error' => 'Error receiving Plugin Information from WordPress.' ) );
- exit;
- }
- if ( ! array_key_exists( 'body', $l_arr_Response ) ) {
- echo json_encode( array( 'error' => 'Error reading WordPress API response message.' ) );
- exit;
- }
- // get the body of the response
- $l_str_Response = $l_arr_Response['body'];
- // get plugin object
- $l_arr_Plugin = json_decode( $l_str_Response, true );
- if ( empty( $l_arr_Plugin ) ) {
- echo json_encode( array( 'error' => 'Error reading Plugin meta information. URL: ' . $l_str_Url . ' Response: ' . $l_str_Response ) );
- exit;
- }
-
- $l_int_NumRatings = array_key_exists( 'num_ratings', $l_arr_Plugin ) ? intval( $l_arr_Plugin['num_ratings'] ) : 0;
- $l_int_Rating = array_key_exists( 'rating', $l_arr_Plugin ) ? floatval( $l_arr_Plugin['rating'] ) : 0.0;
- $l_int_Stars = round( 5 * $l_int_Rating / 100.0, 1 );
-
- // return Plugin information as JSON encoded string
- echo json_encode(
- array(
- 'error' => '',
- 'PluginDescription' => array_key_exists( 'short_description', $l_arr_Plugin ) ? html_entity_decode( $l_arr_Plugin['short_description'] ) : 'Error reading Plugin information',
- 'PluginAuthor' => array_key_exists( 'author', $l_arr_Plugin ) ? html_entity_decode( $l_arr_Plugin['author'] ) : 'unknown',
- 'PluginRatingText' => $l_int_Stars . ' ' . __( 'rating based on', MCI_Footnotes_Config::C_STR_PLUGIN_NAME ) . ' ' . $l_int_NumRatings . ' ' . __( 'ratings', MCI_Footnotes_Config::C_STR_PLUGIN_NAME ),
- 'PluginRating1' => $l_int_Stars >= 0.5 ? 'star-full' : 'star-empty',
- 'PluginRating2' => $l_int_Stars >= 1.5 ? 'star-full' : 'star-empty',
- 'PluginRating3' => $l_int_Stars >= 2.5 ? 'star-full' : 'star-empty',
- 'PluginRating4' => $l_int_Stars >= 3.5 ? 'star-full' : 'star-empty',
- 'PluginRating5' => $l_int_Stars >= 4.5 ? 'star-full' : 'star-empty',
- 'PluginRating' => $l_int_NumRatings,
- 'PluginLastUpdated' => array_key_exists( 'last_updated', $l_arr_Plugin ) ? $l_arr_Plugin['last_updated'] : 'unknown',
- 'PluginDownloads' => array_key_exists( 'downloaded', $l_arr_Plugin ) ? $l_arr_Plugin['downloaded'] : '---',
- )
- );
- exit;
- }
-}
diff --git a/class/hooks.php b/class/hooks.php
index ceb7147..7a9d253 100644
--- a/class/hooks.php
+++ b/class/hooks.php
@@ -1,94 +1,94 @@
-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;
- }
-}
+Clear_all();.
+ }
+
+ /**
+ * 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_plugin_file_name Plugins init file name.
+ * @return array
+ */
+ public static function Plugin_links( $p_arr_links, $p_str_plugin_file_name ) {
+ // 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 Play_pal Donate function.
+ $p_arr_links[] = sprintf( '%s', __( 'Donate', MCI_Footnotes_Config::C_STR_PLUGIN_NAME ) );
+ // Return new links.
+ return $p_arr_links;
+ }
+}
diff --git a/class/init.php b/class/init.php
index 2eb6ff4..32ba613 100644
--- a/class/init.php
+++ b/class/init.php
@@ -1,373 +1,381 @@
-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.
+ *
+ * @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 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.
+ *
+ * @author Stefan Herndler
+ * @since 1.5.0
+ */
+ private function initialize_dashboard() {
+ new MCI_Footnotes_Layout_Init();
+ }
+
+ /**
+ * Initializes the Plugin Task and registers the Task hooks.
+ *
+ * @author Stefan Herndler
+ * @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.
+ *
+ * @author Stefan Herndler
+ * @since 1.5.0
+ *
+ * @since 2.0.0 Update: Tooltips: fix disabling bug by loading j_query 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 j_query 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_BOOL_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_BOOL_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 j_query library registered by WordPress.
+ *
+ * - Bugfix: Reference container: optional alternative expanding and collapsing without j_query 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/
+ *
+ * j_query 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, j_query has become optional,
+ * but still enabled by default.
+ */
+ if ( $l_str_script_mode == 'jquery' || ( 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 j_query Tools library shipped with the plugin.
+ *
+ * redacted j_query.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 j_query UI from the Java_script Content Delivery Network.
+ *
+ * - Update: Tooltips: fix disabling bug by loading j_query UI library, thanks to @rajinderverma @ericcorbett2 @honlapdavid @mmallett bug reports, thanks to @vonpiernik code contribution.
+ *
+ * @since 2.0.0
+ * Alternatively, fetch j_query UI from cdnjs.cloudflare.com:
+ * @since 2.0.0 add j_query_uI from Cloudflare 2020-10-26T1907+0100
+ * Used to add j_query UI following @vonpiernik:
+ * :
+ *
+ *
+ * j_query_uI re-enables the tooltip infobox disabled when WPv5.5 was released.
+ *
+ * Updated for v2.0.4 by adding j_query 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( 'j_query_uI', '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( 'j_query_uI' );.
+ /**
+ * This is then needed instead of the above first instance:
+ * Add j_query Tools and finish adding j_query_uI: 2020-11-08T1638+0100/2020-11-08T2246+0100
+ */
+ // Wp_enqueue_script('mci-footnotes-js-jquery-tools', plugins_url('../js/jquery.tools.min.js', __FILE__), ['j_query_uI']);.
+
+ /**
+ * Enqueues some j_query UI libraries registered by WordPress.
+ *
+ * @since 2.0.4 add j_query 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_tooltips_enabled ) {
+ if ( self::$a_bool_alternative_tooltips_enabled ) {
+ $l_str_tooltip_mode = 'al';
+ $l_str_tcomplement = 'ternative-tooltips';
+ } else {
+ $l_str_tooltip_mode = 'jq';
+ $l_str_tcomplement = 'uery-tooltips';
+ }
+ } else {
+ $l_str_tooltip_mode = 'no';
+ $l_str_tcomplement = '-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 . $l_str_tcomplement . '-pagelayout-' . $l_str_page_layout_option,
+ plugins_url(
+ MCI_Footnotes_Config::C_STR_PLUGIN_NAME . '/css/footnotes-' . $l_str_tooltip_mode . '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 ( $l_str_page_layout_option != 'none' ) {
+ 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..461e2a4 100644
--- a/class/language.php
+++ b/class/language.php
@@ -1,108 +1,107 @@
- 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_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->load_all();
+ }
+
+ /**
+ * 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 get_container( $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 get_defaults( $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 load_all() {
+ // 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->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.
+ *
+ * @author Stefan Herndler
+ * @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.
+ *
+ * @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 Clear_all() {
+ // Iterate through each Settings Container.
+ for ( $i = 0; $i < count( $this->a_arr_container ); $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.
+ *
+ * @author Stefan Herndler
+ * @since 1.5.0
+ */
+ public function Register_settings() {
+ // Register all settings.
+ for ( $i = 0; $i < count( $this->a_arr_container ); $i++ ) {
+ register_setting( $this->get_container( $i ), $this->get_container( $i ) );
+ }
+ }
+}
diff --git a/class/task.php b/class/task.php
index 4fae34f..589734f 100644
--- a/class/task.php
+++ b/class/task.php
@@ -1,2333 +1,2344 @@
-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) {
- // 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 = '
';
- $l_str_SyntaxErrorWarning .= __("WARNING: unbalanced footnote start tag short code found.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME);
- $l_str_SyntaxErrorWarning .= '
';
-
- // syntax validation setting in the dashboard under the General settings tab:
- $l_str_SyntaxErrorWarning .= sprintf( __("If this warning is irrelevant, please disable the syntax validation feature in the dashboard under %s > %s > %s.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), __("General settings", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), __("Footnote start and end short codes", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), __("Check for balanced shortcodes", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) );
-
- $l_str_SyntaxErrorWarning .= '
';
- $l_str_SyntaxErrorWarning .= __("Unbalanced start tag short code found before:", MCI_Footnotes_Config::C_STR_PLUGIN_NAME);
- $l_str_SyntaxErrorWarning .= '
', $l_str_love_me_text );
+ }
+
+ /**
+ * 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 ) {
+ // 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::to_bool( 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->replace_post_object( $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->replace_post_object( $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 replace_post_object( $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_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 ) !== false ) {
+
+ $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 ) !== false ) {
+ 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.
+ *
+ * @author Stefan Herndler
+ * @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 ( $l_str_starting_tag == 'userdefined' || $l_str_ending_tag == 'userdefined' ) {
+ $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_BOOL_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 = strip_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 = '
';
+ $l_str_syntax_error_warning .= __( 'WARNING: unbalanced footnote start tag short code found.', MCI_Footnotes_Config::C_STR_PLUGIN_NAME );
+ $l_str_syntax_error_warning .= '
';
+
+ // Syntax validation setting in the dashboard under the General settings tab:.
+ $l_str_syntax_error_warning .= sprintf( __( 'If this warning is irrelevant, please disable the syntax validation feature in the dashboard under %1$s > %2$s > %3$s.', MCI_Footnotes_Config::C_STR_PLUGIN_NAME ), __( 'General settings', MCI_Footnotes_Config::C_STR_PLUGIN_NAME ), __( 'Footnote start and end short codes', MCI_Footnotes_Config::C_STR_PLUGIN_NAME ), __( 'Check for balanced shortcodes', MCI_Footnotes_Config::C_STR_PLUGIN_NAME ) );
+
+ $l_str_syntax_error_warning .= '
';
+ $l_str_syntax_error_warning .= __( 'Unbalanced start tag short code found before:', MCI_Footnotes_Config::C_STR_PLUGIN_NAME );
+ $l_str_syntax_error_warning .= '