WordPress.org

Make WordPress Core

Ticket #51052: class-wp-plugins-list-talbe.patch

File class-wp-plugins-list-talbe.patch, 43.2 KB (added by sanzeeb3, 4 months ago)
Line 
1<?php
2/**
3 * List Table API: WP_Plugins_List_Table class
4 *
5 * @package WordPress
6 * @subpackage Administration
7 * @since 3.1.0
8 */
9
10/**
11 * Core class used to implement displaying installed plugins in a list table.
12 *
13 * @since 3.1.0
14 * @access private
15 *
16 * @see WP_List_Table
17 */
18class WP_Plugins_List_Table extends WP_List_Table {
19        /**
20         * Whether to show the auto-updates UI.
21         *
22         * @since 5.5.0
23         *
24         * @var bool True if auto-updates UI is to be shown, false otherwise.
25         */
26        protected $show_autoupdates = true;
27
28        /**
29         * Constructor.
30         *
31         * @since 3.1.0
32         *
33         * @see WP_List_Table::__construct() for more information on default arguments.
34         *
35         * @global string $status
36         * @global int    $page
37         *
38         * @param array $args An associative array of arguments.
39         */
40        public function __construct( $args = array() ) {
41                global $status, $page;
42
43                parent::__construct(
44                        array(
45                                'plural' => 'plugins',
46                                'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
47                        )
48                );
49
50                $allowed_statuses = array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search', 'paused', 'auto-update-enabled', 'auto-update-disabled' );
51
52                $status = 'all';
53                if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], $allowed_statuses, true ) ) {
54                        $status = $_REQUEST['plugin_status'];
55                }
56
57                if ( isset( $_REQUEST['s'] ) ) {
58                        $_SERVER['REQUEST_URI'] = add_query_arg( 's', wp_unslash( $_REQUEST['s'] ) );
59                }
60
61                $page = $this->get_pagenum();
62
63                $this->show_autoupdates = wp_is_auto_update_enabled_for_type( 'plugin' )
64                        && current_user_can( 'update_plugins' )
65                        && ( ! is_multisite() || $this->screen->in_admin( 'network' ) )
66                        && ! in_array( $status, array( 'mustuse', 'dropins' ), true );
67        }
68
69        /**
70         * @return array
71         */
72        protected function get_table_classes() {
73                return array( 'widefat', $this->_args['plural'] );
74        }
75
76        /**
77         * @return bool
78         */
79        public function ajax_user_can() {
80                return current_user_can( 'activate_plugins' );
81        }
82
83        /**
84         * @global string $status
85         * @global array  $plugins
86         * @global array  $totals
87         * @global int    $page
88         * @global string $orderby
89         * @global string $order
90         * @global string $s
91         */
92        public function prepare_items() {
93                global $status, $plugins, $totals, $page, $orderby, $order, $s;
94
95                wp_reset_vars( array( 'orderby', 'order' ) );
96
97                /**
98                 * Filters the full array of plugins to list in the Plugins list table.
99                 *
100                 * @since 3.0.0
101                 *
102                 * @see get_plugins()
103                 *
104                 * @param array $all_plugins An array of plugins to display in the list table.
105                 */
106                $all_plugins = apply_filters( 'all_plugins', get_plugins() );
107
108                $plugins = array(
109                        'all'                => $all_plugins,
110                        'search'             => array(),
111                        'active'             => array(),
112                        'inactive'           => array(),
113                        'recently_activated' => array(),
114                        'upgrade'            => array(),
115                        'mustuse'            => array(),
116                        'dropins'            => array(),
117                        'paused'             => array(),
118                );
119                if ( $this->show_autoupdates ) {
120                        $auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
121
122                        $plugins['auto-update-enabled']  = array();
123                        $plugins['auto-update-disabled'] = array();
124                }
125
126                $screen = $this->screen;
127
128                if ( ! is_multisite() || ( $screen->in_admin( 'network' ) && current_user_can( 'manage_network_plugins' ) ) ) {
129
130                        /**
131                         * Filters whether to display the advanced plugins list table.
132                         *
133                         * There are two types of advanced plugins - must-use and drop-ins -
134                         * which can be used in a single site or Multisite network.
135                         *
136                         * The $type parameter allows you to differentiate between the type of advanced
137                         * plugins to filter the display of. Contexts include 'mustuse' and 'dropins'.
138                         *
139                         * @since 3.0.0
140                         *
141                         * @param bool   $show Whether to show the advanced plugins for the specified
142                         *                     plugin type. Default true.
143                         * @param string $type The plugin type. Accepts 'mustuse', 'dropins'.
144                         */
145                        if ( apply_filters( 'show_advanced_plugins', true, 'mustuse' ) ) {
146                                $plugins['mustuse'] = get_mu_plugins();
147                        }
148
149                        /** This action is documented in wp-admin/includes/class-wp-plugins-list-table.php */
150                        if ( apply_filters( 'show_advanced_plugins', true, 'dropins' ) ) {
151                                $plugins['dropins'] = get_dropins();
152                        }
153
154                        if ( current_user_can( 'update_plugins' ) ) {
155                                $current = get_site_transient( 'update_plugins' );
156                                foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
157                                        if ( isset( $current->response[ $plugin_file ] ) ) {
158                                                $plugins['all'][ $plugin_file ]['update'] = true;
159                                                $plugins['upgrade'][ $plugin_file ]       = $plugins['all'][ $plugin_file ];
160                                        }
161                                }
162                        }
163                }
164
165                if ( ! $screen->in_admin( 'network' ) ) {
166                        $show = current_user_can( 'manage_network_plugins' );
167                        /**
168                         * Filters whether to display network-active plugins alongside plugins active for the current site.
169                         *
170                         * This also controls the display of inactive network-only plugins (plugins with
171                         * "Network: true" in the plugin header).
172                         *
173                         * Plugins cannot be network-activated or network-deactivated from this screen.
174                         *
175                         * @since 4.4.0
176                         *
177                         * @param bool $show Whether to show network-active plugins. Default is whether the current
178                         *                   user can manage network plugins (ie. a Super Admin).
179                         */
180                        $show_network_active = apply_filters( 'show_network_active_plugins', $show );
181                }
182
183                if ( $screen->in_admin( 'network' ) ) {
184                        $recently_activated = get_site_option( 'recently_activated', array() );
185                } else {
186                        $recently_activated = get_option( 'recently_activated', array() );
187                }
188
189                foreach ( $recently_activated as $key => $time ) {
190                        if ( $time + WEEK_IN_SECONDS < time() ) {
191                                unset( $recently_activated[ $key ] );
192                        }
193                }
194
195                if ( $screen->in_admin( 'network' ) ) {
196                        update_site_option( 'recently_activated', $recently_activated );
197                } else {
198                        update_option( 'recently_activated', $recently_activated );
199                }
200
201                $plugin_info = get_site_transient( 'update_plugins' );
202
203                foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
204                        // Extra info if known. array_merge() ensures $plugin_data has precedence if keys collide.
205                        if ( isset( $plugin_info->response[ $plugin_file ] ) ) {
206                                $plugin_data = array_merge( (array) $plugin_info->response[ $plugin_file ], array( 'update-supported' => true ), $plugin_data );
207                        } elseif ( isset( $plugin_info->no_update[ $plugin_file ] ) ) {
208                                $plugin_data = array_merge( (array) $plugin_info->no_update[ $plugin_file ], array( 'update-supported' => true ), $plugin_data );
209                        } elseif ( empty( $plugin_data['update-supported'] ) ) {
210                                $plugin_data['update-supported'] = false;
211                        }
212
213                        /*
214                         * Create the payload that's used for the auto_update_plugin filter.
215                         * This is the same data contained within $plugin_info->(response|no_update) however
216                         * not all plugins will be contained in those keys, this avoids unexpected warnings.
217                         */
218                        $filter_payload = array(
219                                'id'            => $plugin_file,
220                                'slug'          => '',
221                                'plugin'        => $plugin_file,
222                                'new_version'   => '',
223                                'url'           => '',
224                                'package'       => '',
225                                'icons'         => array(),
226                                'banners'       => array(),
227                                'banners_rtl'   => array(),
228                                'tested'        => '',
229                                'requires_php'  => '',
230                                'compatibility' => new stdClass(),
231                        );
232                        $filter_payload = (object) array_merge( $filter_payload, array_intersect_key( $plugin_data, $filter_payload ) );
233
234                        $type = 'plugin';
235                        /** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */
236                        $auto_update_forced = apply_filters( "auto_update_{$type}", null, $filter_payload );
237
238                        if ( ! is_null( $auto_update_forced ) ) {
239                                $plugin_data['auto-update-forced'] = $auto_update_forced;
240                        }
241
242                        $plugins['all'][ $plugin_file ] = $plugin_data;
243                        // Make sure that $plugins['upgrade'] also receives the extra info since it is used on ?plugin_status=upgrade.
244                        if ( isset( $plugins['upgrade'][ $plugin_file ] ) ) {
245                                $plugins['upgrade'][ $plugin_file ] = $plugin_data;
246                        }
247
248                        // Filter into individual sections.
249                        if ( is_multisite() && ! $screen->in_admin( 'network' ) && is_network_only_plugin( $plugin_file ) && ! is_plugin_active( $plugin_file ) ) {
250                                if ( $show_network_active ) {
251                                        // On the non-network screen, show inactive network-only plugins if allowed.
252                                        $plugins['inactive'][ $plugin_file ] = $plugin_data;
253                                } else {
254                                        // On the non-network screen, filter out network-only plugins as long as they're not individually active.
255                                        unset( $plugins['all'][ $plugin_file ] );
256                                }
257                        } elseif ( ! $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) {
258                                if ( $show_network_active ) {
259                                        // On the non-network screen, show network-active plugins if allowed.
260                                        $plugins['active'][ $plugin_file ] = $plugin_data;
261                                } else {
262                                        // On the non-network screen, filter out network-active plugins.
263                                        unset( $plugins['all'][ $plugin_file ] );
264                                }
265                        } elseif ( ( ! $screen->in_admin( 'network' ) && is_plugin_active( $plugin_file ) )
266                                || ( $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) ) {
267                                // On the non-network screen, populate the active list with plugins that are individually activated.
268                                // On the network admin screen, populate the active list with plugins that are network-activated.
269                                $plugins['active'][ $plugin_file ] = $plugin_data;
270
271                                if ( ! $screen->in_admin( 'network' ) && is_plugin_paused( $plugin_file ) ) {
272                                        $plugins['paused'][ $plugin_file ] = $plugin_data;
273                                }
274                        } else {
275                                if ( isset( $recently_activated[ $plugin_file ] ) ) {
276                                        // Populate the recently activated list with plugins that have been recently activated.
277                                        $plugins['recently_activated'][ $plugin_file ] = $plugin_data;
278                                }
279                                // Populate the inactive list with plugins that aren't activated.
280                                $plugins['inactive'][ $plugin_file ] = $plugin_data;
281                        }
282
283                        if ( $this->show_autoupdates ) {
284                                $enabled = in_array( $plugin_file, $auto_updates, true ) && $plugin_data['update-supported'];
285                                if ( isset( $plugin_data['auto-update-forced'] ) ) {
286                                        $enabled = (bool) $plugin_data['auto-update-forced'];
287                                }
288
289                                if ( $enabled ) {
290                                        $plugins['auto-update-enabled'][ $plugin_file ] = $plugin_data;
291                                } else {
292                                        $plugins['auto-update-disabled'][ $plugin_file ] = $plugin_data;
293                                }
294                        }
295                }
296
297                if ( strlen( $s ) ) {
298                        $status            = 'search';
299                        $plugins['search'] = array_filter( $plugins['all'], array( $this, '_search_callback' ) );
300                }
301
302                $totals = array();
303                foreach ( $plugins as $type => $list ) {
304                        $totals[ $type ] = count( $list );
305                }
306
307                if ( empty( $plugins[ $status ] ) && ! in_array( $status, array( 'all', 'search' ), true ) ) {
308                        $status = 'all';
309                }
310
311                $this->items = array();
312                foreach ( $plugins[ $status ] as $plugin_file => $plugin_data ) {
313                        // Translate, don't apply markup, sanitize HTML.
314                        $this->items[ $plugin_file ] = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, false, true );
315                }
316
317                $total_this_page = $totals[ $status ];
318
319                $js_plugins = array();
320                foreach ( $plugins as $key => $list ) {
321                        $js_plugins[ $key ] = array_keys( (array) $list );
322                }
323
324                wp_localize_script(
325                        'updates',
326                        '_wpUpdatesItemCounts',
327                        array(
328                                'plugins' => $js_plugins,
329                                'totals'  => wp_get_update_data(),
330                        )
331                );
332
333                if ( ! $orderby ) {
334                        $orderby = 'Name';
335                } else {
336                        $orderby = ucfirst( $orderby );
337                }
338
339                $order = strtoupper( $order );
340
341                uasort( $this->items, array( $this, '_order_callback' ) );
342
343                $plugins_per_page = $this->get_items_per_page( str_replace( '-', '_', $screen->id . '_per_page' ), 999 );
344
345                $start = ( $page - 1 ) * $plugins_per_page;
346
347                if ( $total_this_page > $plugins_per_page ) {
348                        $this->items = array_slice( $this->items, $start, $plugins_per_page );
349                }
350
351                $this->set_pagination_args(
352                        array(
353                                'total_items' => $total_this_page,
354                                'per_page'    => $plugins_per_page,
355                        )
356                );
357        }
358
359        /**
360         * @global string $s URL encoded search term.
361         *
362         * @param array $plugin
363         * @return bool
364         */
365        public function _search_callback( $plugin ) {
366                global $s;
367
368                foreach ( $plugin as $value ) {
369                        if ( is_string( $value ) && false !== stripos( strip_tags( $value ), urldecode( $s ) ) ) {
370                                return true;
371                        }
372                }
373
374                return false;
375        }
376
377        /**
378         * @global string $orderby
379         * @global string $order
380         * @param array $plugin_a
381         * @param array $plugin_b
382         * @return int
383         */
384        public function _order_callback( $plugin_a, $plugin_b ) {
385                global $orderby, $order;
386
387                $a = $plugin_a[ $orderby ];
388                $b = $plugin_b[ $orderby ];
389
390                if ( $a == $b ) {
391                        return 0;
392                }
393
394                if ( 'DESC' === $order ) {
395                        return strcasecmp( $b, $a );
396                } else {
397                        return strcasecmp( $a, $b );
398                }
399        }
400
401        /**
402         * @global array $plugins
403         */
404        public function no_items() {
405                global $plugins;
406
407                if ( ! empty( $_REQUEST['s'] ) ) {
408                        $s = esc_html( wp_unslash( $_REQUEST['s'] ) );
409
410                        /* translators: %s: Plugin search term. */
411                        printf( __( 'No plugins found for &#8220;%s&#8221;.' ), $s );
412
413                        // We assume that somebody who can install plugins in multisite is experienced enough to not need this helper link.
414                        if ( ! is_multisite() && current_user_can( 'install_plugins' ) ) {
415                                echo ' <a href="' . esc_url( admin_url( 'plugin-install.php?tab=search&s=' . urlencode( $s ) ) ) . '">' . __( 'Search for plugins in the WordPress Plugin Directory.' ) . '</a>';
416                        }
417                } elseif ( ! empty( $plugins['all'] ) ) {
418                        _e( 'No plugins found.' );
419                } else {
420                        _e( 'No plugins are currently available.' );
421                }
422        }
423
424        /**
425         * Displays the search box.
426         *
427         * @since 4.6.0
428         *
429         * @param string $text     The 'submit' button label.
430         * @param string $input_id ID attribute value for the search input field.
431         */
432        public function search_box( $text, $input_id ) {
433                if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
434                        return;
435                }
436
437                $input_id = $input_id . '-search-input';
438
439                if ( ! empty( $_REQUEST['orderby'] ) ) {
440                        echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
441                }
442                if ( ! empty( $_REQUEST['order'] ) ) {
443                        echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
444                }
445                ?>
446                <p class="search-box">
447                        <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
448                        <input type="search" id="<?php echo esc_attr( $input_id ); ?>" class="wp-filter-search" name="s" value="<?php _admin_search_query(); ?>" placeholder="<?php esc_attr_e( 'Search installed plugins...' ); ?>"/>
449                        <?php submit_button( $text, 'hide-if-js', '', false, array( 'id' => 'search-submit' ) ); ?>
450                </p>
451                <?php
452        }
453
454        /**
455         * @global string $status
456         * @return array
457         */
458        public function get_columns() {
459                global $status;
460
461                $columns = array(
462                        'cb'          => ! in_array( $status, array( 'mustuse', 'dropins' ), true ) ? '<input type="checkbox" />' : '',
463                        'name'        => __( 'Plugin' ),
464                        'description' => __( 'Description' ),
465                );
466
467                if ( $this->show_autoupdates ) {
468                        $columns['auto-updates'] = __( 'Automatic Updates' );
469                }
470
471                return $columns;
472        }
473
474        /**
475         * @return array
476         */
477        protected function get_sortable_columns() {
478                return array();
479        }
480
481        /**
482         * @global array $totals
483         * @global string $status
484         * @return array
485         */
486        protected function get_views() {
487                global $totals, $status;
488
489                $status_links = array();
490                foreach ( $totals as $type => $count ) {
491                        if ( ! $count ) {
492                                continue;
493                        }
494
495                        switch ( $type ) {
496                                case 'all':
497                                        /* translators: %s: Number of plugins. */
498                                        $text = _nx(
499                                                'All <span class="count">(%s)</span>',
500                                                'All <span class="count">(%s)</span>',
501                                                $count,
502                                                'plugins'
503                                        );
504                                        break;
505                                case 'active':
506                                        /* translators: %s: Number of plugins. */
507                                        $text = _n(
508                                                'Active <span class="count">(%s)</span>',
509                                                'Active <span class="count">(%s)</span>',
510                                                $count
511                                        );
512                                        break;
513                                case 'recently_activated':
514                                        /* translators: %s: Number of plugins. */
515                                        $text = _n(
516                                                'Recently Active <span class="count">(%s)</span>',
517                                                'Recently Active <span class="count">(%s)</span>',
518                                                $count
519                                        );
520                                        break;
521                                case 'inactive':
522                                        /* translators: %s: Number of plugins. */
523                                        $text = _n(
524                                                'Inactive <span class="count">(%s)</span>',
525                                                'Inactive <span class="count">(%s)</span>',
526                                                $count
527                                        );
528                                        break;
529                                case 'mustuse':
530                                        /* translators: %s: Number of plugins. */
531                                        $text = _n(
532                                                'Must-Use <span class="count">(%s)</span>',
533                                                'Must-Use <span class="count">(%s)</span>',
534                                                $count
535                                        );
536                                        break;
537                                case 'dropins':
538                                        /* translators: %s: Number of plugins. */
539                                        $text = _n(
540                                                'Drop-in <span class="count">(%s)</span>',
541                                                'Drop-ins <span class="count">(%s)</span>',
542                                                $count
543                                        );
544                                        break;
545                                case 'paused':
546                                        /* translators: %s: Number of plugins. */
547                                        $text = _n(
548                                                'Paused <span class="count">(%s)</span>',
549                                                'Paused <span class="count">(%s)</span>',
550                                                $count
551                                        );
552                                        break;
553                                case 'upgrade':
554                                        /* translators: %s: Number of plugins. */
555                                        $text = _n(
556                                                'Update Available <span class="count">(%s)</span>',
557                                                'Update Available <span class="count">(%s)</span>',
558                                                $count
559                                        );
560                                        break;
561                                case 'auto-update-enabled':
562                                        /* translators: %s: Number of plugins. */
563                                        $text = _n(
564                                                'Auto-updates Enabled <span class="count">(%s)</span>',
565                                                'Auto-updates Enabled <span class="count">(%s)</span>',
566                                                $count
567                                        );
568                                        break;
569                                case 'auto-update-disabled':
570                                        /* translators: %s: Number of plugins. */
571                                        $text = _n(
572                                                'Auto-updates Disabled <span class="count">(%s)</span>',
573                                                'Auto-updates Disabled <span class="count">(%s)</span>',
574                                                $count
575                                        );
576                                        break;
577                        }
578
579                        if ( 'search' !== $type ) {
580                                $status_links[ $type ] = sprintf(
581                                        "<a href='%s'%s>%s</a>",
582                                        add_query_arg( 'plugin_status', $type, 'plugins.php' ),
583                                        ( $type === $status ) ? ' class="current" aria-current="page"' : '',
584                                        sprintf( $text, number_format_i18n( $count ) )
585                                );
586                        }
587                }
588
589                return $status_links;
590        }
591
592        /**
593         * @global string $status
594         * @return array
595         */
596        protected function get_bulk_actions() {
597                global $status;
598
599                $actions = array();
600
601                if ( 'active' !== $status ) {
602                        $actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Activate' ) : __( 'Activate' );
603                }
604
605                if ( 'inactive' !== $status && 'recent' !== $status ) {
606                        $actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Deactivate' ) : __( 'Deactivate' );
607                }
608
609                if ( ! is_multisite() || $this->screen->in_admin( 'network' ) ) {
610                        if ( current_user_can( 'update_plugins' ) ) {
611                                $actions['update-selected'] = __( 'Update' );
612                        }
613
614                        if ( current_user_can( 'delete_plugins' ) && ( 'active' !== $status ) ) {
615                                $actions['delete-selected'] = __( 'Delete' );
616                        }
617
618                        if ( $this->show_autoupdates ) {
619                                if ( 'auto-update-enabled' !== $status ) {
620                                        $actions['enable-auto-update-selected'] = __( 'Enable Auto-updates' );
621                                }
622                                if ( 'auto-update-disabled' !== $status ) {
623                                        $actions['disable-auto-update-selected'] = __( 'Disable Auto-updates' );
624                                }
625                        }
626                }
627
628                return $actions;
629        }
630
631        /**
632         * @global string $status
633         * @param string $which
634         */
635        public function bulk_actions( $which = '' ) {
636                global $status;
637
638                if ( in_array( $status, array( 'mustuse', 'dropins' ), true ) ) {
639                        return;
640                }
641
642                parent::bulk_actions( $which );
643        }
644
645        /**
646         * @global string $status
647         * @param string $which
648         */
649        protected function extra_tablenav( $which ) {
650                global $status;
651
652                if ( ! in_array( $status, array( 'recently_activated', 'mustuse', 'dropins' ), true ) ) {
653                        return;
654                }
655
656                echo '<div class="alignleft actions">';
657
658                if ( 'recently_activated' === $status ) {
659                        submit_button( __( 'Clear List' ), '', 'clear-recent-list', false );
660                } elseif ( 'top' === $which && 'mustuse' === $status ) {
661                        echo '<p>' . sprintf(
662                                /* translators: %s: mu-plugins directory name. */
663                                __( 'Files in the %s directory are executed automatically.' ),
664                                '<code>' . str_replace( ABSPATH, '/', WPMU_PLUGIN_DIR ) . '</code>'
665                        ) . '</p>';
666                } elseif ( 'top' === $which && 'dropins' === $status ) {
667                        echo '<p>' . sprintf(
668                                /* translators: %s: wp-content directory name. */
669                                __( 'Drop-ins are single files, found in the %s directory, that replace or enhance WordPress features in ways that are not possible for traditional plugins.' ),
670                                '<code>' . str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '</code>'
671                        ) . '</p>';
672                }
673                echo '</div>';
674        }
675
676        /**
677         * @return string
678         */
679        public function current_action() {
680                if ( isset( $_POST['clear-recent-list'] ) ) {
681                        return 'clear-recent-list';
682                }
683
684                return parent::current_action();
685        }
686
687        /**
688         * @global string $status
689         */
690        public function display_rows() {
691                global $status;
692
693                if ( is_multisite() && ! $this->screen->in_admin( 'network' ) && in_array( $status, array( 'mustuse', 'dropins' ), true ) ) {
694                        return;
695                }
696
697                foreach ( $this->items as $plugin_file => $plugin_data ) {
698                        $this->single_row( array( $plugin_file, $plugin_data ) );
699                }
700        }
701
702        /**
703         * @global string $status
704         * @global int $page
705         * @global string $s
706         * @global array $totals
707         *
708         * @param array $item
709         */
710        public function single_row( $item ) {
711                global $status, $page, $s, $totals;
712                static $plugin_id_attrs = array();
713
714                list( $plugin_file, $plugin_data ) = $item;
715
716                $plugin_slug    = isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_data['Name'] );
717                $plugin_id_attr = $plugin_slug;
718
719                // Ensure the ID attribute is unique.
720                $suffix = 2;
721                while ( in_array( $plugin_id_attr, $plugin_id_attrs, true ) ) {
722                        $plugin_id_attr = "$plugin_slug-$suffix";
723                        $suffix++;
724                }
725
726                $plugin_id_attrs[] = $plugin_id_attr;
727
728                $context = $status;
729                $screen  = $this->screen;
730
731                // Pre-order.
732                $actions = array(
733                        'deactivate' => '',
734                        'activate'   => '',
735                        'details'    => '',
736                        'delete'     => '',
737                );
738
739                // Do not restrict by default.
740                $restrict_network_active = false;
741                $restrict_network_only   = false;
742
743                if ( 'mustuse' === $context ) {
744                        $is_active = true;
745                } elseif ( 'dropins' === $context ) {
746                        $dropins     = _get_dropins();
747                        $plugin_name = $plugin_file;
748                        if ( $plugin_file != $plugin_data['Name'] ) {
749                                $plugin_name .= '<br/>' . $plugin_data['Name'];
750                        }
751                        if ( true === ( $dropins[ $plugin_file ][1] ) ) { // Doesn't require a constant.
752                                $is_active   = true;
753                                $description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
754                        } elseif ( defined( $dropins[ $plugin_file ][1] ) && constant( $dropins[ $plugin_file ][1] ) ) { // Constant is true.
755                                $is_active   = true;
756                                $description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
757                        } else {
758                                $is_active   = false;
759                                $description = '<p><strong>' . $dropins[ $plugin_file ][0] . ' <span class="error-message">' . __( 'Inactive:' ) . '</span></strong> ' .
760                                        sprintf(
761                                                /* translators: 1: Drop-in constant name, 2: wp-config.php */
762                                                __( 'Requires %1$s in %2$s file.' ),
763                                                "<code>define('" . $dropins[ $plugin_file ][1] . "', true);</code>",
764                                                '<code>wp-config.php</code>'
765                                        ) . '</p>';
766                        }
767                        if ( $plugin_data['Description'] ) {
768                                $description .= '<p>' . $plugin_data['Description'] . '</p>';
769                        }
770                } else {
771                        if ( $screen->in_admin( 'network' ) ) {
772                                $is_active = is_plugin_active_for_network( $plugin_file );
773                        } else {
774                                $is_active               = is_plugin_active( $plugin_file );
775                                $restrict_network_active = ( is_multisite() && is_plugin_active_for_network( $plugin_file ) );
776                                $restrict_network_only   = ( is_multisite() && is_network_only_plugin( $plugin_file ) && ! $is_active );
777                        }
778
779                        if ( $screen->in_admin( 'network' ) ) {
780                                if ( $is_active ) {
781                                        if ( current_user_can( 'manage_network_plugins' ) ) {
782                                                $actions['deactivate'] = sprintf(
783                                                        '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
784                                                        wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ),
785                                                        esc_attr( $plugin_id_attr ),
786                                                        /* translators: %s: Plugin name. */
787                                                        esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
788                                                        __( 'Network Deactivate' )
789                                                );
790                                        }
791                                } else {
792                                        if ( current_user_can( 'manage_network_plugins' ) ) {
793                                                $actions['activate'] = sprintf(
794                                                        '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
795                                                        wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ),
796                                                        esc_attr( $plugin_id_attr ),
797                                                        /* translators: %s: Plugin name. */
798                                                        esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
799                                                        __( 'Network Activate' )
800                                                );
801                                        }
802
803                                        if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
804                                                $actions['delete'] = sprintf(
805                                                        '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
806                                                        wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins' ),
807                                                        esc_attr( $plugin_id_attr ),
808                                                        /* translators: %s: Plugin name. */
809                                                        esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
810                                                        __( 'Delete' )
811                                                );
812                                        }
813                                }
814                        } else {
815                                if ( $restrict_network_active ) {
816                                        $actions = array(
817                                                'network_active' => __( 'Network Active' ),
818                                        );
819                                } elseif ( $restrict_network_only ) {
820                                        $actions = array(
821                                                'network_only' => __( 'Network Only' ),
822                                        );
823                                } elseif ( $is_active ) {
824                                        if ( current_user_can( 'deactivate_plugin', $plugin_file ) ) {
825                                                $actions['deactivate'] = sprintf(
826                                                        '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
827                                                        wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ),
828                                                        esc_attr( $plugin_id_attr ),
829                                                        /* translators: %s: Plugin name. */
830                                                        esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
831                                                        __( 'Deactivate' )
832                                                );
833                                        }
834
835                                        if ( current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) {
836                                                $actions['resume'] = sprintf(
837                                                        '<a href="%s" id="resume-%s" class="resume-link" aria-label="%s">%s</a>',
838                                                        wp_nonce_url( 'plugins.php?action=resume&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'resume-plugin_' . $plugin_file ),
839                                                        esc_attr( $plugin_id_attr ),
840                                                        /* translators: %s: Plugin name. */
841                                                        esc_attr( sprintf( _x( 'Resume %s', 'plugin' ), $plugin_data['Name'] ) ),
842                                                        __( 'Resume' )
843                                                );
844                                        }
845                                } else {
846                                        if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
847                                                $actions['activate'] = sprintf(
848                                                        '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
849                                                        wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ),
850                                                        esc_attr( $plugin_id_attr ),
851                                                        /* translators: %s: Plugin name. */
852                                                        esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
853                                                        __( 'Activate' )
854                                                );
855                                        }
856
857                                        if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
858                                                $actions['delete'] = sprintf(
859                                                        '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
860                                                        wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins' ),
861                                                        esc_attr( $plugin_id_attr ),
862                                                        /* translators: %s: Plugin name. */
863                                                        esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
864                                                        __( 'Delete' )
865                                                );
866                                        }
867                                } // End if $is_active.
868                        } // End if $screen->in_admin( 'network' ).
869                } // End if $context.
870
871                $actions = array_filter( $actions );
872
873                if ( $screen->in_admin( 'network' ) ) {
874
875                        /**
876                         * Filters the action links displayed for each plugin in the Network Admin Plugins list table.
877                         *
878                         * @since 3.1.0
879                         *
880                         * @param string[] $actions     An array of plugin action links. By default this can include 'activate',
881                         *                              'deactivate', and 'delete'.
882                         * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
883                         * @param array    $plugin_data An array of plugin data. See `get_plugin_data()`.
884                         * @param string   $context     The plugin context. By default this can include 'all', 'active', 'inactive',
885                         *                              'recently_activated', 'upgrade', 'mustuse', 'dropins', and 'search'.
886                         */
887                        $actions = apply_filters( 'network_admin_plugin_action_links', $actions, $plugin_file, $plugin_data, $context );
888
889                        /**
890                         * Filters the list of action links displayed for a specific plugin in the Network Admin Plugins list table.
891                         *
892                         * The dynamic portion of the hook name, `$plugin_file`, refers to the path
893                         * to the plugin file, relative to the plugins directory.
894                         *
895                         * @since 3.1.0
896                         *
897                         * @param string[] $actions     An array of plugin action links. By default this can include 'activate',
898                         *                              'deactivate', and 'delete'.
899                         * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
900                         * @param array    $plugin_data An array of plugin data. See `get_plugin_data()`.
901                         * @param string   $context     The plugin context. By default this can include 'all', 'active', 'inactive',
902                         *                              'recently_activated', 'upgrade', 'mustuse', 'dropins', and 'search'.
903                         */
904                        $actions = apply_filters( "network_admin_plugin_action_links_{$plugin_file}", $actions, $plugin_file, $plugin_data, $context );
905
906                } else {
907
908                        /**
909                         * Filters the action links displayed for each plugin in the Plugins list table.
910                         *
911                         * @since 2.5.0
912                         * @since 2.6.0 The `$context` parameter was added.
913                         * @since 4.9.0 The 'Edit' link was removed from the list of action links.
914                         *
915                         * @param string[] $actions     An array of plugin action links. By default this can include 'activate',
916                         *                              'deactivate', and 'delete'. With Multisite active this can also include
917                         *                              'network_active' and 'network_only' items.
918                         * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
919                         * @param array    $plugin_data An array of plugin data. See `get_plugin_data()`.
920                         * @param string   $context     The plugin context. By default this can include 'all', 'active', 'inactive',
921                         *                              'recently_activated', 'upgrade', 'mustuse', 'dropins', and 'search'.
922                         */
923                        $actions = apply_filters( 'plugin_action_links', $actions, $plugin_file, $plugin_data, $context );
924
925                        /**
926                         * Filters the list of action links displayed for a specific plugin in the Plugins list table.
927                         *
928                         * The dynamic portion of the hook name, `$plugin_file`, refers to the path
929                         * to the plugin file, relative to the plugins directory.
930                         *
931                         * @since 2.7.0
932                         * @since 4.9.0 The 'Edit' link was removed from the list of action links.
933                         *
934                         * @param string[] $actions     An array of plugin action links. By default this can include 'activate',
935                         *                              'deactivate', and 'delete'. With Multisite active this can also include
936                         *                              'network_active' and 'network_only' items.
937                         * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
938                         * @param array    $plugin_data An array of plugin data. See `get_plugin_data()`.
939                         * @param string   $context     The plugin context. By default this can include 'all', 'active', 'inactive',
940                         *                              'recently_activated', 'upgrade', 'mustuse', 'dropins', and 'search'.
941                         */
942                        $actions = apply_filters( "plugin_action_links_{$plugin_file}", $actions, $plugin_file, $plugin_data, $context );
943
944                }
945
946                $requires_php   = isset( $plugin_data['requires_php'] ) ? $plugin_data['requires_php'] : null;
947                $compatible_php = is_php_version_compatible( $requires_php );
948                $class          = $is_active ? 'active' : 'inactive';
949                $checkbox_id    = 'checkbox_' . md5( $plugin_data['Name'] );
950                if ( $restrict_network_active || $restrict_network_only || in_array( $status, array( 'mustuse', 'dropins' ), true ) || ! $compatible_php ) {
951                        $checkbox = '';
952                } else {
953                        $checkbox = sprintf(
954                                '<label class="screen-reader-text" for="%1$s">%2$s</label>' .
955                                '<input type="checkbox" name="checked[]" value="%3$s" id="%1$s" />',
956                                $checkbox_id,
957                                /* translators: %s: Plugin name. */
958                                sprintf( __( 'Select %s' ), $plugin_data['Name'] ),
959                                esc_attr( $plugin_file )
960                        );
961                }
962                if ( 'dropins' !== $context ) {
963                        $description = '<p>' . ( $plugin_data['Description'] ? $plugin_data['Description'] : '&nbsp;' ) . '</p>';
964                        $plugin_name = $plugin_data['Name'];
965                }
966
967                if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] ) ) {
968                        $class .= ' update';
969                }
970
971                $paused = ! $screen->in_admin( 'network' ) && is_plugin_paused( $plugin_file );
972
973                if ( $paused ) {
974                        $class .= ' paused';
975                }
976
977                if ( is_uninstallable_plugin( $plugin_file ) ) {
978                        $class .= ' is-uninstallable';
979                }
980
981                printf(
982                        '<tr class="%s" data-slug="%s" data-plugin="%s">',
983                        esc_attr( $class ),
984                        esc_attr( $plugin_slug ),
985                        esc_attr( $plugin_file )
986                );
987
988                list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
989
990                $auto_updates      = (array) get_site_option( 'auto_update_plugins', array() );
991                $available_updates = get_site_transient( 'update_plugins' );
992
993                foreach ( $columns as $column_name => $column_display_name ) {
994                        $extra_classes = '';
995                        if ( in_array( $column_name, $hidden, true ) ) {
996                                $extra_classes = ' hidden';
997                        }
998
999                        switch ( $column_name ) {
1000                                case 'cb':
1001                                        echo "<th scope='row' class='check-column'>$checkbox</th>";
1002                                        break;
1003                                case 'name':
1004                                        echo "<td class='plugin-title column-primary'><strong>$plugin_name</strong>";
1005                                        echo $this->row_actions( $actions, true );
1006                                        echo '</td>';
1007                                        break;
1008                                case 'description':
1009                                        $classes = 'column-description desc';
1010
1011                                        echo "<td class='$classes{$extra_classes}'>
1012                                                <div class='plugin-description'>$description</div>
1013                                                <div class='$class second plugin-version-author-uri'>";
1014
1015                                        $plugin_meta = array();
1016                                        if ( ! empty( $plugin_data['Version'] ) ) {
1017                                                /* translators: %s: Plugin version number. */
1018                                                $plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
1019                                        }
1020                                        if ( ! empty( $plugin_data['Author'] ) ) {
1021                                                $author = $plugin_data['Author'];
1022                                                if ( ! empty( $plugin_data['AuthorURI'] ) ) {
1023                                                        $author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
1024                                                }
1025                                                /* translators: %s: Plugin author name. */
1026                                                $plugin_meta[] = sprintf( __( 'By %s' ), $author );
1027                                        }
1028
1029                                        // Details link using API info, if available.
1030                                        if ( isset( $plugin_data['slug'] ) && current_user_can( 'install_plugins' ) ) {
1031                                                $plugin_meta[] = sprintf(
1032                                                        '<a href="%s" class="thickbox open-plugin-details-modal" aria-label="%s" data-title="%s">%s</a>',
1033                                                        esc_url(
1034                                                                network_admin_url(
1035                                                                        'plugin-install.php?tab=plugin-information&plugin=' . $plugin_data['slug'] .
1036                                                                        '&TB_iframe=true&width=600&height=550'
1037                                                                )
1038                                                        ),
1039                                                        /* translators: %s: Plugin name. */
1040                                                        esc_attr( sprintf( __( 'More information about %s' ), $plugin_name ) ),
1041                                                        esc_attr( $plugin_name ),
1042                                                        __( 'View details' )
1043                                                );
1044                                        } elseif ( ! empty( $plugin_data['PluginURI'] ) ) {
1045                                                $plugin_meta[] = sprintf(
1046                                                        '<a href="%s">%s</a>',
1047                                                        esc_url( $plugin_data['PluginURI'] ),
1048                                                        __( 'Visit plugin site' )
1049                                                );
1050                                        }
1051
1052                                        /**
1053                                         * Filters the array of row meta for each plugin in the Plugins list table.
1054                                         *
1055                                         * @since 2.8.0
1056                                         *
1057                                         * @param string[] $plugin_meta An array of the plugin's metadata, including
1058                                         *                              the version, author, author URI, and plugin URI.
1059                                         * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
1060                                         * @param array    $plugin_data An array of plugin data.
1061                                         * @param string   $status      Status filter currently applied to the plugin list. Possible
1062                                         *                              values are: 'all', 'active', 'inactive', 'recently_activated',
1063                                         *                              'upgrade', 'mustuse', 'dropins', 'search', 'paused',
1064                                         *                              'auto-update-enabled', 'auto-update-disabled'.
1065                                         */
1066                                        $plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
1067
1068                                        echo implode( ' | ', $plugin_meta );
1069
1070                                        echo '</div>';
1071
1072                                        if ( $paused ) {
1073                                                $notice_text = __( 'This plugin failed to load properly and is paused during recovery mode.' );
1074
1075                                                printf( '<p><span class="dashicons dashicons-warning"></span> <strong>%s</strong></p>', $notice_text );
1076
1077                                                $error = wp_get_plugin_error( $plugin_file );
1078
1079                                                if ( false !== $error ) {
1080                                                        printf( '<div class="error-display"><p>%s</p></div>', wp_get_extension_error_description( $error ) );
1081                                                }
1082                                        }
1083
1084                                        echo '</td>';
1085                                        break;
1086                                case 'auto-updates':
1087                                        if ( ! $this->show_autoupdates ) {
1088                                                break;
1089                                        }
1090
1091                                        echo "<td class='column-auto-updates{$extra_classes}'>";
1092
1093                                        $html = array();
1094
1095                                        if ( isset( $plugin_data['auto-update-forced'] ) ) {
1096                                                if ( $plugin_data['auto-update-forced'] ) {
1097                                                        // Forced on
1098                                                        $text = __( 'Auto-updates enabled' );
1099                                                } else {
1100                                                        $text = __( 'Auto-updates disabled' );
1101                                                }
1102                                                $action     = 'unavailable';
1103                                                $time_class = ' hidden';
1104                                        } elseif ( ! isset( $plugin_data['update-supported'] ) ) {
1105                                                $text       = '';
1106                                                $action     = 'unavailable';
1107                                                $time_class = ' hidden';
1108                                        } elseif ( in_array( $plugin_file, $auto_updates, true ) ) {
1109                                                $text       = __( 'Disable auto-updates' );
1110                                                $action     = 'disable';
1111                                                $time_class = '';
1112                                        } else {
1113                                                $text       = __( 'Enable auto-updates' );
1114                                                $action     = 'enable';
1115                                                $time_class = ' hidden';
1116                                        }
1117
1118                                        $query_args = array(
1119                                                'action'        => "{$action}-auto-update",
1120                                                'plugin'        => $plugin_file,
1121                                                'paged'         => $page,
1122                                                'plugin_status' => $status,
1123                                        );
1124
1125                                        $url = add_query_arg( $query_args, 'plugins.php' );
1126
1127                                        if ( 'unavailable' == $action ) {
1128                                                $html[] = '<span class="label">' . $text . '</span>';
1129                                        } else {
1130                                                $html[] = sprintf(
1131                                                        '<a href="%s" class="toggle-auto-update aria-button-if-js" data-wp-action="%s">',
1132                                                        wp_nonce_url( $url, 'updates' ),
1133                                                        $action
1134                                                );
1135
1136                                                $html[] = '<span class="dashicons dashicons-update spin hidden" aria-hidden="true"></span>';
1137                                                $html[] = '<span class="label">' . $text . '</span>';
1138                                                $html[] = '</a>';
1139                                        }
1140
1141                                        if ( ! empty( $plugin_data['update'] ) ) {
1142                                                $html[] = sprintf(
1143                                                        '<div class="auto-update-time%s">%s</div>',
1144                                                        $time_class,
1145                                                        wp_get_auto_update_message()
1146                                                );
1147                                        }
1148
1149                                        $html = implode( '', $html );
1150
1151                                        /**
1152                                         * Filters the HTML of the auto-updates setting for each plugin in the Plugins list table.
1153                                         *
1154                                         * @since 5.5.0
1155                                         *
1156                                         * @param string $html        The HTML of the plugin's auto-update column content, including
1157                                         *                            toggle auto-update action links and time to next update.
1158                                         * @param string $plugin_file Path to the plugin file relative to the plugins directory.
1159                                         * @param array  $plugin_data An array of plugin data.
1160                                         */
1161                                        echo apply_filters( 'plugin_auto_update_setting_html', $html, $plugin_file, $plugin_data );
1162
1163                                        echo '<div class="notice notice-error notice-alt inline hidden"><p></p></div>';
1164                                        echo '</td>';
1165
1166                                        break;
1167                                default:
1168                                        $classes = "$column_name column-$column_name $class";
1169
1170                                        echo "<td class='$classes{$extra_classes}'>";
1171
1172                                        /**
1173                                         * Fires inside each custom column of the Plugins list table.
1174                                         *
1175                                         * @since 3.1.0
1176                                         *
1177                                         * @param string $column_name Name of the column.
1178                                         * @param string $plugin_file Path to the plugin file relative to the plugins directory.
1179                                         * @param array  $plugin_data An array of plugin data.
1180                                         */
1181                                        do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
1182
1183                                        echo '</td>';
1184                        }
1185                }
1186
1187                echo '</tr>';
1188
1189                /**
1190                 * Fires after each row in the Plugins list table.
1191                 *
1192                 * @since 2.3.0
1193                 * @since 5.5.0 Added 'auto-update-enabled' and 'auto-update-disabled' to possible values for `$status`.
1194                 *
1195                 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
1196                 * @param array  $plugin_data An array of plugin data.
1197                 * @param string $status      Status filter currently applied to the plugin list. Possible
1198                 *                            values are: 'all', 'active', 'inactive', 'recently_activated',
1199                 *                            'upgrade', 'mustuse', 'dropins', 'search', 'paused',
1200                 *                            'auto-update-enabled', 'auto-update-disabled'.
1201                 */
1202                do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
1203
1204                /**
1205                 * Fires after each specific row in the Plugins list table.
1206                 *
1207                 * The dynamic portion of the hook name, `$plugin_file`, refers to the path
1208                 * to the plugin file, relative to the plugins directory.
1209                 *
1210                 * @since 2.7.0
1211                 * @since 5.5.0 Added 'auto-update-enabled' and 'auto-update-disabled' to possible values for `$status`.
1212                 *
1213                 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
1214                 * @param array  $plugin_data An array of plugin data.
1215                 * @param string $status      Status filter currently applied to the plugin list. Possible
1216                 *                            values are: 'all', 'active', 'inactive', 'recently_activated',
1217                 *                            'upgrade', 'mustuse', 'dropins', 'search', 'paused',
1218                 *                            'auto-update-enabled', 'auto-update-disabled'.
1219                 */
1220                do_action( "after_plugin_row_{$plugin_file}", $plugin_file, $plugin_data, $status );
1221        }
1222
1223        /**
1224         * Gets the name of the primary column for this specific list table.
1225         *
1226         * @since 4.3.0
1227         *
1228         * @return string Unalterable name for the primary column, in this case, 'name'.
1229         */
1230        protected function get_primary_column_name() {
1231                return 'name';
1232        }
1233}