PluginProbe
Plugin Groups / 1.2.2
Plugin Groups v1.2.2
trunk 1.0.3 1.1.0 1.2.1 1.2.2 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.9 3.0.0
← All changes | classes/class-plugin-groups.php +216 -1104 2.0.91.2.2 View file →
@@ -1,1104 +1,216 @@
1 -<?php
2 -/**
3 - * Core class for Plugin Groups.
4 - *
5 - * @package plugin_groups
6 - */
7 -
8 -namespace Plugin_Groups;
9 -
10 -use WP_Admin_Bar;
11 -
12 -/**
13 - * Plugin_Groups Class.
14 - */
15 -class Plugin_Groups {
16 -
17 - /**
18 - * The single instance of the class.
19 - *
20 - * @var Plugin_Groups
21 - */
22 - protected static $instance = null;
23 -
24 - /**
25 - * Holds the version of the plugin.
26 - *
27 - * @var string
28 - */
29 - protected $version;
30 -
31 - /**
32 - * Holds the plugin name.
33 - *
34 - * @var string
35 - */
36 - protected $plugin_name;
37 -
38 - /**
39 - * Holds the plugin config.
40 - *
41 - * @var array
42 - */
43 - protected $config = array();
44 -
45 - /**
46 - * Holds the Groups.
47 - *
48 - * @var array
49 - */
50 - protected $groups = array();
51 -
52 - /**
53 - * Holds the menu slug.
54 - *
55 - * @var string
56 - */
57 - public static $slug = 'plugin-groups';
58 -
59 - /**
60 - * Holds the current group.
61 - *
62 - * @var string
63 - */
64 - protected $current_group;
65 -
66 - /**
67 - * Holds the current status.
68 - *
69 - * @var string
70 - */
71 - protected $current_status;
72 -
73 - /**
74 - * Holds a list of missing plugins.
75 - *
76 - * @var array
77 - */
78 - protected $missing = array();
79 -
80 - /**
81 - * Holds the current group and status path.
82 - *
83 - * @var string
84 - */
85 - protected $current_nav_path;
86 -
87 - /**
88 - * Hold the record of the plugins current version for upgrade.
89 - *
90 - * @var string
91 - */
92 - const VERSION_KEY = '_plugin_groups_version';
93 -
94 - /**
95 - * Hold the config storage key.
96 - *
97 - * @var string
98 - */
99 - const CONFIG_KEY = '_plugin_groups_config';
100 -
101 - /**
102 - * Initiate the plugin_groups object.
103 - */
104 - public function __construct() {
105 -
106 - require_once ABSPATH . 'wp-admin/includes/plugin.php';
107 - $plugin = get_plugin_data( PLGGRP_CORE );
108 - $this->plugin_name = $plugin['Name'];
109 - $this->version = $plugin['Version'];
110 -
111 - spl_autoload_register( array( $this, 'autoload_class' ), true, false );
112 -
113 - // Start hooks.
114 - $this->setup_hooks();
115 -
116 - // Init the bulk actions.
117 - new Bulk_Actions( $this );
118 - new Extras( $this );
119 - new Rest( $this );
120 - }
121 -
122 - /**
123 - * Setup and register WordPress hooks.
124 - */
125 - protected function setup_hooks() {
126 -
127 - // Load plugin text domain
128 - add_action( 'init', array( $this, 'plugin_groups_init' ), PHP_INT_MAX ); // Always the last thing to init.
129 - add_action( 'admin_init', array( $this, 'admin_init' ) );
130 - add_action( 'admin_menu', array( $this, 'admin_menu' ) );
131 - add_action( 'network_admin_menu', array( $this, 'admin_menu' ) );
132 - add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
133 - add_filter( 'views_plugins', array( $this, 'add_groups' ), PHP_INT_MAX );
134 - add_filter( 'views_plugins-network', array( $this, 'add_groups' ), PHP_INT_MAX );
135 - add_filter( 'all_plugins', array( $this, 'catch_selected_group' ) );
136 - add_filter( 'show_advanced_plugins', array( $this, 'filter_shown_status' ), 10, 2 );
137 - add_filter( 'site_transient_update_plugins', array( $this, 'alter_update_plugins' ) );
138 - add_action( 'pre_current_active_plugins', array( $this, 'render_group_navigation' ) );
139 - add_filter( 'bulk_actions-plugins', array( $this, 'bulk_actions' ) );
140 - add_action( 'admin_bar_menu', array( $this, 'admin_bar_item' ), 100 );
141 - add_filter( 'self_admin_url', array( $this, 'append_group_to_self' ), 10, 3 );
142 - add_filter( 'plugin_action_links', array( $this, 'append_group_to_actions' ) );
143 - }
144 -
145 - /**
146 - * Append the current group id to plugin action links to maintain selection on activation and deactivation of plugins.
147 - *
148 - * @param array $actions Array of action links.
149 - *
150 - * @return array
151 - */
152 - public function append_group_to_actions( $actions ) {
153 -
154 - if ( isset( $this->current_group ) ) {
155 - foreach ( $actions as &$tag ) {
156 - $parts = shortcode_parse_atts( $tag );
157 - if ( isset( $parts['href'] ) ) {
158 - $url = html_entity_decode( $parts['href'] );
159 - $url = add_query_arg( self::$slug, $this->current_group, $url );
160 -
161 - $tag = str_replace( $parts['href'], htmlentities( $url ), $tag );
162 - }
163 - }
164 - }
165 -
166 - return $actions;
167 - }
168 -
169 - /**
170 - * Append the group to redirect URLS after activation and deactivation of plugins.
171 - *
172 - * @param string $url The url to append to.
173 - * @param string $path The path location.
174 - *
175 - * @return string
176 - */
177 - public function append_group_to_self( $url, $path ) {
178 -
179 - if ( 'plugins.php' === wp_parse_url( $path, PHP_URL_PATH ) ) {
180 - if ( ! isset( $this->current_group ) ) {
181 - // Init the current group if not set yet.
182 - $this->catch_selected_group();
183 - }
184 - // If we found a group, then append it to the self URL on the plugins page to maintain groups in nav.
185 - if ( isset( $this->current_group ) ) {
186 - $url = add_query_arg( self::$slug, $this->current_group, $url );
187 - }
188 - }
189 -
190 - return $url;
191 - }
192 -
193 - /**
194 - * Remove plugins from the update available.
195 - *
196 - * @param object $data The data object.
197 - *
198 - * @return object
199 - */
200 - public function alter_update_plugins( $data ) {
201 -
202 - if ( $this->current_group ) {
203 - $keys = array_keys( $this->groups[ $this->current_group ] );
204 - foreach ( $data->response as $key => $plugin ) {
205 - if ( ! in_array( $key, $keys, true ) ) {
206 - unset( $data->response[ $key ] );
207 - }
208 - }
209 - }
210 -
211 - return $data;
212 - }
213 -
214 - /**
215 - * Remove status that are not relevant.
216 - *
217 - * @param bool $show Flag to show.
218 - * @param string $status The current status
219 - *
220 - * @return bool
221 - */
222 - public function filter_shown_status( $show, $status ) {
223 -
224 - global $plugins;
225 -
226 - static $removes = array(
227 - 'mustuse',
228 - 'dropins',
229 - );
230 - if ( $this->current_group && in_array( $status, $removes, true ) ) {
231 - $show = false;
232 - }
233 - if ( true === $this->config['params']['legacyGrouping'] ) {
234 - $plugins += $this->groups;
235 - }
236 -
237 - return $show;
238 - }
239 -
240 - /**
241 - * Render the Group navigation.
242 - */
243 - public function render_group_navigation() {
244 -
245 - // Use new group system.
246 - if ( true !== $this->config['params']['legacyGrouping'] && 'groups-dropdown' !== $this->config['params']['navStyle'] ) {
247 - $parts = array();
248 - $parts[] = $this->make_all_tag();
249 - foreach ( $this->groups as $key => $plugins ) {
250 - $parts[] = $this->make_group_tag( $key );
251 - }
252 -
253 - $groups = implode( "", $parts );
254 - $group_set = Utils::build_tag( 'ul', array( 'class' => array( $this->config['params']['navStyle'] ) ), $groups );
255 - $html = Utils::build_tag( 'div', array( 'class' => self::$slug ), $group_set );
256 - if ( 1 < count( $parts ) ) {
257 - echo wp_kses( $html, wp_kses_allowed_html( 'post' ) );
258 - }
259 - }
260 - }
261 -
262 - /**
263 - * Add dropdown navigation on bulk actions.
264 - *
265 - * @param array $actions Unchanged actions.
266 - *
267 - * @return array
268 - */
269 - public function bulk_actions( $actions ) {
270 -
271 - if ( true !== $this->config['params']['legacyGrouping'] && 'groups-dropdown' === $this->config['params']['navStyle'] ) {
272 - $this->dropdown_navigation();
273 - }
274 -
275 - return $actions;
276 - }
277 -
278 - /**
279 - * Render a dropdown navigation.
280 - *
281 - * @param bool $echo Optional flag to echo the field or return the string.
282 - *
283 - * @return void|string
284 - */
285 - public function dropdown_navigation( $echo = true ) {
286 -
287 - $html = array();
288 - $html[] = '<label for="bulk-action-selector-groups" class="screen-reader-text">' . __( 'All groups', self::$slug ) . '</label>';
289 - $html[] = '<select id="bulk-action-selector-groups" onChange="window.location = this.value">';
290 - $html[] = '<option value="' . esc_url( $this->get_nav_url() ) . '" ' . ( ! empty( $this->current_group ) ? 'selected="selected"' : '' ) . '>' . __( 'All groups', self::$slug ) . '</option>';
291 -
292 - foreach ( $this->groups as $key => $plugins ) {
293 - $group = $this->config['groups'][ $key ];
294 - $selected = '';
295 - if ( $this->current_group === $key ) {
296 - $selected = ' selected="selected"';
297 - }
298 -
299 - $html[] = "\t" . '<option value="' . esc_url( $this->get_nav_url( $key ) ) . '"' . $selected . '>' . $group['name'] . ' (' . count( $plugins ) . ')</option>' . "\n";
300 - }
301 -
302 - $html[] = "</select>\n";
303 - $html = implode( $html );
304 - if ( false === $echo ) {
305 - return $html;
306 - }
307 - echo $html;
308 - }
309 -
310 - /**
311 - * Catch the selected group.
312 - *
313 - * @param array $plugins List of plugins.
314 - *
315 - * @return array
316 - */
317 - public function catch_selected_group( $plugins = array() ) {
318 -
319 - global $status;
320 -
321 - $this->current_status = $status;
322 - $selected_group = Utils::get_sanitized_text( INPUT_GET, self::$slug );
323 - if ( $selected_group && isset( $this->groups[ $selected_group ] ) ) {
324 - $this->current_group = $selected_group;
325 - if ( ! empty( $plugins ) ) {
326 - $plugins = $this->groups[ $selected_group ];
327 -
328 - // Add selection path.
329 - $this->current_nav_path .= ' | ' . $this->config['groups'][ $selected_group ]['name'];
330 - }
331 - }
332 -
333 - // Add our styles if we have groups;
334 - if ( ! empty( $this->groups ) ) {
335 - wp_enqueue_style( self::$slug . '-navbar' );
336 - }
337 -
338 - return $plugins;
339 - }
340 -
341 - /**
342 - * Get a url link for group navigation.
343 - *
344 - * @param null|string $id The group ID or null for all.
345 - *
346 - * @return string
347 - */
348 - protected function get_nav_url( $id = null ) {
349 -
350 - $url = Utils::get_sanitized_text( INPUT_SERVER, 'REQUEST_URI' );
351 - if ( ! $url || false === strpos( 'plugins.php', $url ) ) {
352 - // Just in case.
353 - $url = self_admin_url( 'plugins.php' );
354 - }
355 - if ( null === $id ) {
356 - // Null id is for the 'All groups'.
357 - return remove_query_arg( self::$slug, $url );
358 - }
359 -
360 - // If no plugins get a link back to admin.
361 - if ( empty( $this->groups[ $id ] ) ) {
362 - return add_query_arg( 'page', self::$slug, $url );
363 - }
364 -
365 - return add_query_arg(
366 - array(
367 - 'plugin_status' => $this->current_status,
368 - self::$slug => $id,
369 -
370 - ),
371 - $url
372 - );
373 - }
374 -
375 - /**
376 - * Get the current group.
377 - *
378 - * @return array|null
379 - */
380 - public function get_current_group() {
381 -
382 - if ( ! isset( $this->current_group ) ) {
383 - $this->catch_selected_group();
384 - }
385 -
386 - return $this->current_group ? $this->config['groups'][ $this->current_group ] : null;
387 - }
388 -
389 - /**
390 - * Get the groups.
391 - *
392 - * @return array
393 - */
394 - public function get_groups() {
395 -
396 - return array_values( $this->config['groups'] );
397 - }
398 -
399 - /**
400 - * Make a group tag.
401 - *
402 - * @param string $id The Group ID.
403 - *
404 - * @return string
405 - */
406 - protected function make_group_tag( $id ) {
407 -
408 - $group = $this->config['groups'][ $id ];
409 - $total = count( $this->groups[ $id ] );
410 - $counter = '';
411 -
412 - if ( ! empty( $total ) ) {
413 -
414 - $counter = Utils::build_tag( 'span', array( 'class' => 'count' ), " ({$total})" );
415 - }
416 - $li_atts = array(
417 - 'class' => array(
418 - 'group-link',
419 - $group['id'],
420 - ),
421 - );
422 - $link_atts = array(
423 - 'href' => $this->get_nav_url( $id ),
424 - );
425 - if ( $group['id'] === $this->current_group ) {
426 - $li_atts['class'][] = 'current';
427 - $link_atts['class'] = 'current';
428 - $link_atts['aria-current'] = 'page';
429 - }
430 -
431 - $link = Utils::build_tag( 'a', $link_atts, $group['name'] . $counter );
432 -
433 - return Utils::build_tag( 'li', $li_atts, $link );
434 - }
435 -
436 - /**
437 - * Load presets into groups for built-in and filtered presets.
438 - *
439 - * @return array
440 - */
441 - protected function load_presets() {
442 -
443 - $groups = array(
444 - 'WooCommerce' => array( 'WooCommerce' ),
445 - 'Easy Digital Downloads' => array( 'Easy Digital Downloads' ),
446 - 'Ninja Forms' => array( 'Ninja Forms' ),
447 - 'Gravity Forms' => array( 'Gravity Forms' ),
448 - 'WPForms' => array( 'WPForms' ),
449 - 'E-Commerce' => array(
450 - 'WooCommerce',
451 - 'Easy Digital Downloads',
452 - ),
453 - 'Forms' => array(
454 - 'Ninja Forms',
455 - 'Gravity Forms',
456 - 'WPForms',
457 - 'Formidable Forms',
458 - ),
459 - 'SEO' => array(
460 - 'All in One SEO',
461 - 'Yoast SEO',
462 - ),
463 - // @todo: Add more categories for presets.
464 - );
465 -
466 - /**
467 - * Filter the presets (legacy)
468 - *
469 - * @deprecated 2.0.0
470 - */
471 - $groups = apply_filters( 'plugin-groups-get-presets', $groups );
472 -
473 - /**
474 - * Filter preset plugin groups.
475 - *
476 - * @hook get_preset_plugin_groups
477 - * @since 2.0.0
478 - *
479 - * @param $groups {array} The preset groups.
480 - *
481 - * @return array
482 - */
483 - $presets = apply_filters( 'get_preset_plugin_groups', $groups );
484 - $preset_groups = array();
485 - foreach ( $presets as $name => $keywords ) {
486 - $id = sanitize_title( $name );
487 - $preset_groups[ $id ] = array(
488 - 'id' => $id,
489 - 'name' => $name,
490 - 'plugins' => array(),
491 - 'keywords' => $keywords,
492 - );
493 - }
494 -
495 - return array(
496 - 'preset_groups' => $preset_groups,
497 - 'presets' => array_keys( $groups ),
498 - );
499 - }
500 -
501 - /**
502 - * Make all link tag.
503 - *
504 - * @return string
505 - */
506 - protected function make_all_tag() {
507 -
508 - $link_atts = array(
509 - 'href' => $this->get_nav_url(),
510 - );
511 - if ( empty( $this->current_group ) ) {
512 - $link_atts['class'] = 'current';
513 - $link_atts['aria-current'] = 'page';
514 - }
515 - $link = Utils::build_tag( 'a', $link_atts, __( 'All Groups', self::$slug ) );
516 -
517 - return Utils::build_tag( 'li', array( 'class' => array( 'group-link', '__allgroups' ) ), $link );
518 - }
519 -
520 - /**
521 - * Add new filter view
522 - *
523 - * @param array $views The list of nav tags for plugin statuses.
524 - *
525 - * @return array
526 - */
527 - public function add_groups( $views ) {
528 -
529 - foreach ( $views as &$tag ) {
530 - if ( preg_match( '/<a([^>]*?)>{1}/', $tag, $found ) ) {
531 - $atts = Utils::get_tag_attributes( $found[1] );
532 - $url = add_query_arg( self::$slug, $this->current_group, $atts['href'] );
533 - $tag = str_replace( $atts['href'], $url, $tag );
534 - wp_parse_str( wp_parse_url( $atts['href'], PHP_URL_QUERY ), $query );
535 - if ( isset( $query['plugin_status'] ) && $query['plugin_status'] === $this->current_status ) {
536 - $names = explode( ' ', wp_kses( $tag, array() ) );
537 - array_pop( $names );
538 - $this->current_nav_path .= ' | ' . implode( ' ', $names );
539 - }
540 - }
541 - }
542 -
543 - // Legacy.
544 - if ( true === $this->config['params']['legacyGrouping'] ) {
545 - foreach ( $this->groups as $key => $plugins ) {
546 - $views[ $key ] = $this->make_group_tag( $key );
547 - }
548 - }
549 -
550 - // @todo: Make method.
551 - if ( ! empty( $this->current_nav_path ) ) {
552 - $append = array(
553 - 'name' => $this->current_nav_path,
554 - );
555 - wp_add_inline_script(
556 - 'wp-util',
557 - 'var appendHead = ' . wp_json_encode(
558 - $append
559 - ) . '; var pluginsHead = document.getElementsByClassName(\'wp-heading-inline\' );if( pluginsHead.length ) {pluginsHead[0].innerText += appendHead.name}'
560 - );
561 - }
562 -
563 - return $views;
564 - }
565 -
566 - /**
567 - * Save the current config.
568 - *
569 - * @param null|int $site_id The site ID to save for.
570 - *
571 - * @return bool
572 - */
573 - public function save_config( $site_id = null ) {
574 -
575 - if ( is_multisite() ) {
576 - if ( null === $site_id ) {
577 - $site_id = get_current_blog_id();
578 - }
579 - $success = update_network_option( $site_id, self::CONFIG_KEY, $this->config );
580 - } else {
581 - $success = update_option( self::CONFIG_KEY, $this->config );
582 - }
583 -
584 - return $success;
585 - }
586 -
587 - /**
588 - * Autoloader by Locating and finding classes via folder structure.
589 - *
590 - * @param string $class class name to be checked and autoloaded.
591 - */
592 -
593 - function autoload_class( $class ) {
594 -
595 - $class_location = self::locate_class_file( $class );
596 - if ( $class_location ) {
597 - include_once $class_location;
598 - }
599 - }
600 -
601 - /**
602 - * Locates the path to a requested class name.
603 - *
604 - * @param string $class The class name to locate.
605 - *
606 - * @return string|null
607 - */
608 - static public function locate_class_file( $class ) {
609 -
610 - $return = null;
611 - $parts = explode( '\\', strtolower( str_replace( '_', '-', $class ) ) );
612 - $core = array_shift( $parts );
613 - $self = strtolower( str_replace( '_', '-', __CLASS__ ) );
614 - if ( $core === self::$slug ) {
615 - $name = 'class-' . strtolower( array_pop( $parts ) ) . '.php';
616 - $parts[] = $name;
617 - $path = PLGGRP_PATH . 'classes/' . implode( '/', $parts );
618 - if ( file_exists( $path ) ) {
619 - $return = $path;
620 - }
621 - }
622 -
623 - return $return;
624 - }
625 -
626 - /**
627 - * Get the plugin version
628 - */
629 - public function version() {
630 -
631 - return $this->version;
632 - }
633 -
634 - /**
635 - * Check plugin_groups version to allow 3rd party implementations to update or upgrade.
636 - */
637 - protected function check_version() {
638 -
639 - $previous_version = get_option( self::VERSION_KEY, 0.0 );
640 - $new_version = $this->version();
641 - if ( version_compare( $previous_version, $new_version, '<' ) ) {
642 - if ( version_compare( $previous_version, '2.0.0', '<' ) ) {
643 - $data = get_option( 'plugin_groups_plugin_groups', array() );
644 - if ( ! empty( $data ) ) {
645 - $new_config = $this->convert_legacy_groups( $data );
646 - update_option( self::CONFIG_KEY, $new_config );
647 - }
648 - }
649 - // Allow for updating.
650 - do_action( "_plugin_groups_version_upgrade", $previous_version, $new_version );
651 - // Update version.
652 - update_option( self::VERSION_KEY, $new_version, true );
653 - }
654 - }
655 -
656 - /**
657 - * Convert legacy configs.
658 - *
659 - * @param array $data Array of previous version config.
660 - *
661 - * @return array
662 - */
663 - protected function convert_legacy_groups( $data ) {
664 -
665 - $groups = array();
666 - foreach ( $data['group'] as $group ) {
667 - $keywords = explode( "\n", $group['config']['keywords'] );
668 - $new_group = array(
669 - 'id' => $group['_id'],
670 - 'name' => $group['config']['group_name'],
671 - 'plugins' => isset( $group['config']['plugins'] ) ? $group['config']['plugins'] : array(),
672 - 'keywords' => array_filter( $keywords ),
673 - );
674 - $groups[ $group['_id'] ] = $new_group;
675 - }
676 -
677 - // Set up the new config.
678 - $config = $this->get_default_config();
679 - $config['groups'] = $groups;
680 - $config['selectedPresets'] = isset( $data['presets'] ) ? $data['presets'] : array();
681 - $config['params']['legacyGrouping'] = true;
682 - $config['params']['navStyle'] = 'subsubsub';
683 -
684 - return $config;
685 - }
686 -
687 - /**
688 - * Initialise plugin_groups.
689 - */
690 - public function plugin_groups_init() {
691 -
692 - // Check version.
693 - $this->check_version();
694 -
695 - // Load config.
696 - $config = $this->load_config();
697 - $this->set_config( $config );
698 -
699 - /**
700 - * Init the settings system
701 - *
702 - * @param Plugin_Groups ${slug} The core object.
703 - */
704 - do_action( 'plugin_groups_init' );
705 - }
706 -
707 - /**
708 - * Hook into admin_init.
709 - */
710 - public function admin_init() {
711 -
712 - $asset = include PLGGRP_PATH . 'js/' . self::$slug . '.asset.php';
713 - wp_register_script( self::$slug, PLGGRP_URL . 'js/' . self::$slug . '.js', $asset['dependencies'], $asset['version'], true );
714 - wp_register_style( self::$slug, PLGGRP_URL . 'css/' . self::$slug . '.css', array(), $asset['version'] );
715 - wp_register_style( self::$slug . '-navbar', PLGGRP_URL . 'css/' . self::$slug . '-navbar.css', array(), $asset['version'] );
716 - }
717 -
718 - /**
719 - * Hook into the admin_menu.
720 - */
721 - public function admin_menu() {
722 -
723 - if ( ! $this->network_active() || $this->site_enabled() || is_network_admin() ) {
724 - add_submenu_page( 'plugins.php', __( 'Plugin Groups', self::$slug ), __( 'Plugin Groups', self::$slug ), 'manage_options', 'plugin-groups', array( $this, 'render_admin' ), 50 );
725 - }
726 - }
727 -
728 - /**
729 - * Check if the plugin is network activated.
730 - *
731 - * @return bool
732 - */
733 - protected function network_active() {
734 -
735 - return is_plugin_active_for_network( PLGGRP_SLUG );
736 - }
737 -
738 - /**
739 - * Check to see if the site is allowed to use this.
740 - *
741 - * @return bool
742 - */
743 - protected function site_enabled() {
744 -
745 - $site_id = get_current_blog_id();
746 - $main_config = get_network_option( get_main_site_id(), self::CONFIG_KEY, $this->get_default_config() );
747 -
748 - return in_array( $site_id, $main_config['sitesEnabled'], true );
749 - }
750 -
751 - /**
752 - * Add Groups to the admin bar.
753 - *
754 - * @param WP_Admin_Bar $admin_bar
755 - */
756 - public function admin_bar_item( $admin_bar ) {
757 -
758 - if ( ! $this->config['params']['menuGroups'] || ! current_user_can( 'activate_plugins' ) ) {
759 - return;
760 - }
761 -
762 - $groups = array(
763 - 'parent' => array(
764 - 'id' => self::$slug,
765 - 'title' => $this->plugin_name,
766 - 'href' => $this->get_nav_url( 'dashboard' ),
767 - 'meta' => array(
768 - 'title' => $this->plugin_name,
769 - ),
770 - ),
771 - );
772 -
773 - foreach ( $this->groups as $key => $plugins ) {
774 - $group = $this->config['groups'][ $key ];
775 - $groups[ $key ] = array(
776 - 'id' => $key,
777 - 'parent' => self::$slug,
778 - 'title' => $group['name'] . ' (' . count( $plugins ) . ')',
779 - 'href' => $this->get_nav_url( $key ),
780 - );
781 - }
782 -
783 - foreach ( $groups as $option ) {
784 - $admin_bar->add_menu( $option );
785 - }
786 - }
787 -
788 - /**
789 - * Enqueue assets where needed.
790 - */
791 - public function enqueue_assets() {
792 -
793 - $page = Utils::get_sanitized_text( INPUT_GET, 'page' );
794 - if ( $page && self::$slug === $page ) {
795 - wp_enqueue_script( self::$slug );
796 - wp_enqueue_style( self::$slug );
797 - wp_set_script_translations( self::$slug, self::$slug );
798 - $this->prep_config();
799 - }
800 - }
801 -
802 - /**
803 - * Prepare the config data for output to the admin UI.
804 - */
805 - protected function prep_config() {
806 -
807 - $data = $this->build_config_object();
808 -
809 - // Add config data.
810 - wp_add_inline_script( self::$slug, 'var plgData = ' . $data, 'before' );
811 - }
812 -
813 - /**
814 - * Build the json config object.
815 - *
816 - * @param int|null $site_id The site to get config for, ir null for current.
817 - *
818 - * @return string|false
819 - */
820 - public function build_config_object( $site_id = null ) {
821 -
822 - if ( null === $site_id ) {
823 - $data = $this->config;
824 - } else {
825 - $data = $this->load_config( $site_id );
826 - }
827 -
828 - // Prep config data.
829 - $data['saveURL'] = rest_url( self::$slug . '/save' );
830 - $data['legacyURL'] = add_query_arg( 'reactivate-legacy', true, $this->get_nav_url( 'dashboard' ) );
831 - $data['restNonce'] = wp_create_nonce( 'wp_rest' );
832 - // Multisite.
833 - if ( $this->network_active() && ( is_network_admin() || defined( 'REST_REQUEST' ) && true === REST_REQUEST ) ) {
834 - $data['loadURL'] = rest_url( self::$slug . '/load' );
835 - $data['sites'] = get_sites();
836 - $data['mainSite'] = get_main_site_id();
837 - }
838 -
839 - // Add plugins.
840 - $data['plugins'] = get_plugins();
841 -
842 - // Remove presets from groups for admin.
843 - $data['groups'] = array_diff_key( $data['groups'], $data['preset_groups'] );
844 -
845 - // Remove ungrouped.
846 - unset( $data['groups']['__ungrouped'] );
847 -
848 - return wp_json_encode( $data );
849 - }
850 -
851 - /**
852 - * Get the default config.
853 - *
854 - * @return array
855 - */
856 - protected function get_default_config() {
857 -
858 - return array(
859 - 'groups' => array(),
860 - 'selectedPresets' => array(),
861 - 'params' => array(
862 - 'legacyGrouping' => false,
863 - 'navStyle' => 'subsubsub',
864 - 'menuGroups' => false,
865 - ),
866 -
867 - 'sitesEnabled' => array(), // Used for multisite.
868 - );
869 - }
870 -
871 - /**
872 - * Load the UI config.
873 - *
874 - * @param int|null $site_id The site ID to load. Null for current site.
875 - *
876 - * @return array;
877 - */
878 - public function load_config( $site_id = null ) {
879 -
880 - // Load the config.
881 - if ( is_multisite() ) {
882 - if ( ! $site_id ) {
883 - $site_id = get_current_blog_id();
884 - }
885 - $config = get_network_option( $site_id, self::CONFIG_KEY, $this->get_default_config() );
886 - $config['siteID'] = (int) $site_id;
887 - } else {
888 - $config = get_option( self::CONFIG_KEY, $this->get_default_config() );
889 - }
890 - $config['pluginName'] = $this->plugin_name;
891 - $config['version'] = $this->version;
892 - $config['slug'] = self::$slug;
893 -
894 - // Flag if network admin vs main site.
895 - if ( is_network_admin() && is_main_site() ) {
896 - $config['networkAdmin'] = true;
897 - }
898 -
899 - // Load the presets.
900 - $config += $this->load_presets();
901 -
902 - return $config;
903 - }
904 -
905 - /**
906 - * Set the config.
907 - *
908 - * @param array $config The config to set.
909 - * @param int|null $site_id The site ID to load. Null for current site.
910 - */
911 - public function set_config( $config, $site_id = null ) {
912 -
913 - $this->config = $config;
914 - if ( ! empty( $this->config['params']['showUngrouped'] ) ) {
915 - $ungrouped = $this->create_ungrouped();
916 - if ( ! empty( $ungrouped['plugins'] ) ) {
917 - $this->config['groups']['__ungrouped'] = $ungrouped;
918 - }
919 - }
920 - // Populate groups with plugins.
921 - array_map( array( $this, 'populate_plugins' ), $this->config['groups'] );
922 - // register selected presets.
923 - if ( ! empty( $this->config['selectedPresets'] ) ) {
924 - array_map( array( $this, 'register_preset' ), $this->config['selectedPresets'] );
925 - }
926 - }
927 -
928 - /**
929 - * Create the Ungrouped, group.
930 - *
931 - * @return array
932 - */
933 - protected function create_ungrouped() {
934 - $plugins = array_keys( get_plugins() );
935 - $new_group = array(
936 - 'id' => '__ungrouped',
937 - 'name' => __( 'Ungrouped', self::$slug ),
938 - 'plugins' => array(),
939 - );
940 - $grouped = array();
941 - foreach ( $this->config['groups'] as $group ) {
942 - $grouped = array_merge( $grouped, $group['plugins'] );
943 - }
944 - $grouped = array_unique( $grouped );
945 - $new_group['plugins'] = array_diff( $plugins, $grouped );
946 -
947 - return $new_group;
948 - }
949 -
950 - /**
951 - * Register a preset.
952 - *
953 - * @param string $preset The preset name to register.
954 - */
955 - protected function register_preset( $preset ) {
956 -
957 - $key = sanitize_title( $preset );
958 - if ( isset( $this->config['preset_groups'][ $key ] ) ) {
959 - $this->config['groups'][ $key ] = $this->config['preset_groups'][ $key ];
960 - }
961 - }
962 -
963 - /**
964 - * Populate a group with selected plugins.
965 - *
966 - * @param array $group The group array.
967 - */
968 - protected function populate_plugins( $group ) {
969 -
970 - static $plugins;
971 - if ( ! $plugins ) {
972 - $plugins = get_plugins();
973 - }
974 - foreach ( $group['plugins'] as $plugin ) {
975 - if ( ! isset( $plugins[ $plugin ] ) ) {
976 - $this->missing[ $plugin ] = array(
977 - 'Version' => '0.0',
978 - );
979 - continue;
980 - }
981 - $this->groups[ $group['id'] ][ $plugin ] = $plugins[ $plugin ];
982 - }
983 - // Populate keywords now to keep ordering.
984 - $this->populate_keywords( $group['id'] );
985 - }
986 -
987 - /**
988 - * Populate a group from keywords.
989 - *
990 - * @param string $id The group ID.
991 - */
992 - protected function populate_keywords( $id ) {
993 -
994 - if ( ! isset( $this->config['groups'][ $id ] ) || empty( $this->config['groups'][ $id ]['keywords'] ) ) {
995 - return;
996 - }
997 - $keywords = array_map( 'strtolower', $this->config['groups'][ $id ]['keywords'] );
998 - $plugins = get_plugins();
999 - foreach ( $plugins as $plugin_key => $plugin_data ) {
1000 - if ( isset( $this->groups[ $id ][ $plugin_key ] ) ) {
1001 - continue;
1002 - }
1003 - $plugin_string = strtolower( implode( ' ', $plugin_data ) );
1004 - $matched = array_filter(
1005 - $keywords,
1006 - function ( $keyword ) use ( $plugin_string ) {
1007 -
1008 - return false !== strpos( $plugin_string, $keyword );
1009 - }
1010 - );
1011 - if ( ! empty( $matched ) ) {
1012 - $this->groups[ $id ][ $plugin_key ] = $plugin_data;
1013 - }
1014 - }
1015 - }
1016 -
1017 - /**
1018 - * Create a new Group.
1019 - *
1020 - * @param string $name The group name to create.
1021 - * @param array $plugin_slugs Plugin slug or list of slugs to add to the group.
1022 - *
1023 - * @return string|bool
1024 - */
1025 - public function create_group( $name, array $plugin_slugs = array() ) {
1026 -
1027 - $success = false;
1028 - $new_id = Utils::generate_id();
1029 - $group = array(
1030 - 'id' => $new_id,
1031 - 'keywords' => array(),
1032 - 'name' => trim( $name ),
1033 - 'open' => false,
1034 - 'plugins' => $plugin_slugs,
1035 - );
1036 - $this->config['groups'][ $new_id ] = $group;
1037 - if ( $this->save_config() ) {
1038 - $success = $new_id;
1039 - }
1040 -
1041 - return $success;
1042 - }
1043 -
1044 - /**
1045 - * Add plugins to a group.
1046 - *
1047 - * @param string $group_id The group ID to add plugin to.
1048 - * @param array $plugin_slugs Plugin slug or list of slugs to add to the group.
1049 - *
1050 - * @return bool
1051 - */
1052 - public function add_to_group( $group_id, array $plugin_slugs ) {
1053 -
1054 - $success = false;
1055 - if ( isset( $this->config['groups'][ $group_id ] ) ) {
1056 - $new_plugins = array_merge( $this->config['groups'][ $group_id ]['plugins'], $plugin_slugs );
1057 - $this->config['groups'][ $group_id ]['plugins'] = array_unique( $new_plugins );
1058 - $success = $this->save_config();
1059 - }
1060 -
1061 - return $success;
1062 - }
1063 -
1064 - /**
1065 - * Remove Plugins from a group.
1066 - *
1067 - * @param string $group_id The group ID to add plugin to.
1068 - * @param array $plugin_slugs Plugin slug or list of slugs to add to the group.
1069 - *
1070 - * @return bool
1071 - */
1072 - public function remove_from_group( $group_id, array $plugin_slugs ) {
1073 -
1074 - $success = false;
1075 - if ( isset( $this->config['groups'][ $group_id ] ) ) {
1076 - $this->config['groups'][ $group_id ]['plugins'] = array_diff( $this->config['groups'][ $group_id ]['plugins'], $plugin_slugs );
1077 - $success = $this->save_config();
1078 - }
1079 -
1080 - return $success;
1081 - }
1082 -
1083 - /**
1084 - * Render the admin page.
1085 - */
1086 - public function render_admin() {
1087 -
1088 - include PLGGRP_PATH . 'includes/main.php';
1089 - }
1090 -
1091 - /**
1092 - * Get the instance of the class.
1093 - *
1094 - * @return Plugin_Groups
1095 - */
1096 - public static function get_instance() {
1097 -
1098 - if ( is_null( self::$instance ) ) {
1099 - self::$instance = new self();
1100 - }
1101 -
1102 - return self::$instance;
1103 - }
1104 -}
1 +<?php
2 +/**
3 + * Plugin Groups.
4 + *
5 + * @package Plugin_Groups
6 + * @author David Cramer <david@digilab.co.za>
7 + * @license GPL-2.0+
8 + * @link
9 + * @copyright 2015 David Cramer <david@digilab.co.za>
10 + */
11 +
12 +/**
13 + * Plugin class.
14 + *
15 + * @package Plugin_Groups
16 + * @author David Cramer <david@digilab.co.za>
17 + */
18 +class Plugin_Groups {
19 +
20 + /**
21 + * The slug for this plugin
22 + *
23 + * @since 0.0.1
24 + * @var string
25 + */
26 + protected $plugin_slug = 'plugin-groups';
27 +
28 + /**
29 + * Holds class isntance
30 + *
31 + * @since 0.0.1
32 + * @var object|Plugin_Groups
33 + */
34 + protected static $instance = null;
35 +
36 + /**
37 + * Holds the option screen prefix
38 + *
39 + * @since 0.0.1
40 + * @var string
41 + */
42 + protected $plugin_screen_hook_suffix = null;
43 +
44 + protected $capability = 'manage_options';
45 + protected $multisite = '';
46 +
47 + /**
48 + * Initialize the plugin by setting localization, filters, and
49 + * administration functions.
50 + *
51 + * @since 0.0.1
52 + * @access private
53 + */
54 + private function __construct() {
55 +
56 + // Load plugin text domain
57 + add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
58 +
59 + // Activate plugin when new blog is added
60 + add_action( 'wpmu_new_blog', array( $this, 'activate_new_site' ) );
61 + // Replace scripts.
62 +
63 + add_action( 'wp_default_scripts', array( $this, 'replace_scripts' ), - 1 );
64 + // Load admin style sheet and JavaScript.
65 + add_action(
66 + 'admin_enqueue_scripts',
67 + array(
68 + $this,
69 + 'enqueue_admin_stylescripts',
70 + )
71 + );
72 +
73 + }
74 +
75 + /**
76 + * Return an instance of this class.
77 + *
78 + * @since 0.0.1
79 + * @return object|Plugin_Groups A single instance of this class.
80 + */
81 + public static function get_instance() {
82 +
83 + // If the single instance hasn't been set, set it now.
84 + if ( null == self::$instance ) {
85 + self::$instance = new self;
86 + }
87 +
88 + return self::$instance;
89 + }
90 +
91 + /**
92 + * Load the plugin text domain for translation.
93 + *
94 + * @since 0.0.1
95 + */
96 + public function load_plugin_textdomain() {
97 +
98 + load_plugin_textdomain( $this->plugin_slug, false, basename( PLORG_PATH ) . '/languages' );
99 +
100 + }
101 +
102 + /**
103 + * Migrate compat WP 5.6 +
104 + *
105 + * @since 1.2.2
106 + */
107 + public function replace_scripts( $scripts ) {
108 + $ver = get_bloginfo( 'version' );
109 + if ( ! version_compare( '5.6', $ver, '<=' ) || ! self::is_plugin_group_screen() ) {
110 + return;
111 + }
112 +
113 + $assets_url = PLORG_URL . '/assets/js/';
114 + self::set_script( $scripts, 'jquery-migrate', $assets_url . 'jquery-migrate/jquery-migrate-1.4.1-wp.js', array(), '1.4.1-wp' );
115 + self::set_script( $scripts, 'jquery-core', $assets_url . 'jquery/jquery-1.12.4-wp.js', array(), '1.12.4-wp' );
116 + self::set_script( $scripts, 'jquery', false, array( 'jquery-core', 'jquery-migrate' ), '1.12.4-wp' );
117 +
118 + // All the jQuery UI stuff comes here.
119 + self::set_script( $scripts, 'jquery-ui-core', $assets_url . 'jquery-ui/core.min.js', array( 'jquery' ), '1.11.4-wp', 1 );
120 + self::set_script( $scripts, 'jquery-effects-core', $assets_url . 'jquery-ui/effect.min.js', array( 'jquery' ), '1.11.4-wp', 1 );
121 + self::set_script( $scripts, 'jquery-ui-autocomplete', $assets_url . 'jquery-ui/autocomplete.min.js', array( 'jquery-ui-menu', 'wp-a11y' ), '1.11.4-wp', 1 );
122 + self::set_script( $scripts, 'jquery-ui-menu', $assets_url . 'jquery-ui/menu.min.js', array( 'jquery-ui-core', 'jquery-ui-widget', 'jquery-ui-position' ), '1.11.4-wp', 1 );
123 + self::set_script( $scripts, 'jquery-ui-sortable', $assets_url . 'jquery-ui/sortable.min.js', array( 'jquery-ui-mouse' ), '1.11.4-wp', 1 );
124 + self::set_script( $scripts, 'jquery-ui-widget', $assets_url . 'jquery-ui/widget.min.js', array( 'jquery' ), '1.11.4-wp', 1 );
125 +
126 + }
127 +
128 + /**
129 + * Pre-register scripts on 'wp_default_scripts' action, they won't be overwritten by $wp_scripts->add().
130 + *
131 + * @since 1.2.2
132 + */
133 + private static function set_script( $scripts, $handle, $src, $deps = array(), $ver = false, $in_footer = false ) {
134 + $script = $scripts->query( $handle, 'registered' );
135 +
136 + if ( $script ) {
137 + // If already added
138 + $script->src = $src;
139 + $script->deps = $deps;
140 + $script->ver = $ver;
141 + $script->args = $in_footer;
142 +
143 + unset( $script->extra['group'] );
144 +
145 + if ( $in_footer ) {
146 + $script->add_data( 'group', 1 );
147 + }
148 + } else {
149 + // Add the script
150 + if ( $in_footer ) {
151 + $scripts->add( $handle, $src, $deps, $ver, 1 );
152 + } else {
153 + $scripts->add( $handle, $src, $deps, $ver );
154 + }
155 + }
156 + }
157 +
158 + /**
159 + * Check if we're in the plugins screen.
160 + *
161 + * @since 1.2.2
162 + * @return bool
163 + */
164 + public static function is_plugin_group_screen() {
165 + $return = false;
166 + if ( PLORG_SLUG === self::current_page() ) {
167 + $return = true;
168 + }
169 +
170 + return $return;
171 + }
172 +
173 + /**
174 + * Get the name of the current admin page query_var.
175 + *
176 + * @since 1.2.2
177 + * @return string|null
178 + */
179 + public static function current_page() {
180 + $return = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
181 + if ( is_null( $return ) && function_exists( 'get_current_screen' ) ) {
182 + $screen = get_current_screen();
183 + $return = $screen->base;
184 + }
185 +
186 + return $return;
187 + }
188 +
189 + /**
190 + * Register and enqueue admin-specific style sheet.
191 + *
192 + * @since 0.0.1
193 + * @return null
194 + */
195 + public function enqueue_admin_stylescripts() {
196 +
197 + if ( self::is_plugin_group_screen() ) {
198 +
199 + wp_enqueue_style( 'plugin_groups-core-style', PLORG_URL . '/assets/css/styles.css' );
200 + wp_enqueue_style( 'plugin_groups-baldrick-modals', PLORG_URL . '/assets/css/modals.css' );
201 + wp_enqueue_script( 'plugin_groups-wp-baldrick', PLORG_URL . '/assets/js/wp-baldrick-full.js', array( 'jquery' ), false, true );
202 + wp_enqueue_script( 'jquery-ui-autocomplete' );
203 + wp_enqueue_script( 'jquery-ui-sortable' );
204 + wp_enqueue_script( 'plugin_groups-core-script', PLORG_URL . '/assets/js/scripts.js', array( 'plugin_groups-wp-baldrick' ), false );
205 + wp_enqueue_style( 'wp-color-picker' );
206 + wp_enqueue_script( 'wp-color-picker' );
207 + wp_enqueue_style( 'plugin_groups-select2-style', PLORG_URL . 'assets/css/select2.css' );
208 + wp_enqueue_script( 'plugin_groups-select2-script', PLORG_URL . 'assets/js/select2.min.js', array( 'jquery' ), false, true );
209 + }
210 +
211 + if ( 'plugins' === self::current_page() ) {
212 + wp_enqueue_script( 'plugin_groups-bulk', PLORG_URL . '/assets/js/bulk.js', array( 'jquery' ), false );
213 + wp_enqueue_style( 'plugin_groups-editor', PLORG_URL . 'assets/css/edit.css' );
214 + }
215 + }
216 +}