--- a/wp/wp-admin/includes/class-wp-plugins-list-table.php Thu Sep 29 08:06:27 2022 +0200
+++ b/wp/wp-admin/includes/class-wp-plugins-list-table.php Fri Sep 05 18:40:08 2025 +0200
@@ -11,7 +11,6 @@
* Core class used to implement displaying installed plugins in a list table.
*
* @since 3.1.0
- * @access private
*
* @see WP_List_Table
*/
@@ -62,8 +61,7 @@
$this->show_autoupdates = wp_is_auto_update_enabled_for_type( 'plugin' )
&& current_user_can( 'update_plugins' )
- && ( ! is_multisite() || $this->screen->in_admin( 'network' ) )
- && ! in_array( $status, array( 'mustuse', 'dropins' ), true );
+ && ( ! is_multisite() || $this->screen->in_admin( 'network' ) );
}
/**
@@ -92,7 +90,8 @@
public function prepare_items() {
global $status, $plugins, $totals, $page, $orderby, $order, $s;
- wp_reset_vars( array( 'orderby', 'order' ) );
+ $orderby = ! empty( $_REQUEST['orderby'] ) ? sanitize_text_field( $_REQUEST['orderby'] ) : '';
+ $order = ! empty( $_REQUEST['order'] ) ? sanitize_text_field( $_REQUEST['order'] ) : '';
/**
* Filters the full array of plugins to list in the Plugins list table.
@@ -263,8 +262,10 @@
}
} elseif ( ( ! $screen->in_admin( 'network' ) && is_plugin_active( $plugin_file ) )
|| ( $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) ) {
- // On the non-network screen, populate the active list with plugins that are individually activated.
- // On the network admin screen, populate the active list with plugins that are network-activated.
+ /*
+ * On the non-network screen, populate the active list with plugins that are individually activated.
+ * On the network admin screen, populate the active list with plugins that are network-activated.
+ */
$plugins['active'][ $plugin_file ] = $plugin_data;
if ( ! $screen->in_admin( 'network' ) && is_plugin_paused( $plugin_file ) ) {
@@ -298,6 +299,15 @@
$plugins['search'] = array_filter( $plugins['all'], array( $this, '_search_callback' ) );
}
+ /**
+ * Filters the array of plugins for the list table.
+ *
+ * @since 6.3.0
+ *
+ * @param array[] $plugins An array of arrays of plugin data, keyed by context.
+ */
+ $plugins = apply_filters( 'plugins_list', $plugins );
+
$totals = array();
foreach ( $plugins as $type => $list ) {
$totals[ $type ] = count( $list );
@@ -404,7 +414,7 @@
global $plugins;
if ( ! empty( $_REQUEST['s'] ) ) {
- $s = esc_html( wp_unslash( $_REQUEST['s'] ) );
+ $s = esc_html( urldecode( wp_unslash( $_REQUEST['s'] ) ) );
/* translators: %s: Plugin search term. */
printf( __( 'No plugins found for: %s.' ), '<strong>' . $s . '</strong>' );
@@ -443,8 +453,8 @@
}
?>
<p class="search-box">
- <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
- <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...' ); ?>" />
+ <label for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?></label>
+ <input type="search" id="<?php echo esc_attr( $input_id ); ?>" class="wp-filter-search" name="s" value="<?php _admin_search_query(); ?>" />
<?php submit_button( $text, 'hide-if-js', '', false, array( 'id' => 'search-submit' ) ); ?>
</p>
<?php
@@ -452,7 +462,8 @@
/**
* @global string $status
- * @return array
+ *
+ * @return string[] Array of column titles keyed by their column name.
*/
public function get_columns() {
global $status;
@@ -463,7 +474,7 @@
'description' => __( 'Description' ),
);
- if ( $this->show_autoupdates ) {
+ if ( $this->show_autoupdates && ! in_array( $status, array( 'mustuse', 'dropins' ), true ) ) {
$columns['auto-updates'] = __( 'Automatic Updates' );
}
@@ -576,16 +587,15 @@
}
if ( 'search' !== $type ) {
- $status_links[ $type ] = sprintf(
- "<a href='%s'%s>%s</a>",
- add_query_arg( 'plugin_status', $type, 'plugins.php' ),
- ( $type === $status ) ? ' class="current" aria-current="page"' : '',
- sprintf( $text, number_format_i18n( $count ) )
+ $status_links[ $type ] = array(
+ 'url' => add_query_arg( 'plugin_status', $type, 'plugins.php' ),
+ 'label' => sprintf( $text, number_format_i18n( $count ) ),
+ 'current' => $type === $status,
);
}
}
- return $status_links;
+ return $this->get_views_links( $status_links );
}
/**
@@ -598,11 +608,11 @@
$actions = array();
if ( 'active' !== $status ) {
- $actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Activate' ) : __( 'Activate' );
+ $actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? _x( 'Network Activate', 'plugin' ) : _x( 'Activate', 'plugin' );
}
if ( 'inactive' !== $status && 'recent' !== $status ) {
- $actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Deactivate' ) : __( 'Deactivate' );
+ $actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? _x( 'Network Deactivate', 'plugin' ) : _x( 'Deactivate', 'plugin' );
}
if ( ! is_multisite() || $this->screen->in_admin( 'network' ) ) {
@@ -719,7 +729,7 @@
$suffix = 2;
while ( in_array( $plugin_id_attr, $plugin_id_attrs, true ) ) {
$plugin_id_attr = "$plugin_slug-$suffix";
- $suffix++;
+ ++$suffix;
}
$plugin_id_attrs[] = $plugin_id_attr;
@@ -745,6 +755,11 @@
$compatible_php = is_php_version_compatible( $requires_php );
$compatible_wp = is_wp_version_compatible( $requires_wp );
+ $has_dependents = WP_Plugin_Dependencies::has_dependents( $plugin_file );
+ $has_active_dependents = WP_Plugin_Dependencies::has_active_dependents( $plugin_file );
+ $has_unmet_dependencies = WP_Plugin_Dependencies::has_unmet_dependencies( $plugin_file );
+ $has_circular_dependency = WP_Plugin_Dependencies::has_circular_dependency( $plugin_file );
+
if ( 'mustuse' === $context ) {
$is_active = true;
} elseif ( 'dropins' === $context ) {
@@ -752,7 +767,7 @@
$plugin_name = $plugin_file;
if ( $plugin_file !== $plugin_data['Name'] ) {
- $plugin_name .= '<br/>' . $plugin_data['Name'];
+ $plugin_name .= '<br />' . $plugin_data['Name'];
}
if ( true === ( $dropins[ $plugin_file ][1] ) ) { // Doesn't require a constant.
@@ -787,26 +802,53 @@
if ( $screen->in_admin( 'network' ) ) {
if ( $is_active ) {
if ( current_user_can( 'manage_network_plugins' ) ) {
- $actions['deactivate'] = sprintf(
- '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
- wp_nonce_url( 'plugins.php?action=deactivate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'deactivate-plugin_' . $plugin_file ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Network Deactivate' )
- );
+ if ( $has_active_dependents ) {
+ $actions['deactivate'] = __( 'Deactivate' ) .
+ '<span class="screen-reader-text">' .
+ __( 'You cannot deactivate this plugin as other plugins require it.' ) .
+ '</span>';
+
+ } else {
+ $deactivate_url = 'plugins.php?action=deactivate' .
+ '&plugin=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['deactivate'] = sprintf(
+ '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
+ wp_nonce_url( $deactivate_url, 'deactivate-plugin_' . $plugin_file ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
+ _x( 'Network Deactivate', 'plugin' )
+ );
+ }
}
} else {
if ( current_user_can( 'manage_network_plugins' ) ) {
if ( $compatible_php && $compatible_wp ) {
- $actions['activate'] = sprintf(
- '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
- wp_nonce_url( 'plugins.php?action=activate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'activate-plugin_' . $plugin_file ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Network Activate' )
- );
+ if ( $has_unmet_dependencies ) {
+ $actions['activate'] = _x( 'Network Activate', 'plugin' ) .
+ '<span class="screen-reader-text">' .
+ __( 'You cannot activate this plugin as it has unmet requirements.' ) .
+ '</span>';
+ } else {
+ $activate_url = 'plugins.php?action=activate' .
+ '&plugin=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['activate'] = sprintf(
+ '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
+ wp_nonce_url( $activate_url, 'activate-plugin_' . $plugin_file ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
+ _x( 'Network Activate', 'plugin' )
+ );
+ }
} else {
$actions['activate'] = sprintf(
'<span>%s</span>',
@@ -816,14 +858,27 @@
}
if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
- $actions['delete'] = sprintf(
- '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
- wp_nonce_url( 'plugins.php?action=delete-selected&checked[]=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'bulk-plugins' ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Delete' )
- );
+ if ( $has_dependents && ! $has_circular_dependency ) {
+ $actions['delete'] = __( 'Delete' ) .
+ '<span class="screen-reader-text">' .
+ __( 'You cannot delete this plugin as other plugins require it.' ) .
+ '</span>';
+ } else {
+ $delete_url = 'plugins.php?action=delete-selected' .
+ '&checked[]=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['delete'] = sprintf(
+ '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
+ wp_nonce_url( $delete_url, 'bulk-plugins' ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
+ __( 'Delete' )
+ );
+ }
}
}
} else {
@@ -837,20 +892,39 @@
);
} elseif ( $is_active ) {
if ( current_user_can( 'deactivate_plugin', $plugin_file ) ) {
- $actions['deactivate'] = sprintf(
- '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
- wp_nonce_url( 'plugins.php?action=deactivate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'deactivate-plugin_' . $plugin_file ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Deactivate' )
- );
+ if ( $has_active_dependents ) {
+ $actions['deactivate'] = __( 'Deactivate' ) .
+ '<span class="screen-reader-text">' .
+ __( 'You cannot deactivate this plugin as other plugins depend on it.' ) .
+ '</span>';
+ } else {
+ $deactivate_url = 'plugins.php?action=deactivate' .
+ '&plugin=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['deactivate'] = sprintf(
+ '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
+ wp_nonce_url( $deactivate_url, 'deactivate-plugin_' . $plugin_file ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
+ __( 'Deactivate' )
+ );
+ }
}
if ( current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) {
+ $resume_url = 'plugins.php?action=resume' .
+ '&plugin=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
$actions['resume'] = sprintf(
'<a href="%s" id="resume-%s" class="resume-link" aria-label="%s">%s</a>',
- wp_nonce_url( 'plugins.php?action=resume&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'resume-plugin_' . $plugin_file ),
+ wp_nonce_url( $resume_url, 'resume-plugin_' . $plugin_file ),
esc_attr( $plugin_id_attr ),
/* translators: %s: Plugin name. */
esc_attr( sprintf( _x( 'Resume %s', 'plugin' ), $plugin_data['Name'] ) ),
@@ -860,14 +934,27 @@
} else {
if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
if ( $compatible_php && $compatible_wp ) {
- $actions['activate'] = sprintf(
- '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
- wp_nonce_url( 'plugins.php?action=activate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'activate-plugin_' . $plugin_file ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Activate' )
- );
+ if ( $has_unmet_dependencies ) {
+ $actions['activate'] = _x( 'Activate', 'plugin' ) .
+ '<span class="screen-reader-text">' .
+ __( 'You cannot activate this plugin as it has unmet requirements.' ) .
+ '</span>';
+ } else {
+ $activate_url = 'plugins.php?action=activate' .
+ '&plugin=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['activate'] = sprintf(
+ '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
+ wp_nonce_url( $activate_url, 'activate-plugin_' . $plugin_file ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
+ _x( 'Activate', 'plugin' )
+ );
+ }
} else {
$actions['activate'] = sprintf(
'<span>%s</span>',
@@ -877,14 +964,27 @@
}
if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
- $actions['delete'] = sprintf(
- '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
- wp_nonce_url( 'plugins.php?action=delete-selected&checked[]=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'bulk-plugins' ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Delete' )
- );
+ if ( $has_dependents && ! $has_circular_dependency ) {
+ $actions['delete'] = __( 'Delete' ) .
+ '<span class="screen-reader-text">' .
+ __( 'You cannot delete this plugin as other plugins require it.' ) .
+ '</span>';
+ } else {
+ $delete_url = 'plugins.php?action=delete-selected' .
+ '&checked[]=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['delete'] = sprintf(
+ '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
+ wp_nonce_url( $delete_url, 'bulk-plugins' ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
+ __( 'Delete' )
+ );
+ }
}
} // End if $is_active.
} // End if $screen->in_admin( 'network' ).
@@ -902,7 +1002,7 @@
* @param string[] $actions An array of plugin action links. By default this can include
* 'activate', 'deactivate', and 'delete'.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
- * @param array $plugin_data An array of plugin data. See `get_plugin_data()`
+ * @param array $plugin_data An array of plugin data. See get_plugin_data()
* and the {@see 'plugin_row_meta'} filter for the list
* of possible values.
* @param string $context The plugin context. By default this can include 'all',
@@ -922,7 +1022,7 @@
* @param string[] $actions An array of plugin action links. By default this can include
* 'activate', 'deactivate', and 'delete'.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
- * @param array $plugin_data An array of plugin data. See `get_plugin_data()`
+ * @param array $plugin_data An array of plugin data. See get_plugin_data()
* and the {@see 'plugin_row_meta'} filter for the list
* of possible values.
* @param string $context The plugin context. By default this can include 'all',
@@ -944,7 +1044,7 @@
* 'activate', 'deactivate', and 'delete'. With Multisite active
* this can also include 'network_active' and 'network_only' items.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
- * @param array $plugin_data An array of plugin data. See `get_plugin_data()`
+ * @param array $plugin_data An array of plugin data. See get_plugin_data()
* and the {@see 'plugin_row_meta'} filter for the list
* of possible values.
* @param string $context The plugin context. By default this can include 'all',
@@ -966,7 +1066,7 @@
* 'activate', 'deactivate', and 'delete'. With Multisite active
* this can also include 'network_active' and 'network_only' items.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
- * @param array $plugin_data An array of plugin data. See `get_plugin_data()`
+ * @param array $plugin_data An array of plugin data. See get_plugin_data()
* and the {@see 'plugin_row_meta'} filter for the list
* of possible values.
* @param string $context The plugin context. By default this can include 'all',
@@ -979,15 +1079,26 @@
$class = $is_active ? 'active' : 'inactive';
$checkbox_id = 'checkbox_' . md5( $plugin_file );
+ $disabled = '';
- if ( $restrict_network_active || $restrict_network_only || in_array( $status, array( 'mustuse', 'dropins' ), true ) || ! $compatible_php ) {
+ if ( $has_dependents || $has_unmet_dependencies ) {
+ $disabled = 'disabled';
+ }
+
+ if (
+ $restrict_network_active ||
+ $restrict_network_only ||
+ in_array( $status, array( 'mustuse', 'dropins' ), true ) ||
+ ! $compatible_php
+ ) {
$checkbox = '';
} else {
$checkbox = sprintf(
- '<label class="screen-reader-text" for="%1$s">%2$s</label>' .
- '<input type="checkbox" name="checked[]" value="%3$s" id="%1$s" />',
+ '<label class="label-covers-full-cell" for="%1$s">' .
+ '<span class="screen-reader-text">%2$s</span></label>' .
+ '<input type="checkbox" name="checked[]" value="%3$s" id="%1$s" ' . $disabled . '/>',
$checkbox_id,
- /* translators: %s: Plugin name. */
+ /* translators: Hidden accessibility text. %s: Plugin name. */
sprintf( __( 'Select %s' ), $plugin_data['Name'] ),
esc_attr( $plugin_file )
);
@@ -998,8 +1109,11 @@
$plugin_name = $plugin_data['Name'];
}
- if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] )
- || ! $compatible_php || ! $compatible_wp
+ if (
+ ! empty( $totals['upgrade'] ) &&
+ ! empty( $plugin_data['update'] ) ||
+ ! $compatible_php ||
+ ! $compatible_wp
) {
$class .= ' update';
}
@@ -1023,8 +1137,7 @@
list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
- $auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
- $available_updates = get_site_transient( 'update_plugins' );
+ $auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
foreach ( $columns as $column_name => $column_display_name ) {
$extra_classes = '';
@@ -1049,15 +1162,19 @@
<div class='$class second plugin-version-author-uri'>";
$plugin_meta = array();
+
if ( ! empty( $plugin_data['Version'] ) ) {
/* translators: %s: Plugin version number. */
$plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
}
+
if ( ! empty( $plugin_data['Author'] ) ) {
$author = $plugin_data['Author'];
+
if ( ! empty( $plugin_data['AuthorURI'] ) ) {
$author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
}
+
/* translators: %s: Plugin author name. */
$plugin_meta[] = sprintf( __( 'By %s' ), $author );
}
@@ -1141,6 +1258,24 @@
echo '</div>';
+ if ( $has_dependents ) {
+ $this->add_dependents_to_dependency_plugin_row( $plugin_file );
+ }
+
+ if ( WP_Plugin_Dependencies::has_dependencies( $plugin_file ) ) {
+ $this->add_dependencies_to_dependent_plugin_row( $plugin_file );
+ }
+
+ /**
+ * Fires after plugin row meta.
+ *
+ * @since 6.5.0
+ *
+ * @param string $plugin_file Refer to {@see 'plugin_row_meta'} filter.
+ * @param array $plugin_data Refer to {@see 'plugin_row_meta'} filter.
+ */
+ do_action( 'after_plugin_row_meta', $plugin_file, $plugin_data );
+
if ( $paused ) {
$notice_text = __( 'This plugin failed to load properly and is paused during recovery mode.' );
@@ -1156,7 +1291,7 @@
echo '</td>';
break;
case 'auto-updates':
- if ( ! $this->show_autoupdates ) {
+ if ( ! $this->show_autoupdates || in_array( $status, array( 'mustuse', 'dropins' ), true ) ) {
break;
}
@@ -1229,13 +1364,20 @@
* including toggle auto-update action links and
* time to next update.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
- * @param array $plugin_data An array of plugin data. See `get_plugin_data()`
+ * @param array $plugin_data An array of plugin data. See get_plugin_data()
* and the {@see 'plugin_row_meta'} filter for the list
* of possible values.
*/
echo apply_filters( 'plugin_auto_update_setting_html', $html, $plugin_file, $plugin_data );
- echo '<div class="notice notice-error notice-alt inline hidden"><p></p></div>';
+ wp_admin_notice(
+ '',
+ array(
+ 'type' => 'error',
+ 'additional_classes' => array( 'notice-alt', 'inline', 'hidden' ),
+ )
+ );
+
echo '</td>';
break;
@@ -1251,7 +1393,7 @@
*
* @param string $column_name Name of the column.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
- * @param array $plugin_data An array of plugin data. See `get_plugin_data()`
+ * @param array $plugin_data An array of plugin data. See get_plugin_data()
* and the {@see 'plugin_row_meta'} filter for the list
* of possible values.
*/
@@ -1265,58 +1407,65 @@
if ( ! $compatible_php || ! $compatible_wp ) {
printf(
- '<tr class="plugin-update-tr">' .
- '<td colspan="%s" class="plugin-update colspanchange">' .
- '<div class="update-message notice inline notice-error notice-alt"><p>',
+ '<tr class="plugin-update-tr"><td colspan="%s" class="plugin-update colspanchange">',
esc_attr( $this->get_column_count() )
);
+ $incompatible_message = '';
if ( ! $compatible_php && ! $compatible_wp ) {
- _e( 'This plugin does not work with your versions of WordPress and PHP.' );
+ $incompatible_message .= __( 'This plugin does not work with your versions of WordPress and PHP.' );
if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) {
- printf(
+ $incompatible_message .= sprintf(
/* translators: 1: URL to WordPress Updates screen, 2: URL to Update PHP page. */
' ' . __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.' ),
self_admin_url( 'update-core.php' ),
esc_url( wp_get_update_php_url() )
);
- wp_update_php_annotation( '</p><p><em>', '</em>' );
+ $incompatible_message .= wp_update_php_annotation( '</p><p><em>', '</em>', false );
} elseif ( current_user_can( 'update_core' ) ) {
- printf(
+ $incompatible_message .= sprintf(
/* translators: %s: URL to WordPress Updates screen. */
' ' . __( '<a href="%s">Please update WordPress</a>.' ),
self_admin_url( 'update-core.php' )
);
} elseif ( current_user_can( 'update_php' ) ) {
- printf(
+ $incompatible_message .= sprintf(
/* translators: %s: URL to Update PHP page. */
' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
esc_url( wp_get_update_php_url() )
);
- wp_update_php_annotation( '</p><p><em>', '</em>' );
+ $incompatible_message .= wp_update_php_annotation( '</p><p><em>', '</em>', false );
}
} elseif ( ! $compatible_wp ) {
- _e( 'This plugin does not work with your version of WordPress.' );
+ $incompatible_message .= __( 'This plugin does not work with your version of WordPress.' );
if ( current_user_can( 'update_core' ) ) {
- printf(
+ $incompatible_message .= sprintf(
/* translators: %s: URL to WordPress Updates screen. */
' ' . __( '<a href="%s">Please update WordPress</a>.' ),
self_admin_url( 'update-core.php' )
);
}
} elseif ( ! $compatible_php ) {
- _e( 'This plugin does not work with your version of PHP.' );
+ $incompatible_message .= __( 'This plugin does not work with your version of PHP.' );
if ( current_user_can( 'update_php' ) ) {
- printf(
+ $incompatible_message .= sprintf(
/* translators: %s: URL to Update PHP page. */
' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
esc_url( wp_get_update_php_url() )
);
- wp_update_php_annotation( '</p><p><em>', '</em>' );
+ $incompatible_message .= wp_update_php_annotation( '</p><p><em>', '</em>', false );
}
}
- echo '</p></div></td></tr>';
+ wp_admin_notice(
+ $incompatible_message,
+ array(
+ 'type' => 'error',
+ 'additional_classes' => array( 'notice-alt', 'inline', 'update-message' ),
+ )
+ );
+
+ echo '</td></tr>';
}
/**
@@ -1327,7 +1476,7 @@
* to possible values for `$status`.
*
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
- * @param array $plugin_data An array of plugin data. See `get_plugin_data()`
+ * @param array $plugin_data An array of plugin data. See get_plugin_data()
* and the {@see 'plugin_row_meta'} filter for the list
* of possible values.
* @param string $status Status filter currently applied to the plugin list.
@@ -1348,7 +1497,7 @@
* to possible values for `$status`.
*
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
- * @param array $plugin_data An array of plugin data. See `get_plugin_data()`
+ * @param array $plugin_data An array of plugin data. See get_plugin_data()
* and the {@see 'plugin_row_meta'} filter for the list
* of possible values.
* @param string $status Status filter currently applied to the plugin list.
@@ -1369,4 +1518,140 @@
protected function get_primary_column_name() {
return 'name';
}
+
+ /**
+ * Prints a list of other plugins that depend on the plugin.
+ *
+ * @since 6.5.0
+ *
+ * @param string $dependency The dependency's filepath, relative to the plugins directory.
+ */
+ protected function add_dependents_to_dependency_plugin_row( $dependency ) {
+ $dependent_names = WP_Plugin_Dependencies::get_dependent_names( $dependency );
+
+ if ( empty( $dependent_names ) ) {
+ return;
+ }
+
+ $dependency_note = __( 'Note: This plugin cannot be deactivated or deleted until the plugins that require it are deactivated or deleted.' );
+
+ $comma = wp_get_list_item_separator();
+ $required_by = sprintf(
+ /* translators: %s: List of dependencies. */
+ __( '<strong>Required by:</strong> %s' ),
+ implode( $comma, $dependent_names )
+ );
+
+ printf(
+ '<div class="required-by"><p>%1$s</p><p>%2$s</p></div>',
+ $required_by,
+ $dependency_note
+ );
+ }
+
+ /**
+ * Prints a list of other plugins that the plugin depends on.
+ *
+ * @since 6.5.0
+ *
+ * @param string $dependent The dependent plugin's filepath, relative to the plugins directory.
+ */
+ protected function add_dependencies_to_dependent_plugin_row( $dependent ) {
+ $dependency_names = WP_Plugin_Dependencies::get_dependency_names( $dependent );
+
+ if ( array() === $dependency_names ) {
+ return;
+ }
+
+ $links = array();
+ foreach ( $dependency_names as $slug => $name ) {
+ $links[] = $this->get_dependency_view_details_link( $name, $slug );
+ }
+
+ $is_active = is_multisite() ? is_plugin_active_for_network( $dependent ) : is_plugin_active( $dependent );
+ $comma = wp_get_list_item_separator();
+ $requires = sprintf(
+ /* translators: %s: List of dependency names. */
+ __( '<strong>Requires:</strong> %s' ),
+ implode( $comma, $links )
+ );
+
+ $notice = '';
+ $error_message = '';
+ if ( WP_Plugin_Dependencies::has_unmet_dependencies( $dependent ) ) {
+ if ( $is_active ) {
+ $error_message = __( 'This plugin is active but may not function correctly because required plugins are missing or inactive.' );
+ } else {
+ $error_message = __( 'This plugin cannot be activated because required plugins are missing or inactive.' );
+ }
+ $notice = wp_get_admin_notice(
+ $error_message,
+ array(
+ 'type' => 'error',
+ 'additional_classes' => array( 'inline', 'notice-alt' ),
+ )
+ );
+ }
+
+ printf(
+ '<div class="requires"><p>%1$s</p><p>%2$s</p></div>',
+ $requires,
+ $notice
+ );
+ }
+
+ /**
+ * Returns a 'View details' like link for a dependency.
+ *
+ * @since 6.5.0
+ *
+ * @param string $name The dependency's name.
+ * @param string $slug The dependency's slug.
+ * @return string A 'View details' link for the dependency.
+ */
+ protected function get_dependency_view_details_link( $name, $slug ) {
+ $dependency_data = WP_Plugin_Dependencies::get_dependency_data( $slug );
+
+ if ( false === $dependency_data
+ || $name === $slug
+ || $name !== $dependency_data['name']
+ || empty( $dependency_data['version'] )
+ ) {
+ return $name;
+ }
+
+ return $this->get_view_details_link( $name, $slug );
+ }
+
+ /**
+ * Returns a 'View details' link for the plugin.
+ *
+ * @since 6.5.0
+ *
+ * @param string $name The plugin's name.
+ * @param string $slug The plugin's slug.
+ * @return string A 'View details' link for the plugin.
+ */
+ protected function get_view_details_link( $name, $slug ) {
+ $url = add_query_arg(
+ array(
+ 'tab' => 'plugin-information',
+ 'plugin' => $slug,
+ 'TB_iframe' => 'true',
+ 'width' => '600',
+ 'height' => '550',
+ ),
+ network_admin_url( 'plugin-install.php' )
+ );
+
+ $name_attr = esc_attr( $name );
+ return sprintf(
+ "<a href='%s' class='thickbox open-plugin-details-modal' aria-label='%s' data-title='%s'>%s</a>",
+ esc_url( $url ),
+ /* translators: %s: Plugin name. */
+ sprintf( __( 'More information about %s' ), $name_attr ),
+ $name_attr,
+ esc_html( $name )
+ );
+ }
}