PluginProbe
Plugins List / 2.6.1
Plugins List v2.6.1
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.1, at plugins-list.php

694 lines 19.8 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.1
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 pll_set_plugins_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', 'pll_set_plugins_meta', 10, 2 );
60
61 /**
62 * Main Shortcode Function
63 *
64 * Extract shortcode parameters and call main function to output results
65 *
66 * @uses pll_get_plugins_list Get the list of plugins
67 *
68 * @param string $paras Shortcode parameters.
69 * @return string Output.
70 */
71 function pll_add_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 = pll_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', 'pll_add_shortcode' );
99
100 /**
101 * Number of plugins shortcode
102 *
103 * Shortcode to return number of plugins
104 *
105 * @uses pll_get_plugin_number Get the number of plugins
106 *
107 * @param string $paras Shortcode parameters.
108 * @return string Output.
109 */
110 function pll_add_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 = pll_get_plugin_number( $atts['active'], $atts['inactive'], $atts['cache'] );
122
123 return $output;
124 }
125
126 add_shortcode( 'plugins_number', 'add_add_number_shortcode' );
127
128 /**
129 * Get Plugins List
130 *
131 * Get list of plugins and, optionally, format them
132 *
133 * @uses pll_format_plugin_list Format the plugin list
134 * @uses pll_get_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 pll_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 = pll_get_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 .= pll_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 * Get Plugin number
249 *
250 * Get number of plugins
251 *
252 * @since 2.2
253 *
254 * @uses pll_get_data Get the plugin data
255 *
256 * @param string $show_active Whether to include active plugins or not.
257 * @param string $show_inactive Whether to include inactive plugins or not.
258 * @param string $cache Cache time.
259 * @return string Plugin number.
260 */
261 function pll_get_plugin_number( $show_active, $show_inactive, $cache ) {
262
263 // Get plugin data.
264
265 $plugins = pll_get_data( $cache );
266
267 // Get count.
268
269 if ( 'true' === $show_inactive && 'true' === $show_active ) {
270 $output = count( $plugins );
271 } else {
272 $output = 0;
273 foreach( $plugins as $plugin_file => $plugin_data ) { // @codingStandardsIgnoreLine -- require $plugin_data for array values but not doing anything with it
274 if ( is_plugin_active( $plugin_file ) ) {
275 ++$output;
276 }
277 }
278 if ( 'true' === $show_inactive ) {
279 $output = count( $plugins ) - $output; }
280 }
281
282 return $output;
283 }
284
285 /**
286 * Get Plugins data
287 *
288 * Get plugin data and cache it
289 *
290 * @uses pll_format_plugin_list Format the plugin list.
291 *
292 * @param string $cache Cache time.
293 * @return string Plugin data.
294 */
295 function pll_get_data( $cache ) {
296
297 // Attempt to get plugin list from cache.
298
299 if ( ! $cache ) {
300 $cache = 'no'; }
301
302 $plugins = false;
303 $cache_key = 'plugins_list';
304 if ( is_numeric( $cache ) ) {
305 $plugins = get_transient( $cache_key ); }
306
307 // If not using cache, generate a new list and cache that.
308
309 if ( ! $plugins ) {
310 $plugins = get_plugins();
311 if ( ( '' !== $plugins ) && ( is_numeric( $cache ) ) ) {
312 set_transient( $cache_key, $plugins, MINUTE_IN_SECONDS * $cache ); }
313 }
314
315 return $plugins;
316 }
317
318 /**
319 * Format Plugin List
320 *
321 * Format the plugin list
322 *
323 * @uses replace_plugin_list_tags Replace the tags
324 *
325 * @param string $plugin_data The plugin list.
326 * @param string $format Format to use.
327 * @param string $nofollow Nofollow text.
328 * @param string $target Target text.
329 * @param string $characters Maximum characters for description.
330 * @param string $words Maximum words for description.
331 * @param string $emoji True or false, whether to strip emoji from description.
332 * @param string $end When the description is truncated, what to place at the end of the string.
333 * @param string $plugin_active True or false, whether the plugin is active or not.
334 * @return string Output.
335 */
336 function pll_format_plugin_list( $plugin_data, $format, $nofollow, $target, $characters, $words, $emoji, $end, $plugin_active ) {
337
338 // Allowed tag.
339
340 $plugins_allowedtags = array(
341 'a' => array(
342 'href' => array(),
343 'title' => array(),
344 ),
345 'abbr' => array( 'title' => array() ),
346 'acronym' => array( 'title' => array() ),
347 'code' => array(),
348 'em' => array(),
349 'strong' => array(),
350 );
351
352 // Sanitize all displayed data.
353
354 $plugin_data['Title'] = wp_kses( $plugin_data['Title'], $plugins_allowedtags );
355 $plugin_data['PluginURI'] = wp_kses( $plugin_data['PluginURI'], $plugins_allowedtags );
356 $plugin_data['AuthorURI'] = wp_kses( $plugin_data['AuthorURI'], $plugins_allowedtags );
357 $plugin_data['Version'] = wp_kses( $plugin_data['Version'], $plugins_allowedtags );
358 $plugin_data['Author'] = wp_kses( $plugin_data['Author'], $plugins_allowedtags );
359 $plugin_data['RequiresWP'] = wp_kses( $plugin_data['RequiresWP'], $plugins_allowedtags );
360 $plugin_data['RequiresPHP'] = wp_kses( $plugin_data['RequiresPHP'], $plugins_allowedtags );
361
362 // Get plugin activity status.
363
364 if ( $plugin_active ) {
365 $plugin_data['Active'] = __( 'Active', 'plugins-list' );
366 } else {
367 $plugin_data['Active'] = __( 'Inactive', 'plugins-list' );
368 }
369
370 // Strip emoji, HTML and unnecessary space from the description.
371
372 if ( false === $emoji ) {
373 $plugin_data['Description'] = remove_emoji_from_plugin_desc( $plugin_data['Description'] );
374 }
375 $plugin_data['Description'] = strip_spaces_from_plugin_desc( wp_strip_all_tags( $plugin_data['Description'] ) );
376
377 // Truncate the description, if required.
378
379 if ( '' !== $characters || '' !== $words ) {
380
381 // Use WordPress function to truncate description at a set number of words (ellipsis added automatically).
382
383 if ( '' !== $words ) {
384 $word_limited = wp_trim_words( $plugin_data['Description'], $words, $end );
385 $plugin_data['Description'] = $word_limited;
386 }
387
388 // Manually truncate description to a set number of characters. This is done cleanly, however, by doing so to
389 // the previous space. Then an ellipsis is added.
390
391 if ( '' !== $characters ) {
392 $character_limited = $plugin_data['Description'];
393 // Make sure the description is greater than the required length.
394 if ( strlen( $character_limited ) > $characters ) {
395 $space = strrpos( substr( $character_limited, 0, $characters + 1 ), ' ' );
396
397 if ( false === $space ) {
398 // If there is no space before the truncation length, just truncate.
399 $character_limited = substr( $character_limited, 0, $characters );
400 } else {
401 // If there is a space within the truncated area, trim to that.
402 $character_limited = substr( $character_limited, 0, $space );
403 }
404 $plugin_data['Description'] = rtrim( $character_limited ) . $end;
405 }
406 }
407
408 // If both words and character limits are used, take whichever results in the shortest result.
409
410 if ( ( '' !== $characters && '' !== $words ) && ( $word_limited < $character_limited ) ) {
411 $plugin_data['Description'] = $word_limited;
412 }
413 }
414
415 // Replace the tags.
416
417 $format = replace_plugin_list_tags( $plugin_data, $format, $nofollow, $target );
418
419 return $format;
420 }
421
422 /**
423 * Replace tags
424 *
425 * Replace the tags in the provided format
426 *
427 * @param string $plugin_data The plugin list.
428 * @param string $format Format to use.
429 * @param string $nofollow Nofollow text.
430 * @param string $target Target text.
431 * @return string Output.
432 */
433 function replace_plugin_list_tags( $plugin_data, $format, $nofollow, $target ) {
434
435 $format = strtr(
436 $format,
437 array(
438 '{{Title}}' => $plugin_data['Title'],
439 '{{PluginURI}}' => $plugin_data['PluginURI'],
440 '{{AuthorURI}}' => $plugin_data['AuthorURI'],
441 '{{Version}}' => $plugin_data['Version'],
442 '{{Description}}' => $plugin_data['Description'],
443 '{{Author}}' => $plugin_data['Author'],
444 '{{RequiresWP}}' => $plugin_data['RequiresWP'],
445 '{{RequiresPHP}}' => $plugin_data['RequiresPHP'],
446 '{{Active}}' => $plugin_data['Active'],
447 '{{LinkedTitle}}' => "<a href='" . $plugin_data['PluginURI'] . "' title='" . $plugin_data['Title'] . "'" . $nofollow . $target . '>' . $plugin_data['Title'] . '</a>',
448 '{{LinkedAuthor}}' => "<a href='" . $plugin_data['AuthorURI'] . "' title='" . $plugin_data['Author'] . "'" . $nofollow . $target . '>' . $plugin_data['Author'] . '</a>',
449 '#Title#' => $plugin_data['Title'],
450 '#PluginURI#' => $plugin_data['PluginURI'],
451 '#AuthorURI#' => $plugin_data['AuthorURI'],
452 '#Version#' => $plugin_data['Version'],
453 '#Description#' => $plugin_data['Description'],
454 '#Author#' => $plugin_data['Author'],
455 '#RequiresWP#' => $plugin_data['RequiresWP'],
456 '#RequiresPHP#' => $plugin_data['RequiresPHP'],
457 '#Active#' => $plugin_data['Active'],
458 '#LinkedTitle#' => "<a href='" . $plugin_data['PluginURI'] . "' title='" . $plugin_data['Title'] . "'" . $nofollow . $target . '>' . $plugin_data['Title'] . '</a>',
459 '#LinkedAuthor#' => "<a href='" . $plugin_data['AuthorURI'] . "' title='" . $plugin_data['Author'] . "'" . $nofollow . $target . '>' . $plugin_data['Author'] . '</a>',
460 '{{' => '<',
461 '}}' => '>',
462 '{' => '<',
463 '}' => '>',
464 )
465 );
466
467 // Remove all HTML tags other than those used for formatting.
468
469 $allowed_tags = array(
470 'a' => array(
471 'href' => array(),
472 'hreflang' => array(),
473 'rel' => array(),
474 'target' => array(),
475 'type' => array(),
476 'class' => array(),
477 'style' => array(),
478 ),
479 'b' => array(),
480 'big' => array(),
481 'blockquote' => array(
482 'cite' => array(),
483 'class' => array(),
484 'style' => array(),
485 ),
486 'br' => array(),
487 'caption' => array(),
488 'center' => array(),
489 'cite' => array(),
490 'code' => array(
491 'pre' => array(),
492 'class' => array(),
493 'style' => array(),
494 ),
495 'col' => array(
496 'span' => array(),
497 'class' => array(),
498 'style' => array(),
499 ),
500 'colgroup' => array(
501 'span' => array(),
502 'class' => array(),
503 'style' => array(),
504 ),
505 'div' => array(
506 'class' => array(),
507 'style' => array(),
508 ),
509 'em' => array(
510 'class' => array(),
511 'style' => array(),
512 ),
513 'font' => array(
514 'class' => array(),
515 'style' => array(),
516 ),
517 'h1' => array(
518 'class' => array(),
519 'style' => array(),
520 ),
521 'h2' => array(
522 'class' => array(),
523 'style' => array(),
524 ),
525 'h3' => array(
526 'class' => array(),
527 'style' => array(),
528 ),
529 'h4' => array(
530 'class' => array(),
531 'style' => array(),
532 ),
533 'h5' => array(
534 'class' => array(),
535 'style' => array(),
536 ),
537 'h6' => array(
538 'class' => array(),
539 'style' => array(),
540 ),
541 'hr' => array(
542 'class' => array(),
543 'style' => array(),
544 ),
545 'i' => array(
546 'class' => array(),
547 'style' => array(),
548 ),
549 'img' => array(
550 'src' => array(),
551 'alt' => array(),
552 'class' => array(),
553 'style' => array(),
554 ),
555 'li' => array(
556 'class' => array(),
557 'style' => array(),
558 ),
559 'ol' => array(
560 'start' => array(),
561 'type' => array(),
562 'class' => array(),
563 'style' => array(),
564 ),
565 'p' => array(
566 'class' => array(),
567 'style' => array(),
568 ),
569 'pre' => array(
570 'code' => array(),
571 'samp' => array(),
572 'class' => array(),
573 'style' => array(),
574 ),
575 'q' => array(
576 'cite' => array(),
577 'class' => array(),
578 'style' => array(),
579 ),
580 's' => array(
581 'class' => array(),
582 'style' => array(),
583 ),
584 'small' => array(
585 'class' => array(),
586 'style' => array(),
587 ),
588 'span' => array(
589 'class' => array(),
590 'style' => array(),
591 ),
592 'strike' => array(
593 'class' => array(),
594 'style' => array(),
595 ),
596 'strong' => array(
597 'class' => array(),
598 'style' => array(),
599 ),
600 'style' => array(
601 'type' => array(),
602 'class' => array(),
603 'style' => array(),
604 ),
605 'sub' => array(
606 'class' => array(),
607 'style' => array(),
608 ),
609 'sup' => array(
610 'class' => array(),
611 'style' => array(),
612 ),
613 'table' => array(
614 'class' => array(),
615 'style' => array(),
616 ),
617 'td' => array(
618 'colspan' => array(),
619 'headers' => array(),
620 'rowspan' => array(),
621 'class' => array(),
622 'style' => array(),
623 ),
624 'th' => array(
625 'colspan' => array(),
626 'headers' => array(),
627 'rowspan' => array(),
628 'scope' => array(),
629 'class' => array(),
630 'style' => array(),
631 ),
632 'tr' => array(
633 'class' => array(),
634 'style' => array(),
635 ),
636 'u' => array(
637 'class' => array(),
638 'style' => array(),
639 ),
640 'ul' => array(
641 'class' => array(),
642 'style' => array(),
643 ),
644 );
645
646 $format = wp_kses( $format, $allowed_tags );
647
648 return $format;
649 }
650
651 /**
652 * Remove emoji
653 *
654 * Function to strip emoji from the plugin description.
655 *
656 * @param string $description The plugin description.
657 * @return string Stripped description.
658 */
659 function remove_emoji_from_plugin_desc( $description ) {
660
661 $symbols = "\x{1F100}-\x{1F1FF}" // Enclosed Alphanumeric Supplement.
662 . "\x{1F300}-\x{1F5FF}" // Miscellaneous Symbols and Pictographs.
663 . "\x{1F600}-\x{1F64F}" // Emoticons.
664 . "\x{1F680}-\x{1F6FF}" // Transport And Map Symbols.
665 . "\x{1F900}-\x{1F9FF}" // Supplemental Symbols and Pictographs.
666 . "\x{2600}-\x{26FF}" // Miscellaneous Symbols.
667 . "\x{2700}-\x{27BF}"; // Dingbats.
668
669 $description = preg_replace( '/[' . $symbols . ']+/u', '', $description );
670
671 return $description;
672 }
673
674 /**
675 * Strip spaces
676 *
677 * Function to strip extra spaces from the plugin description.
678 *
679 * @param string $description The plugin description.
680 * @return string Stripped description.
681 */
682 function strip_spaces_from_plugin_desc( $description ) {
683
684 $continue = true;
685 while ( true === $continue ) {
686 $replace = str_replace( ' ', ' ', $description );
687 if ( $replace === $description ) {
688 $continue = false;
689 }
690 $description = $replace;
691 }
692 return trim( $description );
693 }
694