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
easy-footnotes / easy-footnotes.php

easy-footnotes.php in Easy Footnotes trunk, at easy-footnotes.php

333 lines 12.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Easy Footnotes
4 * Plugin URI: https://jasonyingling.me/easy-footnotes-wordpress/
5 * Description: Easily add footnotes to your posts with a simple shortcode.
6 * Text Domain: easy-footnotes
7 * Version: 1.1.14
8 * Author: Jason Yingling
9 * Author URI: https://jasonyingling.me
10 * License: GPL2
11 *
12 * @package easy-footnotes
13 */
14
15 /*
16 Copyright 2018 Jason Yingling (email : yingling017@gmail.com)
17
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.
21
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.
26
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
30 */
31 /**
32 * The Easy Footnotes class. In camel case. Because I didn't follow WPCS way back when.
33 */
34 class easyFootnotes {
35
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();
42 public $footnoteCount = 0;
43 public $prevPost;
44 public $footnoteOptions;
45 public $footnoteLookup = array();
46 public $usedFootnoteNumbers = array();
47
48 private $footnoteSettings;
49
50 private $version = '1.1.14';
51
52 /**
53 * Constructing the initial plugin options, shortcodes, and hooks.
54 */
55 public function __construct() {
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,
63 );
64
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' );
82 }
83
84 /**
85 * Registering the scripts and styles used by jQuery qTip.
86 */
87 public function register_qtip_scripts() {
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 );
93 }
94
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
108 wp_enqueue_style( 'qtipstyles' );
109 wp_enqueue_style( 'easyfootnotescss' );
110 wp_enqueue_script( 'imagesloaded' );
111 wp_enqueue_script( 'qtip' );
112 wp_enqueue_script( 'qtipcall' );
113 wp_enqueue_style( 'dashicons' );
114
115 // Accept optional custom number attribute
116 $atts = shortcode_atts(
117 array(
118 'num' => null
119 ),
120 $atts
121 );
122
123 $post_id = get_the_ID();
124
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 }
140 }
141
142
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 }
158 } else {
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;
168 }
169
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
181 return $footnoteContent;
182 }
183
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;
191
192 return $this->footnotes;
193 }
194
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;
203 }
204
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 }
210
211 if ( ( is_singular() || $efn_show_on_front ) && is_main_query() ) {
212 $footnotesInsert = $this->footnotes;
213
214 $footnoteCopy = '';
215 $efn_output = '';
216
217 $useLabel = isset( $this->footnoteOptions['useLabel'] ) ? $this->footnoteOptions['useLabel'] : false;
218 $efLabel = isset($this->footnoteOptions['footnoteLabel'] ) ? $this->footnoteOptions['footnoteLabel'] : __( 'Footnotes', 'easy-footnotes' );
219
220 $post_id = get_the_ID();
221
222 // Create a new array to track used footnotes and their numbers
223 $footnote_number = 1;
224
225 // sort footnotes according to numbers
226 ksort($footnotesInsert);
227
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>';
243 }
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;
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 );
268 }
269 }
270
271 return $content;
272 }
273
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
284 return $content;
285 }
286
287 /**
288 * Include the easy-footnotes-admin.php file.
289 */
290 public function easy_footnotes_admin() {
291 include 'easy-footnotes-admin.php';
292 }
293
294 /**
295 * Function to add options page for Easy Footnote Settings.
296 */
297 public function easy_footnotes_admin_actions() {
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 );
305 }
306
307 /**
308 * Function for enqueuring EAsy Footnotes admin scripts.
309 */
310 public function easy_footnotes_admin_scripts() {
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 );
313 }
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 }
330 }
331
332 $easyFootnotes = new easyFootnotes();
333