PluginProbe
Plugins List / 2.6
Plugins List v2.6
trunk 0.2.1 0.2.2 1.0 2.0 2.1 2.2.7 2.3.2 2.4.4 2.5.2 2.6 2.6.1 2.7
plugins-list / plugins-list.php

plugins-list.php in Plugins List 2.6, at plugins-list.php

695 lines 19.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugins List
4 *
5 * @package plugins-list
6 * @author David Artiss
7 * @license GPL-2.0-or-later
8 *
9 * Plugin Name: Plugins List
10 * Plugin URI: https://wordpress.org/plugins/plugins-list/
11 * Description: 🔌 Allows you to insert a list of the WordPress plugins you are using into any post/page.
12 * Version: 2.6
13 * Requires at least: 4.6
14 * Requires PHP: 7.4
15 * Author: David Artiss
16 * Author URI: https://artiss.blog
17 * Text Domain: plugins-list
18 * License: GPL v2 or later
19 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
20 *
21 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
22 * General Public License version 2, as published by the Free Software Foundation. You may NOT assume
23 * that you can use any other version of the GPL.
24 *
25 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
26 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
27 */
28
29 define( 'DEFAULT_PLUGIN_LIST_FORMAT', '<li>{{LinkedTitle}} by {{LinkedAuthor}}.</li>' );
30
31 if ( ! function_exists( 'get_plugins' ) ) {
32 require_once ABSPATH . 'wp-admin/includes/plugin.php'; }
33
34 /**
35 * Add meta to plugin details
36 *
37 * Add options to plugin meta line
38 *
39 * @param string $links Current links.
40 * @param string $file File in use.
41 * @return string Links, now with settings added.
42 */
43 function set_plugins_list_meta( $links, $file ) {
44
45 if ( false !== strpos( $file, 'plugins-list.php' ) ) {
46
47 $links = array_merge( $links, array( '<a href="https://github.com/dartiss/plugins-list">' . __( 'Github', 'plugins-list' ) . '</a>' ) );
48
49 $links = array_merge( $links, array( '<a href="http://wordpress.org/support/plugin/plugins-list">' . __( 'Support', 'plugins-list' ) . '</a>' ) );
50
51 $links = array_merge( $links, array( '<a href="https://artiss.blog/donate">' . __( 'Donate', 'plugins-list' ) . '</a>' ) );
52
53 $links = array_merge( $links, array( '<a href="https://wordpress.org/support/plugin/plugins-list/reviews/#new-post">' . __( 'Write a Review', 'plugins-list' ) . '&nbsp;⭐️⭐️⭐️⭐️⭐️</a>' ) );
54 }
55
56 return $links;
57 }
58
59 add_filter( 'plugin_row_meta', 'set_plugins_list_meta', 10, 2 );
60
61 /**
62 * Main Shortcode Function
63 *
64 * Extract shortcode parameters and call main function to output results
65 *
66 * @uses get_plugins_list Get the list of plugins
67 *
68 * @param string $paras Shortcode parameters.
69 * @return stri Output.
70 */
71 function plugins_list_shortcode( $paras ) {
72
73 $atts = shortcode_atts(
74 array(
75 'format' => '',
76 'show_inactive' => '',
77 'show_active' => '',
78 'show_recent' => '',
79 'cache' => '',
80 'nofollow' => '',
81 'target' => '',
82 'by_author' => '',
83 'chars' => '',
84 'words' => '',
85 'emoji' => '',
86 'end' => '',
87 ),
88 $paras
89 );
90
91 // Pass the shortcode parameters onto a function to generate the plugins list.
92
93 $output = get_plugins_list( $atts['format'], $atts['show_inactive'], $atts['show_active'], $atts['show_recent'], $atts['cache'], $atts['nofollow'], $atts['target'], $atts['by_author'], $atts['chars'], $atts['words'], $atts['emoji'], $atts['end'] );
94
95 return $output;
96 }
97
98 add_shortcode( 'plugins_list', 'plugins_list_shortcode' );
99
100 /**
101 * Number of plugins shortcode
102 *
103 * Shortcode to return number of plugins
104 *
105 * @uses get_plugin_number Get the number of plugins
106 *
107 * @param string $paras Shortcode parameters.
108 * @return string Output.
109 */
110 function plugin_number_shortcode( $paras ) {
111
112 $atts = shortcode_atts(
113 array(
114 'active' => 'true',
115 'inactive' => 'false',
116 'cache' => 5,
117 ),
118 $paras
119 );
120
121 $output = get_plugin_number( $atts['active'], $atts['inactive'], $atts['cache'] );
122
123 return $output;
124 }
125
126 add_shortcode( 'plugins_number', 'plugin_number_shortcode' );
127
128 /**
129 * Get Plugins List
130 *
131 * Get list of plugins and, optionally, format them
132 *
133 * @uses format_plugin_list Format the plugin list
134 * @uses get_plugin_list_data Get the plugin data
135 *
136 * @param string $format Requires format.
137 * @param string $show_inactive Whether to format or not.
138 * @param string $show_active Whether to show active or not.
139 * @param string $show_recent Whether to show recenty active or not.
140 * @param string $cache Cache time.
141 * @param string $nofollow Whether to add nofollow to link.
142 * @param string $target Link target.
143 * @param string $by_author Which author.
144 * @param string $characters Maximum characters for description.
145 * @param string $words Maximum words for description.
146 * @param string $emoji True or false, whether to strip emoji from description.
147 * @param string $end When the description is truncated, what to place at the end of the string.
148 * @return string Output.
149 */
150 function get_plugins_list( $format, $show_inactive, $show_active, $show_recent, $cache, $nofollow, $target, $by_author, $characters, $words, $emoji, $end ) {
151
152 // Set default values.
153
154 if ( '' === $format ) {
155 $format = DEFAULT_PLUGIN_LIST_FORMAT;
156 }
157 if ( '' === $show_inactive ) {
158 $show_inactive = 'false';
159 }
160 if ( '' === $show_active ) {
161 $show_active = 'true';
162 }
163 if ( '' === $show_recent ) {
164 $show_recent = 'true';
165 }
166 if ( '' === $cache ) {
167 $cache = 5;
168 }
169 if ( $nofollow ) {
170 $nofollow = ' rel="nofollow"';
171 } else {
172 $nofollow = '';
173 }
174 if ( '' !== $target ) {
175 $target = ' target="' . $target . '"';
176 } else {
177 $target = '';
178 }
179 if ( '' !== $by_author ) {
180 $by_author = 'true';
181 }
182 if ( 'false' == $emoji ) {
183 $emoji = false;
184 } else {
185 $emoji = true;
186 }
187 if ( '' == $end ) {
188 $end = '&#8230;';
189 }
190
191 // Get plugin data.
192
193 $plugins = get_plugin_list_data( $cache );
194
195 // Sort the plugin array if required in author sequence.
196
197 if ( 'true' === $by_author ) {
198 uasort(
199 $plugins,
200 function( $a, $b ) {
201 return strtoupper( $a['Author'] ) <=> strtoupper( $b['Author'] );
202 }
203 );
204 }
205
206 // Get array of recently activate plugins.
207
208 if ( is_network_admin() ) {
209 $recently_activated = get_site_option( 'recently_activated', array() );
210 } else {
211 $recently_activated = get_option( 'recently_activated', array() );
212 }
213
214 // Extract each plugin and format the output.
215
216 $output = '';
217
218 foreach ( $plugins as $plugin_file => $plugin_data ) {
219
220 // Work out whether plugin is active or not.
221
222 $plugin_active = false;
223 if ( is_plugin_active( $plugin_file ) ) {
224 $plugin_active = true;
225 }
226
227 // Was this recently active?
228
229 $recently_active = false;
230 if ( is_array( $recently_activated ) && array_key_exists( $plugin_file, $recently_activated ) ) {
231 $recently_active = true;
232 }
233
234 // Depending on whhat was requested, format the current plugin for output.
235
236 if ( ( $recently_active && 'true' === $show_recent ) || ( $plugin_active && 'true' === $show_active ) || ( ! $plugin_active && 'true' === $show_inactive ) ) {
237
238 $output .= format_plugin_list( $plugin_data, $format, $nofollow, $target, $characters, $words, $emoji, $end, $plugin_active );
239 }
240 }
241
242 // Return the code, with HTML comments.
243
244 return "\n" . $output . "\n";
245
246 }
247
248 /**
249 * Get Plugin number
250 *
251 * Get number of plugins
252 *
253 * @since 2.2
254 *
255 * @uses get_plugin_list_data Get the plugin data
256 *
257 * @param string $show_active Whether to include active plugins or not.
258 * @param string $show_inactive Whether to include inactive plugins or not.
259 * @param string $cache Cache time.
260 * @return string Plugin number.
261 */
262 function get_plugin_number( $show_active, $show_inactive, $cache ) {
263
264 // Get plugin data.
265
266 $plugins = get_plugin_list_data( $cache );
267
268 // Get count.
269
270 if ( 'true' === $show_inactive && 'true' === $show_active ) {
271 $output = count( $plugins );
272 } else {
273 $output = 0;
274 foreach( $plugins as $plugin_file => $plugin_data ) { // @codingStandardsIgnoreLine -- require $plugin_data for array values but not doing anything with it
275 if ( is_plugin_active( $plugin_file ) ) {
276 $output++;
277 }
278 }
279 if ( 'true' === $show_inactive ) {
280 $output = count( $plugins ) - $output; }
281 }
282
283 return $output;
284 }
285
286 /**
287 * Get Plugins data
288 *
289 * Get plugin data and cache it
290 *
291 * @uses format_plugin_list Format the plugin list.
292 *
293 * @param string $cache Cache time.
294 * @return string Plugin data.
295 */
296 function get_plugin_list_data( $cache ) {
297
298 // Attempt to get plugin list from cache.
299
300 if ( ! $cache ) {
301 $cache = 'no'; }
302
303 $plugins = false;
304 $cache_key = 'plugins_list';
305 if ( is_numeric( $cache ) ) {
306 $plugins = get_transient( $cache_key ); }
307
308 // If not using cache, generate a new list and cache that.
309
310 if ( ! $plugins ) {
311 $plugins = get_plugins();
312 if ( ( '' !== $plugins ) && ( is_numeric( $cache ) ) ) {
313 set_transient( $cache_key, $plugins, MINUTE_IN_SECONDS * $cache ); }
314 }
315
316 return $plugins;
317 }
318
319 /**
320 * Format Plugin List
321 *
322 * Format the plugin list
323 *
324 * @uses replace_plugin_list_tags Replace the tags
325 *
326 * @param string $plugin_data The plugin list.
327 * @param string $format Format to use.
328 * @param string $nofollow Nofollow text.
329 * @param string $target Target text.
330 * @param string $characters Maximum characters for description.
331 * @param string $words Maximum words for description.
332 * @param string $emoji True or false, whether to strip emoji from description.
333 * @param string $end When the description is truncated, what to place at the end of the string.
334 * @param string $plugin_active True or false, whether the plugin is active or not.
335 * @return string Output.
336 */
337 function format_plugin_list( $plugin_data, $format, $nofollow, $target, $characters, $words, $emoji, $end, $plugin_active ) {
338
339 // Allowed tag.
340
341 $plugins_allowedtags = array(
342 'a' => array(
343 'href' => array(),
344 'title' => array(),
345 ),
346 'abbr' => array( 'title' => array() ),
347 'acronym' => array( 'title' => array() ),
348 'code' => array(),
349 'em' => array(),
350 'strong' => array(),
351 );
352
353 // Sanitize all displayed data.
354
355 $plugin_data['Title'] = wp_kses( $plugin_data['Title'], $plugins_allowedtags );
356 $plugin_data['PluginURI'] = wp_kses( $plugin_data['PluginURI'], $plugins_allowedtags );
357 $plugin_data['AuthorURI'] = wp_kses( $plugin_data['AuthorURI'], $plugins_allowedtags );
358 $plugin_data['Version'] = wp_kses( $plugin_data['Version'], $plugins_allowedtags );
359 $plugin_data['Author'] = wp_kses( $plugin_data['Author'], $plugins_allowedtags );
360 $plugin_data['RequiresWP'] = wp_kses( $plugin_data['RequiresWP'], $plugins_allowedtags );
361 $plugin_data['RequiresPHP'] = wp_kses( $plugin_data['RequiresPHP'], $plugins_allowedtags );
362
363 // Get plugin activity status.
364
365 if ( $plugin_active ) {
366 $plugin_data['Active'] = __( 'Active', 'plugins-list' );
367 } else {
368 $plugin_data['Active'] = __( 'Inactive', 'plugins-list' );
369 }
370
371 // Strip emoji, HTML and unnecessary space from the description.
372
373 if ( false == $emoji ) {
374 $plugin_data['Description'] = remove_emoji_from_plugin_desc( $plugin_data['Description'] );
375 }
376 $plugin_data['Description'] = strip_spaces_from_plugin_desc( wp_strip_all_tags( $plugin_data['Description'] ) );
377
378 // Truncate the description, if required.
379
380 if ( '' != $characters || '' != $words ) {
381
382 // Use WordPress function to truncate description at a set number of words (ellipsis added automatically).
383
384 if ( '' != $words ) {
385 $word_limited = wp_trim_words( $plugin_data['Description'], $words, $end );
386 $plugin_data['Description'] = $word_limited;
387 }
388
389 // Manually truncate description to a set number of characters. This is done cleanly, however, by doing so to
390 // the previous space. Then an ellipsis is added.
391
392 if ( '' != $characters ) {
393 $character_limited = $plugin_data['Description'];
394 // Make sure the description is greater than the required length.
395 if ( strlen( $character_limited ) > $characters ) {
396 $space = strrpos( substr( $character_limited, 0, $characters + 1 ), ' ' );
397
398 if ( false == $space ) {
399 // If there is no space before the truncation length, just truncate.
400 $character_limited = substr( $character_limited, 0, $characters );
401 } else {
402 // If there is a space within the truncated area, trim to that.
403 $character_limited = substr( $character_limited, 0, $space );
404 }
405 $plugin_data['Description'] = rtrim( $character_limited ) . $end;
406 }
407 }
408
409 // If both words and character limits are used, take whichever results in the shortest result.
410
411 if ( ( '' != $characters && '' != $words ) && ( $word_limited < $character_limited ) ) {
412 $plugin_data['Description'] = $word_limited;
413 }
414 }
415
416 // Replace the tags.
417
418 $format = replace_plugin_list_tags( $plugin_data, $format, $nofollow, $target );
419
420 return $format;
421 }
422
423 /**
424 * Replace tags
425 *
426 * Replace the tags in the provided format
427 *
428 * @param string $plugin_data The plugin list.
429 * @param string $format Format to use.
430 * @param string $nofollow Nofollow text.
431 * @param string $target Target text.
432 * @return string Output.
433 */
434 function replace_plugin_list_tags( $plugin_data, $format, $nofollow, $target ) {
435
436 $format = strtr(
437 $format,
438 array(
439 '{{Title}}' => $plugin_data['Title'],
440 '{{PluginURI}}' => $plugin_data['PluginURI'],
441 '{{AuthorURI}}' => $plugin_data['AuthorURI'],
442 '{{Version}}' => $plugin_data['Version'],
443 '{{Description}}' => $plugin_data['Description'],
444 '{{Author}}' => $plugin_data['Author'],
445 '{{RequiresWP}}' => $plugin_data['RequiresWP'],
446 '{{RequiresPHP}}' => $plugin_data['RequiresPHP'],
447 '{{Active}}' => $plugin_data['Active'],
448 '{{LinkedTitle}}' => "<a href='" . $plugin_data['PluginURI'] . "' title='" . $plugin_data['Title'] . "'" . $nofollow . $target . '>' . $plugin_data['Title'] . '</a>',
449 '{{LinkedAuthor}}' => "<a href='" . $plugin_data['AuthorURI'] . "' title='" . $plugin_data['Author'] . "'" . $nofollow . $target . '>' . $plugin_data['Author'] . '</a>',
450 '#Title#' => $plugin_data['Title'],
451 '#PluginURI#' => $plugin_data['PluginURI'],
452 '#AuthorURI#' => $plugin_data['AuthorURI'],
453 '#Version#' => $plugin_data['Version'],
454 '#Description#' => $plugin_data['Description'],
455 '#Author#' => $plugin_data['Author'],
456 '#RequiresWP#' => $plugin_data['RequiresWP'],
457 '#RequiresPHP#' => $plugin_data['RequiresPHP'],
458 '#Active#' => $plugin_data['Active'],
459 '#LinkedTitle#' => "<a href='" . $plugin_data['PluginURI'] . "' title='" . $plugin_data['Title'] . "'" . $nofollow . $target . '>' . $plugin_data['Title'] . '</a>',
460 '#LinkedAuthor#' => "<a href='" . $plugin_data['AuthorURI'] . "' title='" . $plugin_data['Author'] . "'" . $nofollow . $target . '>' . $plugin_data['Author'] . '</a>',
461 '{{' => '<',
462 '}}' => '>',
463 '{' => '<',
464 '}' => '>',
465 )
466 );
467
468 // Remove all HTML tags other than those used for formatting.
469
470 $allowed_tags = array(
471 'a' => array(
472 'href' => array(),
473 'hreflang' => array(),
474 'rel' => array(),
475 'target' => array(),
476 'type' => array(),
477 'class' => array(),
478 'style' => array(),
479 ),
480 'b' => array(),
481 'big' => array(),
482 'blockquote' => array(
483 'cite' => array(),
484 'class' => array(),
485 'style' => array(),
486 ),
487 'br' => array(),
488 'caption' => array(),
489 'center' => array(),
490 'cite' => array(),
491 'code' => array(
492 'pre' => array(),
493 'class' => array(),
494 'style' => array(),
495 ),
496 'col' => array(
497 'span' => array(),
498 'class' => array(),
499 'style' => array(),
500 ),
501 'colgroup' => array(
502 'span' => array(),
503 'class' => array(),
504 'style' => array(),
505 ),
506 'div' => array(
507 'class' => array(),
508 'style' => array(),
509 ),
510 'em' => array(
511 'class' => array(),
512 'style' => array(),
513 ),
514 'font' => array(
515 'class' => array(),
516 'style' => array(),
517 ),
518 'h1' => array(
519 'class' => array(),
520 'style' => array(),
521 ),
522 'h2' => array(
523 'class' => array(),
524 'style' => array(),
525 ),
526 'h3' => array(
527 'class' => array(),
528 'style' => array(),
529 ),
530 'h4' => array(
531 'class' => array(),
532 'style' => array(),
533 ),
534 'h5' => array(
535 'class' => array(),
536 'style' => array(),
537 ),
538 'h6' => array(
539 'class' => array(),
540 'style' => array(),
541 ),
542 'hr' => array(
543 'class' => array(),
544 'style' => array(),
545 ),
546 'i' => array(
547 'class' => array(),
548 'style' => array(),
549 ),
550 'img' => array(
551 'src' => array(),
552 'alt' => array(),
553 'class' => array(),
554 'style' => array(),
555 ),
556 'li' => array(
557 'class' => array(),
558 'style' => array(),
559 ),
560 'ol' => array(
561 'start' => array(),
562 'type' => array(),
563 'class' => array(),
564 'style' => array(),
565 ),
566 'p' => array(
567 'class' => array(),
568 'style' => array(),
569 ),
570 'pre' => array(
571 'code' => array(),
572 'samp' => array(),
573 'class' => array(),
574 'style' => array(),
575 ),
576 'q' => array(
577 'cite' => array(),
578 'class' => array(),
579 'style' => array(),
580 ),
581 's' => array(
582 'class' => array(),
583 'style' => array(),
584 ),
585 'small' => array(
586 'class' => array(),
587 'style' => array(),
588 ),
589 'span' => array(
590 'class' => array(),
591 'style' => array(),
592 ),
593 'strike' => array(
594 'class' => array(),
595 'style' => array(),
596 ),
597 'strong' => array(
598 'class' => array(),
599 'style' => array(),
600 ),
601 'style' => array(
602 'type' => array(),
603 'class' => array(),
604 'style' => array(),
605 ),
606 'sub' => array(
607 'class' => array(),
608 'style' => array(),
609 ),
610 'sup' => array(
611 'class' => array(),
612 'style' => array(),
613 ),
614 'table' => array(
615 'class' => array(),
616 'style' => array(),
617 ),
618 'td' => array(
619 'colspan' => array(),
620 'headers' => array(),
621 'rowspan' => array(),
622 'class' => array(),
623 'style' => array(),
624 ),
625 'th' => array(
626 'colspan' => array(),
627 'headers' => array(),
628 'rowspan' => array(),
629 'scope' => array(),
630 'class' => array(),
631 'style' => array(),
632 ),
633 'tr' => array(
634 'class' => array(),
635 'style' => array(),
636 ),
637 'u' => array(
638 'class' => array(),
639 'style' => array(),
640 ),
641 'ul' => array(
642 'class' => array(),
643 'style' => array(),
644 ),
645 );
646
647 $format = wp_kses( $format, $allowed_tags );
648
649 return $format;
650 }
651
652 /**
653 * Remove emoji
654 *
655 * Function to strip emoji from the plugin description.
656 *
657 * @param string $description The plugin description.
658 * @return string Stripped description.
659 */
660 function remove_emoji_from_plugin_desc( $description ) {
661
662 $symbols = "\x{1F100}-\x{1F1FF}" // Enclosed Alphanumeric Supplement.
663 . "\x{1F300}-\x{1F5FF}" // Miscellaneous Symbols and Pictographs.
664 . "\x{1F600}-\x{1F64F}" // Emoticons.
665 . "\x{1F680}-\x{1F6FF}" // Transport And Map Symbols.
666 . "\x{1F900}-\x{1F9FF}" // Supplemental Symbols and Pictographs.
667 . "\x{2600}-\x{26FF}" // Miscellaneous Symbols.
668 . "\x{2700}-\x{27BF}"; // Dingbats.
669
670 $description = preg_replace( '/[' . $symbols . ']+/u', '', $description );
671
672 return $description;
673 }
674
675 /**
676 * Strip spaces
677 *
678 * Function to strip extra spaces from the plugin description.
679 *
680 * @param string $description The plugin description.
681 * @return string Stripped description.
682 */
683 function strip_spaces_from_plugin_desc( $description ) {
684
685 $continue = true;
686 while ( true === $continue ) {
687 $replace = str_replace( ' ', ' ', $description );
688 if ( $replace == $description ) {
689 $continue = false;
690 }
691 $description = $replace;
692 }
693 return trim( $description );
694 }
695