PluginProbe
Easy Footnotes / trunk
Easy Footnotes vtrunk
trunk 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.2 All 32 releases
← All changes | easy-footnotes.php +256 -84 1.0.13trunk View file →
@@ -1,61 +1,111 @@
1 1 <?php
2 2 /**
3 3 * Plugin Name: Easy Footnotes
4 - * Plugin URI: http://jasonyingling.me/easy-footnotes-wordpress/
4 + * Plugin URI: https://jasonyingling.me/easy-footnotes-wordpress/
5 5 * Description: Easily add footnotes to your posts with a simple shortcode.
6 - * Version: 1.0.13
6 + * Text Domain: easy-footnotes
7 + * Version: 1.1.14
7 8 * Author: Jason Yingling
8 - * Author URI: http://jasonyingling.me
9 + * Author URI: https://jasonyingling.me
9 10 * License: GPL2
11 + *
12 + * @package easy-footnotes
10 13 */
11 14
12 - /* Copyright 2017 Jason Yingling (email : yingling017@gmail.com)
15 +/*
16 + Copyright 2018 Jason Yingling (email : yingling017@gmail.com)
13 17
14 - This program is free software; you can redistribute it and/or modify
15 - it under the terms of the GNU General Public License, version 2, as
16 - published by the Free Software Foundation.
18 + This program is free software; you can redistribute it and/or modify
19 + it under the terms of the GNU General Public License, version 2, as
20 + published by the Free Software Foundation.
17 21
18 - This program is distributed in the hope that it will be useful,
19 - but WITHOUT ANY WARRANTY; without even the implied warranty of
20 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 - GNU General Public License for more details.
22 + This program is distributed in the hope that it will be useful,
23 + but WITHOUT ANY WARRANTY; without even the implied warranty of
24 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 + GNU General Public License for more details.
22 26
23 - You should have received a copy of the GNU General Public License
24 - along with this program; if not, write to the Free Software
25 - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 + You should have received a copy of the GNU General Public License
28 + along with this program; if not, write to the Free Software
29 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 30 */
27 -
31 +/**
32 + * The Easy Footnotes class. In camel case. Because I didn't follow WPCS way back when.
33 + */
28 34 class easyFootnotes {
29 35
30 - // Add label option using add_option if it does not already exist
31 - public $footnotes = array();
36 + /**
37 + * Add label option using add_option if it does not already exist.
38 + *
39 + * @var array $footnotes An array for the footnotes to be stored.
40 + */
41 + public $footnotes = array();
32 42 public $footnoteCount = 0;
33 43 public $prevPost;
44 + public $footnoteOptions;
45 + public $footnoteLookup = array();
46 + public $usedFootnoteNumbers = array();
34 47
48 + private $footnoteSettings;
49 +
50 + private $version = '1.1.14';
51 +
52 + /**
53 + * Constructing the initial plugin options, shortcodes, and hooks.
54 + */
35 55 public function __construct() {
36 - $footnoteSettings = array(
37 - 'footnoteLabel' => 'Footnotes',
38 - 'useLabel' => false,
56 + $this->footnoteSettings = array(
57 + 'footnoteLabel' => 'Footnotes',
58 + 'useLabel' => false,
59 + 'hide_easy_footnote_after_posts' => false,
60 + 'show_easy_footnote_on_front' => false,
61 + 'reset_footnotes' => false,
62 + 'combine_duplicate_footnotes' => false,
39 63 );
40 64
41 - add_option('easy_footnotes_options', $footnoteSettings);
42 - add_shortcode( 'note', array($this, 'easy_footnote_shortcode') );
43 - add_filter('the_content', array($this, 'easy_footnote_after_content'), 20);
44 - add_action('wp_enqueue_scripts', array($this, 'register_qtip_scripts'));
45 - add_action('admin_menu', array($this, 'easy_footnotes_admin_actions'));
46 - add_action( 'admin_enqueue_scripts', array($this, 'easy_footnotes_admin_scripts') );
65 + add_option( 'easy_footnotes_options', $this->footnoteSettings );
66 + add_shortcode( 'note', array( $this, 'easy_footnote_shortcode' ) );
67 + add_shortcode( 'efn_note', array( $this, 'easy_footnote_shortcode' ) );
68 + add_shortcode( 'efn_reset', array( $this, 'short_code_reset' ) );
69 + add_filter( 'the_content', array( $this, 'easy_footnote_after_content' ), 20 );
70 +
71 + $this->footnoteOptions = get_option( 'easy_footnotes_options' );
72 + if ( isset( $this->footnoteOptions['reset_footnotes'] ) && $this->footnoteOptions['reset_footnotes'] || ( ! isset( $this->footnoteOptions[ 'combine_duplicate_footnotes' ] ) || $this->footnoteOptions[ 'combine_duplicate_footnotes' ] === false ) ) {
73 + add_filter( 'the_content', array( $this, 'easy_footnote_reset' ), 999 );
74 + }
75 +
76 + add_action( 'wp_enqueue_scripts', array( $this, 'register_qtip_scripts' ) );
77 + add_action( 'admin_menu', array( $this, 'easy_footnotes_admin_actions' ) );
78 + add_action( 'admin_enqueue_scripts', array( $this, 'easy_footnotes_admin_scripts' ) );
79 + add_action( 'init', array($this, 'efn_load_textdomain') );
80 +
81 + $this->footnoteOptions = get_option( 'easy_footnotes_options' );
47 82 }
48 83
84 + /**
85 + * Registering the scripts and styles used by jQuery qTip.
86 + */
49 87 public function register_qtip_scripts() {
50 - wp_register_script( 'imagesloaded', plugins_url( '/assets/qtip/imagesloaded.pkgd.min.js' , __FILE__ ), null, false, true );
51 - wp_register_script( 'qtip', plugins_url( '/assets/qtip/jquery.qtip.min.js' , __FILE__ ), array('jquery', 'imagesloaded'), false, true );
52 - wp_register_script( 'qtipcall', plugins_url( '/assets/qtip/jquery.qtipcall.js' , __FILE__ ), array('jquery', 'qtip'), false, true );
53 - wp_register_style( 'qtipstyles', plugins_url( '/assets/qtip/jquery.qtip.min.css' , __FILE__ ), null, false, false );
54 - wp_register_style( 'easyfootnotescss', plugins_url( '/assets/easy-footnotes.css' , __FILE__ ), null, false, false );
88 + wp_register_script( 'imagesloaded', plugins_url( '/assets/qtip/imagesloaded.pkgd.min.js', __FILE__ ), array(), $this->version, true );
89 + wp_register_script( 'qtip', plugins_url( '/assets/qtip/jquery.qtip.min.js', __FILE__ ), array( 'jquery', 'imagesloaded' ), $this->version, true );
90 + wp_register_script( 'qtipcall', plugins_url( '/assets/qtip/jquery.qtipcall.js', __FILE__ ), array( 'jquery', 'qtip' ), $this->version, true );
91 + wp_register_style( 'qtipstyles', plugins_url( '/assets/qtip/jquery.qtip.min.css', __FILE__ ), array(), $this->version, false );
92 + wp_register_style( 'easyfootnotescss', plugins_url( '/assets/easy-footnotes.css', __FILE__ ), array(), $this->version, false );
55 93 }
56 94
57 - public function easy_footnote_shortcode($atts, $content = null) {
95 + /**
96 + * Create the Easy Footnotes shortcode.
97 + *
98 + * @param array $atts Shortcode attributes.
99 + * @param string $content Content within the shortcode.
100 + */
101 + public function easy_footnote_shortcode( $atts, $content = null ) {
102 + if ( isset( $this->footnoteOptions['show_easy_footnote_on_front'] ) && $this->footnoteOptions['show_easy_footnote_on_front'] ) {
103 + $efn_show_on_front = is_front_page();
104 + } else {
105 + $efn_show_on_front = false;
106 + }
107 +
58 108 wp_enqueue_style( 'qtipstyles' );
59 109 wp_enqueue_style( 'easyfootnotescss' );
60 110 wp_enqueue_script( 'imagesloaded' );
61 111 wp_enqueue_script( 'qtip' );
@@ -61,100 +111,222 @@
61 111 wp_enqueue_script( 'qtip' );
62 112 wp_enqueue_script( 'qtipcall' );
63 113 wp_enqueue_style( 'dashicons' );
64 114
65 - extract (shortcode_atts(array(
66 - ), $atts));
115 + // Accept optional custom number attribute
116 + $atts = shortcode_atts(
117 + array(
118 + 'num' => null
119 + ),
120 + $atts
121 + );
67 122
68 - // Get an array of all of the footnotes
69 - $pattern = '/\[note\](.*?)\[\/note\]/';
70 - preg_match_all( $pattern, get_the_content( get_the_ID() ), $shortcodes );
123 + $post_id = get_the_ID();
71 124
72 - // If the current content matches the first [note] set the count to 0. This prevents extra counting by themes using the_content
73 - if ( isset( $shortcodes[1][0] ) && $content === $shortcodes[1][0] ) {
74 - $count = 0;
75 - } else {
76 - $count = $this->footnoteCount;
125 + $content = do_shortcode( $content );
126 +
127 + $content_id = md5( preg_replace("/[^A-Za-z0-9 ]/", '', wp_strip_all_tags( html_entity_decode( $content ) ) ) );
128 +
129 + if ( isset( $this->footnoteOptions[ 'combine_duplicate_footnotes' ] ) && $this->footnoteOptions[ 'combine_duplicate_footnotes' ] === true ) {
130 + /**
131 + * Search for existing footnote for removing duplicate
132 + * Also add the same numbers to duplicate footnotes
133 + */
134 + if (!isset($this->usedFootnoteNumbers) ) {
135 + $this->usedFootnoteNumbers = array();
136 + }
137 + if (!isset($this->footnoteLookup)) {
138 + $this->footnoteLookup = array();
139 + }
77 140 }
78 141
79 - // Increment the counter
80 - $count++;
81 142
82 - // Set the footnoteCount (This whole process needs reworked)
83 - $this->footnoteCount = $count;
84 -
85 - //$this->easy_footnote_count($this->footnoteCount, get_the_ID());
86 - $this->easy_footnote_content($content);
87 -
88 - if (is_singular() && is_main_query()) {
89 - $footnoteLink = '#easy-footnote-bottom-'.$this->footnoteCount;
143 + // If a custom number is provided, use that number and mark it as used
144 + if ( ! empty( $atts['num'] ) ) {
145 + $footnote_number = intval( $atts['num'] );
146 + $this->usedFootnoteNumbers[] = $footnote_number; // Track custom number
147 + $this->footnoteLookup[$content_id] = $footnote_number;
148 + $this->footnotes[$footnote_number] = $content;
149 + } elseif ( isset( $this->footnoteLookup[$content_id] ) ) {
150 + if ( isset( $this->footnoteOptions[ 'combine_duplicate_footnotes' ] ) && $this->footnoteOptions[ 'combine_duplicate_footnotes' ] === true ) {
151 + // Use existing footnote number for duplicate content
152 + $footnote_number = $this->footnoteLookup[$content_id];
153 + } else {
154 + $this->footnoteCount++;
155 + $footnote_number = $this->footnoteCount;
156 + $this->footnotes[$footnote_number] = $content;
157 + }
90 158 } else {
91 - $footnoteLink = get_permalink(get_the_ID()).'#easy-footnote-bottom-'.$this->footnoteCount;
159 + // Auto-increment for new footnotes, skipping used numbers
160 + do {
161 + $this->footnoteCount++;
162 + } while ( in_array( $this->footnoteCount, $this->usedFootnoteNumbers ) );
163 +
164 + $footnote_number = $this->footnoteCount;
165 + $this->footnoteLookup[$content_id] = $footnote_number;
166 + $this->usedFootnoteNumbers[] = $footnote_number; // Mark as used
167 + $this->footnotes[$footnote_number] = $content;
92 168 }
93 169
94 - $footnoteContent = "<span id='easy-footnote-".esc_attr($this->footnoteCount)."' class='easy-footnote-margin-adjust'></span><span class='easy-footnote'><a href='".esc_url($footnoteLink)."' title='".htmlspecialchars($content, ENT_QUOTES)."'><sup>".esc_html($this->footnoteCount)."</sup></a></span>";
95 -
170 + // Generate the correct footnote link with the correct number
171 + $footnoteLink = (is_singular() || $efn_show_on_front) && is_main_query()
172 + ? '#easy-footnote-bottom-' . $footnote_number . '-' . $post_id
173 + : get_permalink($post_id) . '#easy-footnote-bottom-' . $footnote_number . '-' . $post_id;
174 +
175 + // Now generate the footnote markup with the correct number and link
176 + $footnoteContent = "<span id='easy-footnote-" . esc_attr($footnote_number) . '-' . $post_id
177 + . "' class='easy-footnote-margin-adjust'></span><span class='easy-footnote'>"
178 + . "<a href='" . esc_url($footnoteLink) . "' title='" . htmlspecialchars($content, ENT_QUOTES)
179 + . "'><sup>" . esc_html($footnote_number) . "</sup></a></span>";
180 +
96 181 return $footnoteContent;
97 182 }
98 183
99 - public function easy_footnote_content($content) {
100 - $this->footnotes[$this->footnoteCount] = $content;
184 + /**
185 + * The content of a particular footnote.
186 + *
187 + * @param string $content The content from a particular call of the shortcode.
188 + */
189 + public function easy_footnote_content( $content ) {
190 + $this->footnotes[ $this->footnoteCount ] = $content;
101 191
102 192 return $this->footnotes;
103 193 }
104 194
105 - public function easy_footnote_count($count, $currentPost) {
106 - if ($this->prevPost != $currentPost) {
107 - $count = 0;
195 + /**
196 + * Display the list of footnotes after the post content.
197 + *
198 + * @param string $content The content of the current post.
199 + */
200 + public function easy_footnote_after_content( $content ) {
201 + if ( isset( $this->footnoteOptions['hide_easy_footnote_after_posts'] ) && $this->footnoteOptions['hide_easy_footnote_after_posts'] ) {
202 + return $content;
108 203 }
109 204
110 - $this->prevPost = $currentPost;
205 + if ( isset( $this->footnoteOptions['show_easy_footnote_on_front'] ) && $this->footnoteOptions['show_easy_footnote_on_front'] ) {
206 + $efn_show_on_front = is_front_page() || is_home();
207 + } else {
208 + $efn_show_on_front = false;
209 + }
111 210
112 - $count++;
211 + if ( ( is_singular() || $efn_show_on_front ) && is_main_query() ) {
212 + $footnotesInsert = $this->footnotes;
113 213
114 - $this->footnoteCount = $count;
214 + $footnoteCopy = '';
215 + $efn_output = '';
115 216
116 - return $this->footnoteCount;
117 - }
217 + $useLabel = isset( $this->footnoteOptions['useLabel'] ) ? $this->footnoteOptions['useLabel'] : false;
218 + $efLabel = isset($this->footnoteOptions['footnoteLabel'] ) ? $this->footnoteOptions['footnoteLabel'] : __( 'Footnotes', 'easy-footnotes' );
118 219
119 - public function easy_footnote_after_content($content) {
120 - if (is_singular() && is_main_query()) {
121 - $footnotesInsert = $this->footnotes;
220 + $post_id = get_the_ID();
122 221
123 - $footnoteCopy = '';
222 + // Create a new array to track used footnotes and their numbers
223 + $footnote_number = 1;
124 224
125 - $footnoteOptions = get_option('easy_footnotes_options');
126 - $useLabel = $footnoteOptions['useLabel'];
127 - $efLabel = $footnoteOptions['footnoteLabel'];
225 + // sort footnotes according to numbers
226 + ksort($footnotesInsert);
128 227
129 - foreach ($footnotesInsert as $count => $footnote) {
130 - $footnoteCopy .= '<li class="easy-footnote-single"><span id="easy-footnote-bottom-'.esc_attr($count).'" class="easy-footnote-margin-adjust"></span>'.wp_kses_post($footnote).'<a class="easy-footnote-to-top" href="'.esc_url('#easy-footnote-'.$count).'"></a></li>';
228 + foreach ( $footnotesInsert as $count => $footnote ) {
229 +
230 + if ( isset( $this->footnoteOptions[ 'combine_duplicate_footnotes' ] ) && $this->footnoteOptions[ 'combine_duplicate_footnotes' ] === true ) {
231 + // If the footnote is already in the lookup, use its number
232 + if ( isset( $this->footnoteLookup[$footnote] ) ) {
233 + $count = $this->footnoteLookup[$footnote];
234 + } else {
235 + // Skip custom numbers that were already used
236 + while ( in_array( $footnote_number, $this->usedFootnoteNumbers ) ) {
237 + $footnote_number++;
238 + }
239 + }
240 + }
241 + // Generate back-to-top link and the footnote item
242 + $footnoteCopy .= '<li class="easy-footnote-single"><span id="easy-footnote-bottom-' . esc_attr( $count ) . '-' . $post_id . '" class="easy-footnote-margin-adjust"></span>' . wp_kses_post( $footnote ) . '<a class="easy-footnote-to-top" href="' . esc_url( '#easy-footnote-' . $count . '-' . $post_id ) . '"></a></li>';
131 243 }
132 - if (!empty($footnotesInsert)) {
133 - if ($useLabel === true) {
134 - $content .= '<div class="easy-footnote-title"><h4>'.esc_html($efLabel).'</h4></div><ol class="easy-footnotes-wrapper">'.$footnoteCopy.'</ol>';
135 - } else {
136 - $content .= '<ol class="easy-footnotes-wrapper">'.$footnoteCopy.'</ol>';
244 + if ( ! empty( $footnotesInsert ) ) {
245 + if ( true === $useLabel ) {
246 + $footnote_label = '<div class="easy-footnote-title"><h4>' . esc_html( $efLabel ) . '</h4></div>';
247 + // Filter for editing footnote label markup and output.
248 + $footnote_label = apply_filters( 'efn_footnote_label', $footnote_label, $efLabel );
249 +
250 + $efn_output .= $footnote_label;
137 251 }
252 +
253 + $footnote_content = '';
254 +
255 + // Add filter before footnote list.
256 + $footnote_content = apply_filters( 'before_footnote', $footnote_content );
257 + $footnote_content .= '<ol class="easy-footnotes-wrapper">' . $footnoteCopy . '</ol>';
258 +
259 + // Add filter after footnote list.
260 + $footnote_content = apply_filters( 'after_footnote', $footnote_content );
261 +
262 + $efn_output .= $footnote_content;
263 +
264 + // Add filters for the entire footnote list output.
265 + $efn_output = apply_filters( 'efn_footnote_list_output', $efn_output );
266 +
267 + $content .= do_shortcode( $efn_output );
138 268 }
269 + }
139 270
271 + return $content;
272 + }
140 273
141 - }
274 + /**
275 + * Reset the footnote count and footnote array each time the_content has been run.
276 + *
277 + * @param string $content The content of the post from the_content filter.
278 + */
279 + public function easy_footnote_reset( $content ) {
280 + $this->footnoteCount = 0;
281 +
282 + $this->footnotes = array();
283 +
142 284 return $content;
143 285 }
144 286
145 - // Functions to create Reading Time admin pages
287 + /**
288 + * Include the easy-footnotes-admin.php file.
289 + */
146 290 public function easy_footnotes_admin() {
147 - include('easy-footnotes-admin.php');
291 + include 'easy-footnotes-admin.php';
148 292 }
149 293
294 + /**
295 + * Function to add options page for Easy Footnote Settings.
296 + */
150 297 public function easy_footnotes_admin_actions() {
151 - add_options_page("Easy Footnotes Settings", "Easy Footnotes", "manage_options", "easy-footnotes-settings", array($this, "easy_footnotes_admin"));
298 + add_options_page(
299 + __( 'Easy Footnotes Settings', 'easy-footnotes' ),
300 + __( 'Easy Footnotes', 'easy-footnotes' ),
301 + 'manage_options',
302 + 'easy-footnotes-settings',
303 + array( $this, 'easy_footnotes_admin' )
304 + );
152 305 }
153 306
307 + /**
308 + * Function for enqueuring EAsy Footnotes admin scripts.
309 + */
154 310 public function easy_footnotes_admin_scripts() {
155 - wp_enqueue_style( 'easy-footnotes-admin-styles', plugins_url( '/assets/easy-footnotes-admin.css' , __FILE__ ), '', '1.0.13' );
311 + wp_enqueue_style( 'easy-footnotes-admin-styles', plugins_url( '/assets/easy-footnotes-admin.css', __FILE__ ), '', $this->version );
312 + wp_enqueue_script( 'easy-footnotes-admin-scripts', plugins_url( '/assets/js/easy-footnotes-admin.js', __FILE__ ), array( 'jquery' ), $this->version, true );
156 313 }
157 314
315 + /**
316 + * Load plugin textdomain easy-footnotes
317 + */
318 + public function efn_load_textdomain() {
319 + load_plugin_textdomain( 'easy-footnotes', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
320 + }
321 +
322 + /**
323 + * Manually reset footnotes and counter
324 + */
325 + public function short_code_reset() {
326 + $this->footnoteCount = 0;
327 + $this->footnotes = array();
328 + return "";
329 + }
158 330 }
159 331
160 332 $easyFootnotes = new easyFootnotes();