PluginProbe
Modern Footnotes / 1.4.6
Modern Footnotes v1.4.6
1.5.1 1.5.0 1.4.21 trunk 1.0 1.0.1 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.0 1.3.1 1.3.10 1.3.11 1.3.2 1.3.3 All 52 releases
modern-footnotes / modern-footnotes.php

modern-footnotes.php in Modern Footnotes 1.4.6, at modern-footnotes.php

663 lines 29.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Modern Footnotes
4 Plugin URI: http://prismtechstudios.com/modern-footnotes
5 Text Domain: modern-footnotes
6 Description: Add inline footnotes to your post via the footnote icon on the toolbar for editing posts and pages. Or, use the [mfn] or [modern_footnote] shortcodes [mfn]like this[/mfn].
7 Version: 1.4.6
8 Author: Prism Tech Studios
9 Author URI: http://prismtechstudios.com/
10 License: GPL2
11 License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
12 */
13
14 //don't let users call this file directly
15 defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
16
17 $modern_footnotes_version = '1.4.6';
18
19 $modern_footnotes_options = get_option('modern_footnotes_settings');
20
21 // set default options, if they have not been set
22 if ($modern_footnotes_options === FALSE) {
23 $modern_footnotes_options = [];
24 }
25 if (get_option('modern_footnotes_include_footnote_list_at_end_of_rss_content_default_value_has_been_set') === FALSE &&
26 !isset($modern_footnotes_options['modern_footnotes_include_footnote_list_at_end_of_rss_content'])) {
27 $modern_footnotes_options['modern_footnotes_include_footnote_list_at_end_of_rss_content'] = 1;
28 update_option('modern_footnotes_include_footnote_list_at_end_of_rss_content_default_value_has_been_set', 1); // this variable is so the default value doesn't get reset if modern_footnotes_include_footnote_list_at_end_of_rss_content is removed from optiosn (which happens when the settings checkbox is unchecked)
29 update_option('modern_footnotes_settings', $modern_footnotes_options);
30 }
31 if (get_option('modern_footnotes_use_expandable_footnotes_on_desktop_instead_of_tooltips_has_been_migrated') === FALSE &&
32 !isset($modern_footnotes_options['desktop_footnote_behavior']) &&
33 isset($modern_footnotes_options['use_expandable_footnotes_on_desktop_instead_of_tooltips']) &&
34 $modern_footnotes_options['use_expandable_footnotes_on_desktop_instead_of_tooltips']) {
35 $modern_footnotes_options['desktop_footnote_behavior'] = 'expandable';
36 update_option('modern_footnotes_use_expandable_footnotes_on_desktop_instead_of_tooltips_has_been_migrated', 1); // this variable is so the default value doesn't get re-migrated
37 update_option('modern_footnotes_settings', $modern_footnotes_options);
38 }
39
40 //will contain an entry for each unique post displayed on the page. Each post will have three values:
41 // modern_footnotes_post_number -- a number identifying the post that can be written out to the HTML
42 // used_reference_numbers -- an array of the reference numbers for the footnotes that have been used
43 // footnotes -- an array containing each individual footnote, keyed by the reference number
44 // footnotes_previously_used -- an array, that if it appears, is an array that could contain multiple previous values of the `footnotes` property. The `footnotes` property is reset when `referencereset` is passed into the mfn shortcode, and previously used footnotes are all stored in this array
45 $modern_footnotes_all_posts_data = array();
46
47 $current_modern_footnotes_post_number = 0;
48
49 function modern_footnotes_execute_mfn_list_shortcode($content) {
50 $content = str_replace('[mfn_list_execute_after_content_processed]', modern_footnotes_list_footnotes(), $content);
51 return $content;
52 }
53
54 function modern_footnotes_list_footnotes($show_only_when_printing = FALSE, $hide_when_printing = FALSE, $for_rss_feed = FALSE) {
55 global $modern_footnotes_all_posts_data;
56 $scope_id = modern_footnotes_get_post_scope_id();
57 if (empty($modern_footnotes_all_posts_data[$scope_id])) {
58 return '';
59 }
60 $footnotes_used = array();
61 if (isset($modern_footnotes_all_posts_data[$scope_id]['footnotes_previously_used'])) {
62 foreach ($modern_footnotes_all_posts_data[$scope_id]['footnotes_previously_used'] as $f) {
63 $footnotes_used[] = $f;
64 }
65 }
66 $footnotes_used[] = $modern_footnotes_all_posts_data[$scope_id]['footnotes'];
67
68 $content = '';
69 if ($for_rss_feed) {
70 $content .= '<b>Footnotes</b>';
71 foreach ($footnotes_used as $footnote_list) {
72 foreach($footnote_list as $display_number => $footnote_content) {
73 $content .= '<div>';
74 $content .= $display_number;
75 $content .= '&nbsp;&nbsp;&nbsp;&nbsp;';
76 $content .= $footnote_content;
77 $content .= '</div>';
78 }
79 }
80 }
81 else {
82 $content .= '<ul class="modern-footnotes-list ' .
83 ($show_only_when_printing ? 'modern-footnotes-list--show-only-for-print' : '') .
84 ($hide_when_printing ? 'modern-footnotes-list--hide-for-print' : '')
85 . '">';
86 foreach ($footnotes_used as $footnote_list) {
87 foreach($footnote_list as $display_number => $footnote_content) {
88 $content .= '<li>';
89 $content .= '<span>' . $display_number . '</span>';
90 $content .= '<div>';
91 $content .= $footnote_content;
92 $content .= '</div>';
93 $content .= '</li>';
94 }
95 }
96 $content .= '</ul>';
97 }
98 return $content;
99 }
100
101 function modern_footnotes_list_func($atts=[], $content = "") {
102 modern_footnotes_enqueue_scripts_styles_if_not_already_enqueued();
103 return '[mfn_list_execute_after_content_processed]';
104 }
105
106 function modern_footnotes_rss_func($atts, $content = "") {
107 if (!is_array($atts)) {
108 $atts = [];
109 }
110 $atts['for_rss_feed'] = TRUE;
111 return modern_footnotes_func($atts,$content);
112 }
113
114 function modern_footnotes_func($atts, $content = "") {
115
116 global $modern_footnotes_all_posts_data, $modern_footnotes_options;
117
118 modern_footnotes_enqueue_scripts_styles_if_not_already_enqueued();
119
120 $additional_classes = '';
121 if (
122 (isset($modern_footnotes_options['desktop_footnote_behavior']) && $modern_footnotes_options['desktop_footnote_behavior'] == 'expandable')
123 /* legacy option use_expandable_footnotes_on_desktop_instead_of_tooltips - should not be set in modern footnotes 1.4.5+ */
124 || (
125 !isset($modern_footnotes_options['desktop_footnote_behavior']) && isset($modern_footnotes_options['use_expandable_footnotes_on_desktop_instead_of_tooltips']) && $modern_footnotes_options['use_expandable_footnotes_on_desktop_instead_of_tooltips']
126 )
127 ) {
128 $additional_classes = 'modern-footnotes-footnote--expands-on-desktop';
129 } else if (isset($modern_footnotes_options['desktop_footnote_behavior']) && $modern_footnotes_options['desktop_footnote_behavior'] == 'tooltip_hover') {
130 $additional_classes = 'modern-footnotes-footnote--hover-on-desktop';
131 }
132
133 // $scope_id will have a unique value for each post on the page -- this helps handle when a post is
134 // nested inside another post, as can happen with the Display Posts plugin
135 $scope_id = modern_footnotes_get_post_scope_id();
136
137 $additional_attributes = '';
138
139 if (isset($atts['referencereset']) && $atts['referencereset'] == 'true') {
140 if (isset($modern_footnotes_all_posts_data[$scope_id])) {
141 $modern_footnotes_all_posts_data[$scope_id]['used_reference_numbers'] = array();
142 $additional_attributes .= ' data-mfn-reset';
143 // store the content of previously used footnotes, in case we are reusing a reference number and we
144 // are also using a list of footnotes.
145 if (!isset($modern_footnotes_all_posts_data[$scope_id]['footnotes_previously_used'])) {
146 $modern_footnotes_all_posts_data[$scope_id]['footnotes_previously_used'] = array($modern_footnotes_all_posts_data[$scope_id]['footnotes']);
147 } else {
148 $modern_footnotes_all_posts_data[$scope_id]['footnotes_previously_used'][] = $modern_footnotes_all_posts_data[$scope_id]['footnotes'];
149 }
150 $modern_footnotes_all_posts_data[$scope_id]['footnotes'] = array();
151 }
152 }
153
154 if (isset($atts['referencenumber'])) {
155 $display_number = $atts['referencenumber'];
156 $additional_attributes = 'refnum="' . $display_number . '"';
157 } else if (!isset($modern_footnotes_all_posts_data[$scope_id]) || count($modern_footnotes_all_posts_data[$scope_id]['used_reference_numbers']) == 0) {
158 $display_number = 1;
159 } else {
160 $display_number = max($modern_footnotes_all_posts_data[$scope_id]['used_reference_numbers']) + 1;
161 }
162
163 $content = do_shortcode($content); // render out any shortcodes within the contents
164
165 $content = str_replace('<p>','', $content);
166 $content = str_replace('</p>','<br /><br />', $content);
167
168 if (!isset($modern_footnotes_all_posts_data[$scope_id])) {
169 $modern_footnotes_all_posts_data[$scope_id] = array(
170 'modern_footnotes_post_number' => $GLOBALS['current_modern_footnotes_post_number'],
171 'used_reference_numbers' => array($display_number),
172 'footnotes' => array(
173 $display_number => $content
174 )
175 );
176 $GLOBALS['current_modern_footnotes_post_number']++;
177 } else {
178 $modern_footnotes_all_posts_data[$scope_id]['used_reference_numbers'][] = $display_number;
179 $modern_footnotes_all_posts_data[$scope_id]['footnotes'][$display_number] = $content;
180 }
181
182 if (isset($atts['for_rss_feed']) && $atts['for_rss_feed']) {
183 $content = '<sup class="modern-footnotes-footnote ' . $additional_classes . '">' . $display_number . '</sup>'; // only display the superscript for RSS feeds
184 } else {
185 $content = '<sup class="modern-footnotes-footnote ' . $additional_classes . '" data-mfn="' . str_replace('"',"\\\"", $display_number) . '" data-mfn-post-scope="' . $scope_id . '">' .
186 '<a href="javascript:void(0)" ' . $additional_attributes . '>' . $display_number . '</a>' .
187 '</sup>' .
188 '<span class="modern-footnotes-footnote__note" tabindex="0" data-mfn="' . str_replace('"',"\\\"", $display_number) . '">' . $content . '</span>'; //use a block element, not an inline element: otherwise, footnotes with line breaks won't display correctly
189 }
190
191 return $content;
192
193
194
195 }
196
197 //if the options are set to do so, list the footnotes at the bottom of the page
198 function modern_footnotes_display_after_content($content) {
199 global $modern_footnotes_options;
200
201 $show_only_when_printing = FALSE;
202 $hide_when_printing = FALSE;
203 if (
204 (!isset($GLOBALS['modern_footnotes_displaying_rss_feed']) || !$GLOBALS['modern_footnotes_displaying_rss_feed']) &&
205 (
206 (isset($modern_footnotes_options['display_footnotes_at_bottom_of_posts']) && $modern_footnotes_options['display_footnotes_at_bottom_of_posts']) ||
207 (isset($modern_footnotes_options['display_footnotes_at_bottom_of_posts_when_printing']) && $modern_footnotes_options['display_footnotes_at_bottom_of_posts_when_printing'])
208 )
209 ) {
210 $options = array();
211 if (isset($modern_footnotes_options['display_footnotes_at_bottom_of_posts_when_printing']) && $modern_footnotes_options['display_footnotes_at_bottom_of_posts_when_printing']) {
212 if (!isset($modern_footnotes_options['display_footnotes_at_bottom_of_posts']) || !$modern_footnotes_options['display_footnotes_at_bottom_of_posts']) {
213 $show_only_when_printing = TRUE;
214 }
215 } else {
216 $hide_when_printing = TRUE;
217 }
218 $content .= modern_footnotes_list_footnotes($show_only_when_printing, $hide_when_printing);
219 }
220
221 return $content;
222 }
223
224 $modern_footnotes_shortcodes = array('modern_footnote','mfn');
225 if (isset($modern_footnotes_options['modern_footnotes_custom_shortcode']) && !empty($modern_footnotes_options['modern_footnotes_custom_shortcode'])) {
226 $modern_footnotes_shortcodes[] = $modern_footnotes_options['modern_footnotes_custom_shortcode'];
227 }
228 foreach ($modern_footnotes_shortcodes as $modern_footnote_shortcode) {
229 add_shortcode($modern_footnote_shortcode, 'modern_footnotes_func');
230 }
231
232 add_shortcode('mfn_list', 'modern_footnotes_list_func');
233
234 add_filter('the_content', 'modern_footnotes_reset_count', 10); // run before shortcodes are processed
235 add_filter('the_content', 'modern_footnotes_display_after_content', 11);
236 add_filter('the_content', 'modern_footnotes_execute_mfn_list_shortcode', 12);
237
238 //reset the footnote counter for every new post
239 function modern_footnotes_reset_count($content) {
240 // if we are loading a scope that has previously been loaded, this is our second time loading the post. Reset the footnotes for the post.
241 $scope = modern_footnotes_get_post_scope_id();
242 if (isset($GLOBALS['modern_footnotes_all_posts_data'][$scope])) {
243 unset($GLOBALS['modern_footnotes_all_posts_data'][$scope]);
244 }
245 return $content;
246 }
247
248 add_action('the_post', 'modern_footnotes_check_post_query',10,2);
249
250 // save the unique queries on the page, so that if a post is contained within another post, we can properly scope the
251 // footnote numbering to that particular post
252 function modern_footnotes_check_post_query($scoped_post, $scoped_query = null) {
253 global $modern_footnotes_active_query;
254 if (isset($scoped_query)) {
255 $modern_footnotes_active_query = $scoped_query;
256 }
257 }
258
259 // return an ID that can be used to identify the unique post that we are in -- used for listing multiple posts on the
260 // same page, including when posts are nested with plugins like DisplayPosts
261 function modern_footnotes_get_post_scope_id() {
262 if (isset($GLOBALS['modern_footnotes_active_query'])) {
263 return spl_object_hash($GLOBALS['modern_footnotes_active_query']) . '_' . $GLOBALS['post']->ID;
264 } else {
265 return 'post_' . $GLOBALS['post']->ID;
266 }
267 }
268
269 // replace <mfn> HTML tags added by Gutenberg/block editor to [mfn] shortcodes
270 // When multiple formats are applied, Gutenberg can have multiple <mfn> tags for one footnote, so we'll have to iterate through the text and group sibling tags together (see https://github.com/seankwilliams/modern-footnotes/issues/14)
271 function modern_footnotes_replace_mfn_tag_with_shortcode( $content ) {
272 $content = str_replace('</mfn>','<mfn>',$content); //using [mfn] instead of [/mfn] is intentional here
273 $content_parts = explode('<mfn>', $content);
274 $content_data = array();
275 //$tagsFromPreviousSegment = array();
276 $inFootnote = FALSE;
277 foreach ($content_parts as $c) {
278 $content_data[] = array(
279 "content" => $c,
280 "inFootnote" => $inFootnote
281 );
282 $inFootnote = !$inFootnote;
283 }
284 $wasInFootnote = FALSE;
285 for ($i = 0; $i < count($content_data); $i++) {
286 //if this is only opening tags or only closing tags, place it in the footnote
287 $replacedString = preg_replace("/<\/?\\w+\\s?\\w?.*?>/ms", "", $content_data[$i]['content']);
288 if (strlen($replacedString) === 0 && !$content_data[$i]['inFootnote'] && $wasInFootnote) { // check $wasInFootnote to fix https://github.com/seankwilliams/modern-footnotes/issues/18
289 $content_data[$i]['inFootnote'] = TRUE;
290 } else {
291 $wasInFootnote = $content_data[$i]['inFootnote'];
292 }
293 }
294 $final_content = '';
295 $inFootnote = FALSE;
296 foreach ($content_data as $cd) {
297 if ($cd['inFootnote'] && !$inFootnote) {
298 $inFootnote = TRUE;
299 $final_content .= '[mfn]';
300 } else if ($inFootnote && !$cd['inFootnote']) {
301 $inFootnote = FALSE;
302 $final_content .= '[/mfn]';
303 }
304
305 $final_content .= $cd['content'];
306 }
307 if ($inFootnote) {
308 $final_content .= '[/mfn]';
309 }
310 return $final_content;
311 }
312 add_filter( 'the_content', 'modern_footnotes_replace_mfn_tag_with_shortcode' );
313
314 // remove <mfn> HTML tags added by Gutenberg/block editor
315 function modern_footnotes_strip_rendered_mfn_tag( $content ) {
316
317 // we will remove all rendered text from the <mfn> tags
318 global $modern_footnotes_all_posts_data;
319 $scope_id = modern_footnotes_get_post_scope_id();
320 if (empty($modern_footnotes_all_posts_data[$scope_id])) {
321 return $content;
322 }
323 $footnotes_used = array();
324 if (isset($modern_footnotes_all_posts_data[$scope_id]['footnotes_previously_used'])) {
325 foreach ($modern_footnotes_all_posts_data[$scope_id]['footnotes_previously_used'] as $f) {
326 $footnotes_used[] = $f;
327 }
328 }
329 $footnotes_used[] = $modern_footnotes_all_posts_data[$scope_id]['footnotes'];
330
331 foreach ($footnotes_used as $footnote_list) {
332 foreach($footnote_list as $display_number => $footnote_content) {
333 if (!empty($footnote_content)) { //ensure footnote_content is not empty: otherwise, we may be replacing just a number, which is far too common
334 $content = str_replace($display_number . wp_strip_all_tags($footnote_content), '', $content);
335 }
336 }
337 }
338
339 return $content;
340
341 }
342 add_filter( 'wp_trim_words', 'modern_footnotes_strip_rendered_mfn_tag'); // use this filter so that <mfn> HTML tags added through gutenberg are removed in wp_trim_excerpt -- in wp_trim_excerpt, strip_shortcodes runs AFTER the_content filters do
343
344
345
346 function modern_footnotes_register_scripts_styles() {
347 global $modern_footnotes_options, $modern_footnotes_shortcodes, $modern_footnotes_version, $post;
348 wp_register_style('modern_footnotes', plugin_dir_url(__FILE__) . 'styles.min.css', array(), $modern_footnotes_version);
349 wp_register_script('modern_footnotes', plugin_dir_url(__FILE__) . 'modern-footnotes.min.js', array('jquery'), $modern_footnotes_version, TRUE);
350
351 if (!is_admin() && isset($modern_footnotes_options['modern_footnotes_custom_css']) && !empty($modern_footnotes_options['modern_footnotes_custom_css'])) {
352 wp_add_inline_style( 'modern_footnotes', $modern_footnotes_options['modern_footnotes_custom_css'] );
353 }
354
355 // if we are in a post, and the post uses the shortcode, enqueue the style + script
356 // this is not foolproof since the shortcode could be used in other ways (like post metadata), so we
357 // will have to check when rendering the shortcodes to ensure that the scripts/styles are enqueued
358 if (is_a( $post, 'WP_Post' )) {
359 $has_shortcode = FALSE;
360 foreach ($modern_footnotes_shortcodes as $modern_footnote_shortcode) {
361 if (has_shortcode($post->post_content, $modern_footnote_shortcode)) {
362 $has_shortcode = TRUE;
363 }
364 }
365 if (has_shortcode($post->post_content, 'mfn_list')) {
366 $has_shortcode = TRUE;
367 }
368 if ($has_shortcode) {
369 wp_enqueue_style('modern_footnotes');
370 wp_enqueue_script('modern_footnotes');
371 }
372 }
373 }
374
375 add_action('wp_enqueue_scripts', 'modern_footnotes_register_scripts_styles');
376
377 function modern_footnotes_enqueue_scripts_styles_if_not_already_enqueued() {
378 if (!wp_style_is('modern_footnotes')) {
379 wp_enqueue_style('modern_footnotes');
380 }
381 if (!wp_script_is('modern_footnotes')) {
382 wp_enqueue_script('modern_footnotes');
383 }
384 }
385
386 //
387 //modify the admin
388 //
389
390 //create a settings page
391 function modern_footnotes_menu() {
392 add_options_page( __('Modern Footnotes Settings', 'modern-footnotes'),
393 __('Modern Footnotes','modern-footnotes'),
394 'manage_options', __FILE__, 'modern_footnotes_options' );
395 }
396
397 function modern_footnotes_options() {
398 if ( !current_user_can( 'manage_options' ) ) {
399 wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
400 }
401 echo '<div class="wrap">';
402 echo '<h1>' . esc_html__('Modern Footnotes Settings','modern-footnotes') . '</h1>';
403 echo '<form method="post" action="options.php">';
404 settings_fields('modern_footnotes_settings');
405 do_settings_sections(__FILE__);
406 submit_button();
407 echo '</form>';
408 echo '</div>';
409 }
410
411 function modern_footnotes_register_settings() { // whitelist options
412 register_setting('modern_footnotes_settings', 'modern_footnotes_settings',
413 array(
414 'type' => 'boolean',
415 'default' => FALSE,
416 'sanitize_callback' => 'modern_footnotes_sanitize_callback'
417 ));
418 add_settings_section(
419 'modern_footnotes_option_group_section',
420 __('Modern Footnotes Settings', 'modern-footnotes'),
421 function() { /* do nothing, no HTML needed for section heading */ },
422 __FILE__
423 );
424
425 add_settings_field(
426 'modern_footnotes_desktop_footnote_behavior',
427 __('Desktop footnote behavior', 'modern-footnotes'),
428 'modern_footnotes_desktop_footnote_behavior_dropdown_callback',
429 __FILE__,
430 'modern_footnotes_option_group_section'
431 );
432
433 add_settings_field(
434 'display_footnotes_at_bottom_of_posts',
435 __('Display footnote list at bottom of posts', 'modern-footnotes'),
436 'modern_footnotes_checkbox_element_callback',
437 __FILE__,
438 'modern_footnotes_option_group_section',
439 array(
440 'property_name' => 'display_footnotes_at_bottom_of_posts',
441 'property_label' => 'Display footnote list at bottom of posts'
442 )
443 );
444 add_settings_field(
445 'display_footnotes_at_bottom_of_posts_when_printing',
446 __('When printing, list footnotes at the bottom of posts', 'modern-footnotes'),
447 'modern_footnotes_checkbox_element_callback',
448 __FILE__,
449 'modern_footnotes_option_group_section',
450 array(
451 'property_name' => 'display_footnotes_at_bottom_of_posts_when_printing',
452 'property_label' => 'When printing, list footnotes at the bottom of posts'
453 )
454 );
455
456 add_settings_field(
457 'modern_footnotes_include_footnote_list_at_end_of_rss_content',
458 __('For post content in RSS feeds, list footnotes at the bottom of posts', 'modern-footnotes'),
459 'modern_footnotes_checkbox_element_callback',
460 __FILE__,
461 'modern_footnotes_option_group_section',
462 array(
463 'property_name' => 'modern_footnotes_include_footnote_list_at_end_of_rss_content',
464 'property_label' => 'For post content in RSS feeds, list footnotes at the bottom of posts'
465 )
466 );
467
468 add_settings_field(
469 'modern_footnotes_custom_css',
470 __('Modern Footnotes Custom CSS', 'modern-footnotes'),
471 'modern_footnotes_custom_css_element_callback',
472 __FILE__,
473 'modern_footnotes_option_group_section'
474 );
475 add_settings_field(
476 'modern_footnotes_custom_shortcode',
477 __('Modern Footnotes Custom Shortcode', 'modern-footnotes'),
478 'modern_footnotes_custom_shortcode_element_callback',
479 __FILE__,
480 'modern_footnotes_option_group_section'
481 );
482 }
483
484 function modern_footnotes_sanitize_callback($plugin_options) {
485 global $modern_footnotes_options;
486
487 if (isset($plugin_options['modern_footnotes_custom_css']) && !empty($plugin_options['modern_footnotes_custom_css'])) {
488 //strip style HTML tags from the custom CSS property
489 $plugin_options['modern_footnotes_custom_css'] = preg_replace('/<\/?style.*?>/i', '', $plugin_options['modern_footnotes_custom_css']);
490 }
491
492 if (isset($plugin_options['modern_footnotes_custom_shortcode']) && !empty($plugin_options['modern_footnotes_custom_shortcode'])) {
493 //remove invalid characters from shortcode
494 $plugin_options['modern_footnotes_custom_shortcode'] = preg_replace('/[^a-zA-Z0-9-_]/i', '', $plugin_options['modern_footnotes_custom_shortcode']);
495 if ((!isset($modern_footnotes_options['modern_footnotes_custom_shortcode']) || $modern_footnotes_options['modern_footnotes_custom_shortcode'] != $plugin_options['modern_footnotes_custom_shortcode']) &&
496 shortcode_exists($plugin_options['modern_footnotes_custom_shortcode'])) {
497 add_settings_error( 'modern_footnotes_custom_shortcode', 'shortcode-in-use', 'The shortcode "' . $plugin_options['modern_footnotes_custom_shortcode'] . '" is already in use, please enter a different one' );
498 $plugin_options['modern_footnotes_custom_shortcode'] = '';
499 }
500 }
501 return $plugin_options;
502 }
503
504 function modern_footnotes_checkbox_element_callback($args) {
505 global $modern_footnotes_options;
506
507 $property_name = $args['property_name'];
508 $property_label = $args['property_label'];
509
510 $html = '<input type="checkbox" id="%1$s" name="modern_footnotes_settings[%1$s]" value="1"' . checked( 1, isset($modern_footnotes_options[$property_name]) && $modern_footnotes_options[$property_name], FALSE ) . '/>';
511 $html .= '<label for="%1$s">' .
512 esc_html__($property_label, 'modern-footnotes') .
513 '</label>';
514 $html = sprintf($html, $property_name);
515
516 echo $html;
517 }
518
519 function modern_footnotes_desktop_footnote_behavior_dropdown_callback() {
520 global $modern_footnotes_options;
521
522 $selected_value = isset($modern_footnotes_options['desktop_footnote_behavior']) ? $modern_footnotes_options['desktop_footnote_behavior'] : '';
523
524 $options = array(
525 'tooltip_click' => __('Tooltip footnotes that open on click', 'modern-footnotes'),
526 'tooltip_hover' => __('Tooltip footnotes that open on hover', 'modern-footnotes'),
527 'expandable' => __('Expandable footnotes', 'modern-footnotes'),
528 );
529
530 $html = '<select id="modern_footnotes_desktop_footnote_behavior" name="modern_footnotes_settings[desktop_footnote_behavior]"> aria-label="%1$s"';
531 foreach ($options as $key => $value) {
532 $option_html = '<option value="%s" %s>%s</option>';
533 $html .= sprintf($option_html, $key, $selected_value == $key ? 'selected' : '', $value);
534 }
535 $html .= '</select>';
536
537 $html = sprintf($html, __('Desktop footnote behavior', 'modern-footnotes'));
538
539 echo $html;
540 }
541
542 function modern_footnotes_custom_css_element_callback() {
543 global $modern_footnotes_options;
544
545 $html = '<textarea id="modern_footnotes_custom_css" name="modern_footnotes_settings[modern_footnotes_custom_css]" style="max-width:100%;width:400px;height:200px">' . (isset($modern_footnotes_options['modern_footnotes_custom_css']) ? $modern_footnotes_options['modern_footnotes_custom_css'] : '') . '</textarea>';
546 $html .= '<label for="modern_footnotes_custom_css">' .
547 esc_html__('Enter any custom CSS for the plugin, without any <style> tags.', 'modern-footnotes') .
548 '</label>';
549
550 echo $html;
551 }
552
553 function modern_footnotes_custom_shortcode_element_callback() {
554 global $modern_footnotes_options;
555
556 $html = '<input type="text" id="modern_footnotes_custom_shortcode" name="modern_footnotes_settings[modern_footnotes_custom_shortcode]" value="' . (isset($modern_footnotes_options['modern_footnotes_custom_shortcode']) ? $modern_footnotes_options['modern_footnotes_custom_shortcode'] : '') . '" />';
557 $html .= '<label for="modern_footnotes_custom_shortcode">' .
558 esc_html__('Custom shortcode if you\'d like to use something other than [mfn] or [modern_footnote]. Enter the shortcode without the brackets.', 'modern-footnotes') .
559 '</label>';
560
561 echo $html;
562 }
563
564 function modern_footnotes_return_blank_for_rss_func($atts, $content = "") {
565 return "";
566 }
567
568 // remove shortcode from RSS feed
569 function modern_footnotes_remove_from_rss_content_feed($content) {
570 return modern_footnotes_remove_from_rss_feed($content, TRUE);
571 }
572 function modern_footnotes_remove_from_rss_feed($content, $is_content_section = FALSE){
573 foreach ($GLOBALS['modern_footnotes_shortcodes'] as $modern_footnote_shortcode) {
574 remove_shortcode($modern_footnote_shortcode);
575 if ($GLOBALS['modern_footnotes_options']['modern_footnotes_include_footnote_list_at_end_of_rss_content']) {
576 add_shortcode($modern_footnote_shortcode, 'modern_footnotes_rss_func');
577 } else {
578 add_shortcode($modern_footnote_shortcode, 'modern_footnotes_return_blank_for_rss_func');
579 }
580 }
581 // do not let the [mfn_list] shortcode execute in the RSS feed
582 remove_shortcode('mfn_list');
583 add_shortcode('mfn_list', 'modern_footnotes_return_blank_for_rss_func');
584 // add a [mfn_rss_list] shortcode to the end of the post content
585 if ($GLOBALS['modern_footnotes_options']['modern_footnotes_include_footnote_list_at_end_of_rss_content'] && $is_content_section) {
586 $content .= modern_footnotes_list_footnotes(FALSE,FALSE,TRUE);
587 }
588
589 return $content;
590 }
591 add_filter('the_excerpt_rss', 'modern_footnotes_remove_from_rss_feed');
592 add_filter('the_content_feed', 'modern_footnotes_remove_from_rss_content_feed');
593
594 // set variable to let us know we are in an rss feed
595 function modern_footnotes_in_rss() {
596 $GLOBALS['modern_footnotes_displaying_rss_feed'] = TRUE;
597 }
598 add_action('rss_head', 'modern_footnotes_in_rss'); // for RSS 1
599 add_action('rss_tag_pre', 'modern_footnotes_in_rss'); //for all other feed types
600
601
602 if (is_admin()) { // admin actions
603 add_action( 'admin_menu', 'modern_footnotes_menu' );
604 add_action( 'admin_init', 'modern_footnotes_register_settings' );
605 }
606
607 //setup button on the WordPress editor
608
609 //
610 // Pre-Gutenberg editor
611 //
612 function modern_footnotes_add_container_button() {
613 if ( ! current_user_can('edit_posts') && ! current_user_can('edit_pages') )
614 return;
615 if ( get_user_option('rich_editing') == 'true') {
616 add_filter('mce_external_plugins', 'modern_footnotes_add_container_plugin');
617 add_filter('mce_buttons', 'modern_footnotes_register_container_button');
618 }
619 }
620 if (is_admin()) {
621 add_filter('init', 'modern_footnotes_add_container_button');
622
623 function modern_footnotes_enqueue_admin_scripts() {
624 global $modern_footnotes_version;
625 wp_enqueue_style('modern_footnotes', plugin_dir_url(__FILE__) . 'styles.mce-button.min.css', array(), $modern_footnotes_version);
626 }
627
628 add_action('admin_enqueue_scripts', 'modern_footnotes_enqueue_admin_scripts');
629 }
630
631
632 function modern_footnotes_register_container_button($buttons) {
633 array_push($buttons, "modern_footnotes");
634 return $buttons;
635 }
636
637 function modern_footnotes_add_container_plugin($plugin_array) {
638 $plugin_array['modern_footnotes'] = plugin_dir_url(__FILE__) . 'modern-footnotes.mce-button.min.js';
639 return $plugin_array;
640 }
641 //
642 // End Pre-Gutenberg editor
643 //
644
645 //
646 // Gutenberg / Block Editor
647 //
648 function modern_footnotes_block_editor_button() {
649 global $modern_footnotes_version;
650 wp_enqueue_script( 'modern_footnotes_block_editor_js',
651 plugin_dir_url(__FILE__) . 'modern-footnotes.block-editor.min.js',
652 array( 'wp-rich-text', 'wp-element', 'wp-editor', 'wp-i18n' ),
653 $modern_footnotes_version
654 );
655 wp_set_script_translations('modern_footnotes_block_editor_js','modern-footnotes');
656 wp_enqueue_style('modern_footnotes_block_editor_css', plugin_dir_url(__FILE__) . 'styles.block-editor-button.min.css', array(), $modern_footnotes_version);
657
658 }
659 add_action( 'enqueue_block_editor_assets', 'modern_footnotes_block_editor_button' );
660 //
661 // End Gutenberg / Block Editor
662 //
663