wp/wp-admin/includes/class-wp-plugins-list-table.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
     9 
     9 
    10 /**
    10 /**
    11  * Core class used to implement displaying installed plugins in a list table.
    11  * Core class used to implement displaying installed plugins in a list table.
    12  *
    12  *
    13  * @since 3.1.0
    13  * @since 3.1.0
    14  * @access private
       
    15  *
    14  *
    16  * @see WP_List_Table
    15  * @see WP_List_Table
    17  */
    16  */
    18 class WP_Plugins_List_Table extends WP_List_Table {
    17 class WP_Plugins_List_Table extends WP_List_Table {
    19 	/**
    18 	/**
    60 
    59 
    61 		$page = $this->get_pagenum();
    60 		$page = $this->get_pagenum();
    62 
    61 
    63 		$this->show_autoupdates = wp_is_auto_update_enabled_for_type( 'plugin' )
    62 		$this->show_autoupdates = wp_is_auto_update_enabled_for_type( 'plugin' )
    64 			&& current_user_can( 'update_plugins' )
    63 			&& current_user_can( 'update_plugins' )
    65 			&& ( ! is_multisite() || $this->screen->in_admin( 'network' ) )
    64 			&& ( ! is_multisite() || $this->screen->in_admin( 'network' ) );
    66 			&& ! in_array( $status, array( 'mustuse', 'dropins' ), true );
       
    67 	}
    65 	}
    68 
    66 
    69 	/**
    67 	/**
    70 	 * @return array
    68 	 * @return array
    71 	 */
    69 	 */
    90 	 * @global string $s
    88 	 * @global string $s
    91 	 */
    89 	 */
    92 	public function prepare_items() {
    90 	public function prepare_items() {
    93 		global $status, $plugins, $totals, $page, $orderby, $order, $s;
    91 		global $status, $plugins, $totals, $page, $orderby, $order, $s;
    94 
    92 
    95 		wp_reset_vars( array( 'orderby', 'order' ) );
    93 		$orderby = ! empty( $_REQUEST['orderby'] ) ? sanitize_text_field( $_REQUEST['orderby'] ) : '';
       
    94 		$order   = ! empty( $_REQUEST['order'] ) ? sanitize_text_field( $_REQUEST['order'] ) : '';
    96 
    95 
    97 		/**
    96 		/**
    98 		 * Filters the full array of plugins to list in the Plugins list table.
    97 		 * Filters the full array of plugins to list in the Plugins list table.
    99 		 *
    98 		 *
   100 		 * @since 3.0.0
    99 		 * @since 3.0.0
   261 					// On the non-network screen, filter out network-active plugins.
   260 					// On the non-network screen, filter out network-active plugins.
   262 					unset( $plugins['all'][ $plugin_file ] );
   261 					unset( $plugins['all'][ $plugin_file ] );
   263 				}
   262 				}
   264 			} elseif ( ( ! $screen->in_admin( 'network' ) && is_plugin_active( $plugin_file ) )
   263 			} elseif ( ( ! $screen->in_admin( 'network' ) && is_plugin_active( $plugin_file ) )
   265 				|| ( $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) ) {
   264 				|| ( $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) ) {
   266 				// On the non-network screen, populate the active list with plugins that are individually activated.
   265 				/*
   267 				// On the network admin screen, populate the active list with plugins that are network-activated.
   266 				 * On the non-network screen, populate the active list with plugins that are individually activated.
       
   267 				 * On the network admin screen, populate the active list with plugins that are network-activated.
       
   268 				 */
   268 				$plugins['active'][ $plugin_file ] = $plugin_data;
   269 				$plugins['active'][ $plugin_file ] = $plugin_data;
   269 
   270 
   270 				if ( ! $screen->in_admin( 'network' ) && is_plugin_paused( $plugin_file ) ) {
   271 				if ( ! $screen->in_admin( 'network' ) && is_plugin_paused( $plugin_file ) ) {
   271 					$plugins['paused'][ $plugin_file ] = $plugin_data;
   272 					$plugins['paused'][ $plugin_file ] = $plugin_data;
   272 				}
   273 				}
   296 		if ( strlen( $s ) ) {
   297 		if ( strlen( $s ) ) {
   297 			$status            = 'search';
   298 			$status            = 'search';
   298 			$plugins['search'] = array_filter( $plugins['all'], array( $this, '_search_callback' ) );
   299 			$plugins['search'] = array_filter( $plugins['all'], array( $this, '_search_callback' ) );
   299 		}
   300 		}
   300 
   301 
       
   302 		/**
       
   303 		 * Filters the array of plugins for the list table.
       
   304 		 *
       
   305 		 * @since 6.3.0
       
   306 		 *
       
   307 		 * @param array[] $plugins An array of arrays of plugin data, keyed by context.
       
   308 		 */
       
   309 		$plugins = apply_filters( 'plugins_list', $plugins );
       
   310 
   301 		$totals = array();
   311 		$totals = array();
   302 		foreach ( $plugins as $type => $list ) {
   312 		foreach ( $plugins as $type => $list ) {
   303 			$totals[ $type ] = count( $list );
   313 			$totals[ $type ] = count( $list );
   304 		}
   314 		}
   305 
   315 
   402 	 */
   412 	 */
   403 	public function no_items() {
   413 	public function no_items() {
   404 		global $plugins;
   414 		global $plugins;
   405 
   415 
   406 		if ( ! empty( $_REQUEST['s'] ) ) {
   416 		if ( ! empty( $_REQUEST['s'] ) ) {
   407 			$s = esc_html( wp_unslash( $_REQUEST['s'] ) );
   417 			$s = esc_html( urldecode( wp_unslash( $_REQUEST['s'] ) ) );
   408 
   418 
   409 			/* translators: %s: Plugin search term. */
   419 			/* translators: %s: Plugin search term. */
   410 			printf( __( 'No plugins found for: %s.' ), '<strong>' . $s . '</strong>' );
   420 			printf( __( 'No plugins found for: %s.' ), '<strong>' . $s . '</strong>' );
   411 
   421 
   412 			// We assume that somebody who can install plugins in multisite is experienced enough to not need this helper link.
   422 			// We assume that somebody who can install plugins in multisite is experienced enough to not need this helper link.
   441 		if ( ! empty( $_REQUEST['order'] ) ) {
   451 		if ( ! empty( $_REQUEST['order'] ) ) {
   442 			echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
   452 			echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
   443 		}
   453 		}
   444 		?>
   454 		?>
   445 		<p class="search-box">
   455 		<p class="search-box">
   446 			<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
   456 			<label for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?></label>
   447 			<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...' ); ?>" />
   457 			<input type="search" id="<?php echo esc_attr( $input_id ); ?>" class="wp-filter-search" name="s" value="<?php _admin_search_query(); ?>" />
   448 			<?php submit_button( $text, 'hide-if-js', '', false, array( 'id' => 'search-submit' ) ); ?>
   458 			<?php submit_button( $text, 'hide-if-js', '', false, array( 'id' => 'search-submit' ) ); ?>
   449 		</p>
   459 		</p>
   450 		<?php
   460 		<?php
   451 	}
   461 	}
   452 
   462 
   453 	/**
   463 	/**
   454 	 * @global string $status
   464 	 * @global string $status
   455 	 * @return array
   465 	 *
       
   466 	 * @return string[] Array of column titles keyed by their column name.
   456 	 */
   467 	 */
   457 	public function get_columns() {
   468 	public function get_columns() {
   458 		global $status;
   469 		global $status;
   459 
   470 
   460 		$columns = array(
   471 		$columns = array(
   461 			'cb'          => ! in_array( $status, array( 'mustuse', 'dropins' ), true ) ? '<input type="checkbox" />' : '',
   472 			'cb'          => ! in_array( $status, array( 'mustuse', 'dropins' ), true ) ? '<input type="checkbox" />' : '',
   462 			'name'        => __( 'Plugin' ),
   473 			'name'        => __( 'Plugin' ),
   463 			'description' => __( 'Description' ),
   474 			'description' => __( 'Description' ),
   464 		);
   475 		);
   465 
   476 
   466 		if ( $this->show_autoupdates ) {
   477 		if ( $this->show_autoupdates && ! in_array( $status, array( 'mustuse', 'dropins' ), true ) ) {
   467 			$columns['auto-updates'] = __( 'Automatic Updates' );
   478 			$columns['auto-updates'] = __( 'Automatic Updates' );
   468 		}
   479 		}
   469 
   480 
   470 		return $columns;
   481 		return $columns;
   471 	}
   482 	}
   574 					);
   585 					);
   575 					break;
   586 					break;
   576 			}
   587 			}
   577 
   588 
   578 			if ( 'search' !== $type ) {
   589 			if ( 'search' !== $type ) {
   579 				$status_links[ $type ] = sprintf(
   590 				$status_links[ $type ] = array(
   580 					"<a href='%s'%s>%s</a>",
   591 					'url'     => add_query_arg( 'plugin_status', $type, 'plugins.php' ),
   581 					add_query_arg( 'plugin_status', $type, 'plugins.php' ),
   592 					'label'   => sprintf( $text, number_format_i18n( $count ) ),
   582 					( $type === $status ) ? ' class="current" aria-current="page"' : '',
   593 					'current' => $type === $status,
   583 					sprintf( $text, number_format_i18n( $count ) )
       
   584 				);
   594 				);
   585 			}
   595 			}
   586 		}
   596 		}
   587 
   597 
   588 		return $status_links;
   598 		return $this->get_views_links( $status_links );
   589 	}
   599 	}
   590 
   600 
   591 	/**
   601 	/**
   592 	 * @global string $status
   602 	 * @global string $status
   593 	 * @return array
   603 	 * @return array
   596 		global $status;
   606 		global $status;
   597 
   607 
   598 		$actions = array();
   608 		$actions = array();
   599 
   609 
   600 		if ( 'active' !== $status ) {
   610 		if ( 'active' !== $status ) {
   601 			$actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Activate' ) : __( 'Activate' );
   611 			$actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? _x( 'Network Activate', 'plugin' ) : _x( 'Activate', 'plugin' );
   602 		}
   612 		}
   603 
   613 
   604 		if ( 'inactive' !== $status && 'recent' !== $status ) {
   614 		if ( 'inactive' !== $status && 'recent' !== $status ) {
   605 			$actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Deactivate' ) : __( 'Deactivate' );
   615 			$actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? _x( 'Network Deactivate', 'plugin' ) : _x( 'Deactivate', 'plugin' );
   606 		}
   616 		}
   607 
   617 
   608 		if ( ! is_multisite() || $this->screen->in_admin( 'network' ) ) {
   618 		if ( ! is_multisite() || $this->screen->in_admin( 'network' ) ) {
   609 			if ( current_user_can( 'update_plugins' ) ) {
   619 			if ( current_user_can( 'update_plugins' ) ) {
   610 				$actions['update-selected'] = __( 'Update' );
   620 				$actions['update-selected'] = __( 'Update' );
   717 
   727 
   718 		// Ensure the ID attribute is unique.
   728 		// Ensure the ID attribute is unique.
   719 		$suffix = 2;
   729 		$suffix = 2;
   720 		while ( in_array( $plugin_id_attr, $plugin_id_attrs, true ) ) {
   730 		while ( in_array( $plugin_id_attr, $plugin_id_attrs, true ) ) {
   721 			$plugin_id_attr = "$plugin_slug-$suffix";
   731 			$plugin_id_attr = "$plugin_slug-$suffix";
   722 			$suffix++;
   732 			++$suffix;
   723 		}
   733 		}
   724 
   734 
   725 		$plugin_id_attrs[] = $plugin_id_attr;
   735 		$plugin_id_attrs[] = $plugin_id_attr;
   726 
   736 
   727 		$context = $status;
   737 		$context = $status;
   743 		$requires_wp  = isset( $plugin_data['RequiresWP'] ) ? $plugin_data['RequiresWP'] : null;
   753 		$requires_wp  = isset( $plugin_data['RequiresWP'] ) ? $plugin_data['RequiresWP'] : null;
   744 
   754 
   745 		$compatible_php = is_php_version_compatible( $requires_php );
   755 		$compatible_php = is_php_version_compatible( $requires_php );
   746 		$compatible_wp  = is_wp_version_compatible( $requires_wp );
   756 		$compatible_wp  = is_wp_version_compatible( $requires_wp );
   747 
   757 
       
   758 		$has_dependents          = WP_Plugin_Dependencies::has_dependents( $plugin_file );
       
   759 		$has_active_dependents   = WP_Plugin_Dependencies::has_active_dependents( $plugin_file );
       
   760 		$has_unmet_dependencies  = WP_Plugin_Dependencies::has_unmet_dependencies( $plugin_file );
       
   761 		$has_circular_dependency = WP_Plugin_Dependencies::has_circular_dependency( $plugin_file );
       
   762 
   748 		if ( 'mustuse' === $context ) {
   763 		if ( 'mustuse' === $context ) {
   749 			$is_active = true;
   764 			$is_active = true;
   750 		} elseif ( 'dropins' === $context ) {
   765 		} elseif ( 'dropins' === $context ) {
   751 			$dropins     = _get_dropins();
   766 			$dropins     = _get_dropins();
   752 			$plugin_name = $plugin_file;
   767 			$plugin_name = $plugin_file;
   753 
   768 
   754 			if ( $plugin_file !== $plugin_data['Name'] ) {
   769 			if ( $plugin_file !== $plugin_data['Name'] ) {
   755 				$plugin_name .= '<br/>' . $plugin_data['Name'];
   770 				$plugin_name .= '<br />' . $plugin_data['Name'];
   756 			}
   771 			}
   757 
   772 
   758 			if ( true === ( $dropins[ $plugin_file ][1] ) ) { // Doesn't require a constant.
   773 			if ( true === ( $dropins[ $plugin_file ][1] ) ) { // Doesn't require a constant.
   759 				$is_active   = true;
   774 				$is_active   = true;
   760 				$description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
   775 				$description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
   785 			}
   800 			}
   786 
   801 
   787 			if ( $screen->in_admin( 'network' ) ) {
   802 			if ( $screen->in_admin( 'network' ) ) {
   788 				if ( $is_active ) {
   803 				if ( $is_active ) {
   789 					if ( current_user_can( 'manage_network_plugins' ) ) {
   804 					if ( current_user_can( 'manage_network_plugins' ) ) {
   790 						$actions['deactivate'] = sprintf(
   805 						if ( $has_active_dependents ) {
   791 							'<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
   806 							$actions['deactivate'] = __( 'Deactivate' ) .
   792 							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 ),
   807 								'<span class="screen-reader-text">' .
   793 							esc_attr( $plugin_id_attr ),
   808 								__( 'You cannot deactivate this plugin as other plugins require it.' ) .
   794 							/* translators: %s: Plugin name. */
   809 								'</span>';
   795 							esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
   810 
   796 							__( 'Network Deactivate' )
   811 						} else {
   797 						);
   812 							$deactivate_url = 'plugins.php?action=deactivate' .
       
   813 								'&amp;plugin=' . urlencode( $plugin_file ) .
       
   814 								'&amp;plugin_status=' . $context .
       
   815 								'&amp;paged=' . $page .
       
   816 								'&amp;s=' . $s;
       
   817 
       
   818 							$actions['deactivate'] = sprintf(
       
   819 								'<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
       
   820 								wp_nonce_url( $deactivate_url, 'deactivate-plugin_' . $plugin_file ),
       
   821 								esc_attr( $plugin_id_attr ),
       
   822 								/* translators: %s: Plugin name. */
       
   823 								esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
       
   824 								_x( 'Network Deactivate', 'plugin' )
       
   825 							);
       
   826 						}
   798 					}
   827 					}
   799 				} else {
   828 				} else {
   800 					if ( current_user_can( 'manage_network_plugins' ) ) {
   829 					if ( current_user_can( 'manage_network_plugins' ) ) {
   801 						if ( $compatible_php && $compatible_wp ) {
   830 						if ( $compatible_php && $compatible_wp ) {
   802 							$actions['activate'] = sprintf(
   831 							if ( $has_unmet_dependencies ) {
   803 								'<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
   832 								$actions['activate'] = _x( 'Network Activate', 'plugin' ) .
   804 								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 ),
   833 									'<span class="screen-reader-text">' .
   805 								esc_attr( $plugin_id_attr ),
   834 									__( 'You cannot activate this plugin as it has unmet requirements.' ) .
   806 								/* translators: %s: Plugin name. */
   835 									'</span>';
   807 								esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
   836 							} else {
   808 								__( 'Network Activate' )
   837 								$activate_url = 'plugins.php?action=activate' .
   809 							);
   838 									'&amp;plugin=' . urlencode( $plugin_file ) .
       
   839 									'&amp;plugin_status=' . $context .
       
   840 									'&amp;paged=' . $page .
       
   841 									'&amp;s=' . $s;
       
   842 
       
   843 								$actions['activate'] = sprintf(
       
   844 									'<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
       
   845 									wp_nonce_url( $activate_url, 'activate-plugin_' . $plugin_file ),
       
   846 									esc_attr( $plugin_id_attr ),
       
   847 									/* translators: %s: Plugin name. */
       
   848 									esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
       
   849 									_x( 'Network Activate', 'plugin' )
       
   850 								);
       
   851 							}
   810 						} else {
   852 						} else {
   811 							$actions['activate'] = sprintf(
   853 							$actions['activate'] = sprintf(
   812 								'<span>%s</span>',
   854 								'<span>%s</span>',
   813 								_x( 'Cannot Activate', 'plugin' )
   855 								_x( 'Cannot Activate', 'plugin' )
   814 							);
   856 							);
   815 						}
   857 						}
   816 					}
   858 					}
   817 
   859 
   818 					if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
   860 					if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
   819 						$actions['delete'] = sprintf(
   861 						if ( $has_dependents && ! $has_circular_dependency ) {
   820 							'<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
   862 							$actions['delete'] = __( 'Delete' ) .
   821 							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' ),
   863 								'<span class="screen-reader-text">' .
   822 							esc_attr( $plugin_id_attr ),
   864 								__( 'You cannot delete this plugin as other plugins require it.' ) .
   823 							/* translators: %s: Plugin name. */
   865 								'</span>';
   824 							esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
   866 						} else {
   825 							__( 'Delete' )
   867 							$delete_url = 'plugins.php?action=delete-selected' .
   826 						);
   868 								'&amp;checked[]=' . urlencode( $plugin_file ) .
       
   869 								'&amp;plugin_status=' . $context .
       
   870 								'&amp;paged=' . $page .
       
   871 								'&amp;s=' . $s;
       
   872 
       
   873 							$actions['delete'] = sprintf(
       
   874 								'<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
       
   875 								wp_nonce_url( $delete_url, 'bulk-plugins' ),
       
   876 								esc_attr( $plugin_id_attr ),
       
   877 								/* translators: %s: Plugin name. */
       
   878 								esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
       
   879 								__( 'Delete' )
       
   880 							);
       
   881 						}
   827 					}
   882 					}
   828 				}
   883 				}
   829 			} else {
   884 			} else {
   830 				if ( $restrict_network_active ) {
   885 				if ( $restrict_network_active ) {
   831 					$actions = array(
   886 					$actions = array(
   835 					$actions = array(
   890 					$actions = array(
   836 						'network_only' => __( 'Network Only' ),
   891 						'network_only' => __( 'Network Only' ),
   837 					);
   892 					);
   838 				} elseif ( $is_active ) {
   893 				} elseif ( $is_active ) {
   839 					if ( current_user_can( 'deactivate_plugin', $plugin_file ) ) {
   894 					if ( current_user_can( 'deactivate_plugin', $plugin_file ) ) {
   840 						$actions['deactivate'] = sprintf(
   895 						if ( $has_active_dependents ) {
   841 							'<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
   896 							$actions['deactivate'] = __( 'Deactivate' ) .
   842 							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 ),
   897 								'<span class="screen-reader-text">' .
   843 							esc_attr( $plugin_id_attr ),
   898 								__( 'You cannot deactivate this plugin as other plugins depend on it.' ) .
   844 							/* translators: %s: Plugin name. */
   899 								'</span>';
   845 							esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
   900 						} else {
   846 							__( 'Deactivate' )
   901 							$deactivate_url = 'plugins.php?action=deactivate' .
   847 						);
   902 								'&amp;plugin=' . urlencode( $plugin_file ) .
       
   903 								'&amp;plugin_status=' . $context .
       
   904 								'&amp;paged=' . $page .
       
   905 								'&amp;s=' . $s;
       
   906 
       
   907 							$actions['deactivate'] = sprintf(
       
   908 								'<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
       
   909 								wp_nonce_url( $deactivate_url, 'deactivate-plugin_' . $plugin_file ),
       
   910 								esc_attr( $plugin_id_attr ),
       
   911 								/* translators: %s: Plugin name. */
       
   912 								esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
       
   913 								__( 'Deactivate' )
       
   914 							);
       
   915 						}
   848 					}
   916 					}
   849 
   917 
   850 					if ( current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) {
   918 					if ( current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) {
       
   919 						$resume_url = 'plugins.php?action=resume' .
       
   920 							'&amp;plugin=' . urlencode( $plugin_file ) .
       
   921 							'&amp;plugin_status=' . $context .
       
   922 							'&amp;paged=' . $page .
       
   923 							'&amp;s=' . $s;
       
   924 
   851 						$actions['resume'] = sprintf(
   925 						$actions['resume'] = sprintf(
   852 							'<a href="%s" id="resume-%s" class="resume-link" aria-label="%s">%s</a>',
   926 							'<a href="%s" id="resume-%s" class="resume-link" aria-label="%s">%s</a>',
   853 							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 ),
   927 							wp_nonce_url( $resume_url, 'resume-plugin_' . $plugin_file ),
   854 							esc_attr( $plugin_id_attr ),
   928 							esc_attr( $plugin_id_attr ),
   855 							/* translators: %s: Plugin name. */
   929 							/* translators: %s: Plugin name. */
   856 							esc_attr( sprintf( _x( 'Resume %s', 'plugin' ), $plugin_data['Name'] ) ),
   930 							esc_attr( sprintf( _x( 'Resume %s', 'plugin' ), $plugin_data['Name'] ) ),
   857 							__( 'Resume' )
   931 							__( 'Resume' )
   858 						);
   932 						);
   859 					}
   933 					}
   860 				} else {
   934 				} else {
   861 					if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
   935 					if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
   862 						if ( $compatible_php && $compatible_wp ) {
   936 						if ( $compatible_php && $compatible_wp ) {
   863 							$actions['activate'] = sprintf(
   937 							if ( $has_unmet_dependencies ) {
   864 								'<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
   938 								$actions['activate'] = _x( 'Activate', 'plugin' ) .
   865 								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 ),
   939 									'<span class="screen-reader-text">' .
   866 								esc_attr( $plugin_id_attr ),
   940 									__( 'You cannot activate this plugin as it has unmet requirements.' ) .
   867 								/* translators: %s: Plugin name. */
   941 									'</span>';
   868 								esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
   942 							} else {
   869 								__( 'Activate' )
   943 								$activate_url = 'plugins.php?action=activate' .
   870 							);
   944 									'&amp;plugin=' . urlencode( $plugin_file ) .
       
   945 									'&amp;plugin_status=' . $context .
       
   946 									'&amp;paged=' . $page .
       
   947 									'&amp;s=' . $s;
       
   948 
       
   949 								$actions['activate'] = sprintf(
       
   950 									'<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
       
   951 									wp_nonce_url( $activate_url, 'activate-plugin_' . $plugin_file ),
       
   952 									esc_attr( $plugin_id_attr ),
       
   953 									/* translators: %s: Plugin name. */
       
   954 									esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
       
   955 									_x( 'Activate', 'plugin' )
       
   956 								);
       
   957 							}
   871 						} else {
   958 						} else {
   872 							$actions['activate'] = sprintf(
   959 							$actions['activate'] = sprintf(
   873 								'<span>%s</span>',
   960 								'<span>%s</span>',
   874 								_x( 'Cannot Activate', 'plugin' )
   961 								_x( 'Cannot Activate', 'plugin' )
   875 							);
   962 							);
   876 						}
   963 						}
   877 					}
   964 					}
   878 
   965 
   879 					if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
   966 					if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
   880 						$actions['delete'] = sprintf(
   967 						if ( $has_dependents && ! $has_circular_dependency ) {
   881 							'<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
   968 							$actions['delete'] = __( 'Delete' ) .
   882 							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' ),
   969 								'<span class="screen-reader-text">' .
   883 							esc_attr( $plugin_id_attr ),
   970 								__( 'You cannot delete this plugin as other plugins require it.' ) .
   884 							/* translators: %s: Plugin name. */
   971 								'</span>';
   885 							esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
   972 						} else {
   886 							__( 'Delete' )
   973 							$delete_url = 'plugins.php?action=delete-selected' .
   887 						);
   974 								'&amp;checked[]=' . urlencode( $plugin_file ) .
       
   975 								'&amp;plugin_status=' . $context .
       
   976 								'&amp;paged=' . $page .
       
   977 								'&amp;s=' . $s;
       
   978 
       
   979 							$actions['delete'] = sprintf(
       
   980 								'<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
       
   981 								wp_nonce_url( $delete_url, 'bulk-plugins' ),
       
   982 								esc_attr( $plugin_id_attr ),
       
   983 								/* translators: %s: Plugin name. */
       
   984 								esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
       
   985 								__( 'Delete' )
       
   986 							);
       
   987 						}
   888 					}
   988 					}
   889 				} // End if $is_active.
   989 				} // End if $is_active.
   890 			} // End if $screen->in_admin( 'network' ).
   990 			} // End if $screen->in_admin( 'network' ).
   891 		} // End if $context.
   991 		} // End if $context.
   892 
   992 
   900 			 * @since 3.1.0
  1000 			 * @since 3.1.0
   901 			 *
  1001 			 *
   902 			 * @param string[] $actions     An array of plugin action links. By default this can include
  1002 			 * @param string[] $actions     An array of plugin action links. By default this can include
   903 			 *                              'activate', 'deactivate', and 'delete'.
  1003 			 *                              'activate', 'deactivate', and 'delete'.
   904 			 * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
  1004 			 * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
   905 			 * @param array    $plugin_data An array of plugin data. See `get_plugin_data()`
  1005 			 * @param array    $plugin_data An array of plugin data. See get_plugin_data()
   906 			 *                              and the {@see 'plugin_row_meta'} filter for the list
  1006 			 *                              and the {@see 'plugin_row_meta'} filter for the list
   907 			 *                              of possible values.
  1007 			 *                              of possible values.
   908 			 * @param string   $context     The plugin context. By default this can include 'all',
  1008 			 * @param string   $context     The plugin context. By default this can include 'all',
   909 			 *                              'active', 'inactive', 'recently_activated', 'upgrade',
  1009 			 *                              'active', 'inactive', 'recently_activated', 'upgrade',
   910 			 *                              'mustuse', 'dropins', and 'search'.
  1010 			 *                              'mustuse', 'dropins', and 'search'.
   920 			 * @since 3.1.0
  1020 			 * @since 3.1.0
   921 			 *
  1021 			 *
   922 			 * @param string[] $actions     An array of plugin action links. By default this can include
  1022 			 * @param string[] $actions     An array of plugin action links. By default this can include
   923 			 *                              'activate', 'deactivate', and 'delete'.
  1023 			 *                              'activate', 'deactivate', and 'delete'.
   924 			 * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
  1024 			 * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
   925 			 * @param array    $plugin_data An array of plugin data. See `get_plugin_data()`
  1025 			 * @param array    $plugin_data An array of plugin data. See get_plugin_data()
   926 			 *                              and the {@see 'plugin_row_meta'} filter for the list
  1026 			 *                              and the {@see 'plugin_row_meta'} filter for the list
   927 			 *                              of possible values.
  1027 			 *                              of possible values.
   928 			 * @param string   $context     The plugin context. By default this can include 'all',
  1028 			 * @param string   $context     The plugin context. By default this can include 'all',
   929 			 *                              'active', 'inactive', 'recently_activated', 'upgrade',
  1029 			 *                              'active', 'inactive', 'recently_activated', 'upgrade',
   930 			 *                              'mustuse', 'dropins', and 'search'.
  1030 			 *                              'mustuse', 'dropins', and 'search'.
   942 			 *
  1042 			 *
   943 			 * @param string[] $actions     An array of plugin action links. By default this can include
  1043 			 * @param string[] $actions     An array of plugin action links. By default this can include
   944 			 *                              'activate', 'deactivate', and 'delete'. With Multisite active
  1044 			 *                              'activate', 'deactivate', and 'delete'. With Multisite active
   945 			 *                              this can also include 'network_active' and 'network_only' items.
  1045 			 *                              this can also include 'network_active' and 'network_only' items.
   946 			 * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
  1046 			 * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
   947 			 * @param array    $plugin_data An array of plugin data. See `get_plugin_data()`
  1047 			 * @param array    $plugin_data An array of plugin data. See get_plugin_data()
   948 			 *                              and the {@see 'plugin_row_meta'} filter for the list
  1048 			 *                              and the {@see 'plugin_row_meta'} filter for the list
   949 			 *                              of possible values.
  1049 			 *                              of possible values.
   950 			 * @param string   $context     The plugin context. By default this can include 'all',
  1050 			 * @param string   $context     The plugin context. By default this can include 'all',
   951 			 *                              'active', 'inactive', 'recently_activated', 'upgrade',
  1051 			 *                              'active', 'inactive', 'recently_activated', 'upgrade',
   952 			 *                              'mustuse', 'dropins', and 'search'.
  1052 			 *                              'mustuse', 'dropins', and 'search'.
   964 			 *
  1064 			 *
   965 			 * @param string[] $actions     An array of plugin action links. By default this can include
  1065 			 * @param string[] $actions     An array of plugin action links. By default this can include
   966 			 *                              'activate', 'deactivate', and 'delete'. With Multisite active
  1066 			 *                              'activate', 'deactivate', and 'delete'. With Multisite active
   967 			 *                              this can also include 'network_active' and 'network_only' items.
  1067 			 *                              this can also include 'network_active' and 'network_only' items.
   968 			 * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
  1068 			 * @param string   $plugin_file Path to the plugin file relative to the plugins directory.
   969 			 * @param array    $plugin_data An array of plugin data. See `get_plugin_data()`
  1069 			 * @param array    $plugin_data An array of plugin data. See get_plugin_data()
   970 			 *                              and the {@see 'plugin_row_meta'} filter for the list
  1070 			 *                              and the {@see 'plugin_row_meta'} filter for the list
   971 			 *                              of possible values.
  1071 			 *                              of possible values.
   972 			 * @param string   $context     The plugin context. By default this can include 'all',
  1072 			 * @param string   $context     The plugin context. By default this can include 'all',
   973 			 *                              'active', 'inactive', 'recently_activated', 'upgrade',
  1073 			 *                              'active', 'inactive', 'recently_activated', 'upgrade',
   974 			 *                              'mustuse', 'dropins', and 'search'.
  1074 			 *                              'mustuse', 'dropins', and 'search'.
   977 
  1077 
   978 		}
  1078 		}
   979 
  1079 
   980 		$class       = $is_active ? 'active' : 'inactive';
  1080 		$class       = $is_active ? 'active' : 'inactive';
   981 		$checkbox_id = 'checkbox_' . md5( $plugin_file );
  1081 		$checkbox_id = 'checkbox_' . md5( $plugin_file );
   982 
  1082 		$disabled    = '';
   983 		if ( $restrict_network_active || $restrict_network_only || in_array( $status, array( 'mustuse', 'dropins' ), true ) || ! $compatible_php ) {
  1083 
       
  1084 		if ( $has_dependents || $has_unmet_dependencies ) {
       
  1085 			$disabled = 'disabled';
       
  1086 		}
       
  1087 
       
  1088 		if (
       
  1089 			$restrict_network_active ||
       
  1090 			$restrict_network_only ||
       
  1091 			in_array( $status, array( 'mustuse', 'dropins' ), true ) ||
       
  1092 			! $compatible_php
       
  1093 		) {
   984 			$checkbox = '';
  1094 			$checkbox = '';
   985 		} else {
  1095 		} else {
   986 			$checkbox = sprintf(
  1096 			$checkbox = sprintf(
   987 				'<label class="screen-reader-text" for="%1$s">%2$s</label>' .
  1097 				'<label class="label-covers-full-cell" for="%1$s">' .
   988 				'<input type="checkbox" name="checked[]" value="%3$s" id="%1$s" />',
  1098 				'<span class="screen-reader-text">%2$s</span></label>' .
       
  1099 				'<input type="checkbox" name="checked[]" value="%3$s" id="%1$s" ' . $disabled . '/>',
   989 				$checkbox_id,
  1100 				$checkbox_id,
   990 				/* translators: %s: Plugin name. */
  1101 				/* translators: Hidden accessibility text. %s: Plugin name. */
   991 				sprintf( __( 'Select %s' ), $plugin_data['Name'] ),
  1102 				sprintf( __( 'Select %s' ), $plugin_data['Name'] ),
   992 				esc_attr( $plugin_file )
  1103 				esc_attr( $plugin_file )
   993 			);
  1104 			);
   994 		}
  1105 		}
   995 
  1106 
   996 		if ( 'dropins' !== $context ) {
  1107 		if ( 'dropins' !== $context ) {
   997 			$description = '<p>' . ( $plugin_data['Description'] ? $plugin_data['Description'] : '&nbsp;' ) . '</p>';
  1108 			$description = '<p>' . ( $plugin_data['Description'] ? $plugin_data['Description'] : '&nbsp;' ) . '</p>';
   998 			$plugin_name = $plugin_data['Name'];
  1109 			$plugin_name = $plugin_data['Name'];
   999 		}
  1110 		}
  1000 
  1111 
  1001 		if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] )
  1112 		if (
  1002 			|| ! $compatible_php || ! $compatible_wp
  1113 			! empty( $totals['upgrade'] ) &&
       
  1114 			! empty( $plugin_data['update'] ) ||
       
  1115 			! $compatible_php ||
       
  1116 			! $compatible_wp
  1003 		) {
  1117 		) {
  1004 			$class .= ' update';
  1118 			$class .= ' update';
  1005 		}
  1119 		}
  1006 
  1120 
  1007 		$paused = ! $screen->in_admin( 'network' ) && is_plugin_paused( $plugin_file );
  1121 		$paused = ! $screen->in_admin( 'network' ) && is_plugin_paused( $plugin_file );
  1021 			esc_attr( $plugin_file )
  1135 			esc_attr( $plugin_file )
  1022 		);
  1136 		);
  1023 
  1137 
  1024 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
  1138 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
  1025 
  1139 
  1026 		$auto_updates      = (array) get_site_option( 'auto_update_plugins', array() );
  1140 		$auto_updates = (array) get_site_option( 'auto_update_plugins', array() );
  1027 		$available_updates = get_site_transient( 'update_plugins' );
       
  1028 
  1141 
  1029 		foreach ( $columns as $column_name => $column_display_name ) {
  1142 		foreach ( $columns as $column_name => $column_display_name ) {
  1030 			$extra_classes = '';
  1143 			$extra_classes = '';
  1031 			if ( in_array( $column_name, $hidden, true ) ) {
  1144 			if ( in_array( $column_name, $hidden, true ) ) {
  1032 				$extra_classes = ' hidden';
  1145 				$extra_classes = ' hidden';
  1047 					echo "<td class='$classes{$extra_classes}'>
  1160 					echo "<td class='$classes{$extra_classes}'>
  1048 						<div class='plugin-description'>$description</div>
  1161 						<div class='plugin-description'>$description</div>
  1049 						<div class='$class second plugin-version-author-uri'>";
  1162 						<div class='$class second plugin-version-author-uri'>";
  1050 
  1163 
  1051 					$plugin_meta = array();
  1164 					$plugin_meta = array();
       
  1165 
  1052 					if ( ! empty( $plugin_data['Version'] ) ) {
  1166 					if ( ! empty( $plugin_data['Version'] ) ) {
  1053 						/* translators: %s: Plugin version number. */
  1167 						/* translators: %s: Plugin version number. */
  1054 						$plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
  1168 						$plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
  1055 					}
  1169 					}
       
  1170 
  1056 					if ( ! empty( $plugin_data['Author'] ) ) {
  1171 					if ( ! empty( $plugin_data['Author'] ) ) {
  1057 						$author = $plugin_data['Author'];
  1172 						$author = $plugin_data['Author'];
       
  1173 
  1058 						if ( ! empty( $plugin_data['AuthorURI'] ) ) {
  1174 						if ( ! empty( $plugin_data['AuthorURI'] ) ) {
  1059 							$author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
  1175 							$author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
  1060 						}
  1176 						}
       
  1177 
  1061 						/* translators: %s: Plugin author name. */
  1178 						/* translators: %s: Plugin author name. */
  1062 						$plugin_meta[] = sprintf( __( 'By %s' ), $author );
  1179 						$plugin_meta[] = sprintf( __( 'By %s' ), $author );
  1063 					}
  1180 					}
  1064 
  1181 
  1065 					// Details link using API info, if available.
  1182 					// Details link using API info, if available.
  1139 
  1256 
  1140 					echo implode( ' | ', $plugin_meta );
  1257 					echo implode( ' | ', $plugin_meta );
  1141 
  1258 
  1142 					echo '</div>';
  1259 					echo '</div>';
  1143 
  1260 
       
  1261 					if ( $has_dependents ) {
       
  1262 						$this->add_dependents_to_dependency_plugin_row( $plugin_file );
       
  1263 					}
       
  1264 
       
  1265 					if ( WP_Plugin_Dependencies::has_dependencies( $plugin_file ) ) {
       
  1266 						$this->add_dependencies_to_dependent_plugin_row( $plugin_file );
       
  1267 					}
       
  1268 
       
  1269 					/**
       
  1270 					 * Fires after plugin row meta.
       
  1271 					 *
       
  1272 					 * @since 6.5.0
       
  1273 					 *
       
  1274 					 * @param string $plugin_file Refer to {@see 'plugin_row_meta'} filter.
       
  1275 					 * @param array  $plugin_data Refer to {@see 'plugin_row_meta'} filter.
       
  1276 					 */
       
  1277 					do_action( 'after_plugin_row_meta', $plugin_file, $plugin_data );
       
  1278 
  1144 					if ( $paused ) {
  1279 					if ( $paused ) {
  1145 						$notice_text = __( 'This plugin failed to load properly and is paused during recovery mode.' );
  1280 						$notice_text = __( 'This plugin failed to load properly and is paused during recovery mode.' );
  1146 
  1281 
  1147 						printf( '<p><span class="dashicons dashicons-warning"></span> <strong>%s</strong></p>', $notice_text );
  1282 						printf( '<p><span class="dashicons dashicons-warning"></span> <strong>%s</strong></p>', $notice_text );
  1148 
  1283 
  1154 					}
  1289 					}
  1155 
  1290 
  1156 					echo '</td>';
  1291 					echo '</td>';
  1157 					break;
  1292 					break;
  1158 				case 'auto-updates':
  1293 				case 'auto-updates':
  1159 					if ( ! $this->show_autoupdates ) {
  1294 					if ( ! $this->show_autoupdates || in_array( $status, array( 'mustuse', 'dropins' ), true ) ) {
  1160 						break;
  1295 						break;
  1161 					}
  1296 					}
  1162 
  1297 
  1163 					echo "<td class='column-auto-updates{$extra_classes}'>";
  1298 					echo "<td class='column-auto-updates{$extra_classes}'>";
  1164 
  1299 
  1227 					 *
  1362 					 *
  1228 					 * @param string $html        The HTML of the plugin's auto-update column content,
  1363 					 * @param string $html        The HTML of the plugin's auto-update column content,
  1229 					 *                            including toggle auto-update action links and
  1364 					 *                            including toggle auto-update action links and
  1230 					 *                            time to next update.
  1365 					 *                            time to next update.
  1231 					 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
  1366 					 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
  1232 					 * @param array  $plugin_data An array of plugin data. See `get_plugin_data()`
  1367 					 * @param array  $plugin_data An array of plugin data. See get_plugin_data()
  1233 					 *                            and the {@see 'plugin_row_meta'} filter for the list
  1368 					 *                            and the {@see 'plugin_row_meta'} filter for the list
  1234 					 *                            of possible values.
  1369 					 *                            of possible values.
  1235 					 */
  1370 					 */
  1236 					echo apply_filters( 'plugin_auto_update_setting_html', $html, $plugin_file, $plugin_data );
  1371 					echo apply_filters( 'plugin_auto_update_setting_html', $html, $plugin_file, $plugin_data );
  1237 
  1372 
  1238 					echo '<div class="notice notice-error notice-alt inline hidden"><p></p></div>';
  1373 					wp_admin_notice(
       
  1374 						'',
       
  1375 						array(
       
  1376 							'type'               => 'error',
       
  1377 							'additional_classes' => array( 'notice-alt', 'inline', 'hidden' ),
       
  1378 						)
       
  1379 					);
       
  1380 
  1239 					echo '</td>';
  1381 					echo '</td>';
  1240 
  1382 
  1241 					break;
  1383 					break;
  1242 				default:
  1384 				default:
  1243 					$classes = "$column_name column-$column_name $class";
  1385 					$classes = "$column_name column-$column_name $class";
  1249 					 *
  1391 					 *
  1250 					 * @since 3.1.0
  1392 					 * @since 3.1.0
  1251 					 *
  1393 					 *
  1252 					 * @param string $column_name Name of the column.
  1394 					 * @param string $column_name Name of the column.
  1253 					 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
  1395 					 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
  1254 					 * @param array  $plugin_data An array of plugin data. See `get_plugin_data()`
  1396 					 * @param array  $plugin_data An array of plugin data. See get_plugin_data()
  1255 					 *                            and the {@see 'plugin_row_meta'} filter for the list
  1397 					 *                            and the {@see 'plugin_row_meta'} filter for the list
  1256 					 *                            of possible values.
  1398 					 *                            of possible values.
  1257 					 */
  1399 					 */
  1258 					do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
  1400 					do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
  1259 
  1401 
  1263 
  1405 
  1264 		echo '</tr>';
  1406 		echo '</tr>';
  1265 
  1407 
  1266 		if ( ! $compatible_php || ! $compatible_wp ) {
  1408 		if ( ! $compatible_php || ! $compatible_wp ) {
  1267 			printf(
  1409 			printf(
  1268 				'<tr class="plugin-update-tr">' .
  1410 				'<tr class="plugin-update-tr"><td colspan="%s" class="plugin-update colspanchange">',
  1269 				'<td colspan="%s" class="plugin-update colspanchange">' .
       
  1270 				'<div class="update-message notice inline notice-error notice-alt"><p>',
       
  1271 				esc_attr( $this->get_column_count() )
  1411 				esc_attr( $this->get_column_count() )
  1272 			);
  1412 			);
  1273 
  1413 
       
  1414 			$incompatible_message = '';
  1274 			if ( ! $compatible_php && ! $compatible_wp ) {
  1415 			if ( ! $compatible_php && ! $compatible_wp ) {
  1275 				_e( 'This plugin does not work with your versions of WordPress and PHP.' );
  1416 				$incompatible_message .= __( 'This plugin does not work with your versions of WordPress and PHP.' );
  1276 				if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) {
  1417 				if ( current_user_can( 'update_core' ) && current_user_can( 'update_php' ) ) {
  1277 					printf(
  1418 					$incompatible_message .= sprintf(
  1278 						/* translators: 1: URL to WordPress Updates screen, 2: URL to Update PHP page. */
  1419 						/* translators: 1: URL to WordPress Updates screen, 2: URL to Update PHP page. */
  1279 						' ' . __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.' ),
  1420 						' ' . __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.' ),
  1280 						self_admin_url( 'update-core.php' ),
  1421 						self_admin_url( 'update-core.php' ),
  1281 						esc_url( wp_get_update_php_url() )
  1422 						esc_url( wp_get_update_php_url() )
  1282 					);
  1423 					);
  1283 					wp_update_php_annotation( '</p><p><em>', '</em>' );
  1424 					$incompatible_message .= wp_update_php_annotation( '</p><p><em>', '</em>', false );
  1284 				} elseif ( current_user_can( 'update_core' ) ) {
  1425 				} elseif ( current_user_can( 'update_core' ) ) {
  1285 					printf(
  1426 					$incompatible_message .= sprintf(
  1286 						/* translators: %s: URL to WordPress Updates screen. */
  1427 						/* translators: %s: URL to WordPress Updates screen. */
  1287 						' ' . __( '<a href="%s">Please update WordPress</a>.' ),
  1428 						' ' . __( '<a href="%s">Please update WordPress</a>.' ),
  1288 						self_admin_url( 'update-core.php' )
  1429 						self_admin_url( 'update-core.php' )
  1289 					);
  1430 					);
  1290 				} elseif ( current_user_can( 'update_php' ) ) {
  1431 				} elseif ( current_user_can( 'update_php' ) ) {
  1291 					printf(
  1432 					$incompatible_message .= sprintf(
  1292 						/* translators: %s: URL to Update PHP page. */
  1433 						/* translators: %s: URL to Update PHP page. */
  1293 						' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
  1434 						' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
  1294 						esc_url( wp_get_update_php_url() )
  1435 						esc_url( wp_get_update_php_url() )
  1295 					);
  1436 					);
  1296 					wp_update_php_annotation( '</p><p><em>', '</em>' );
  1437 					$incompatible_message .= wp_update_php_annotation( '</p><p><em>', '</em>', false );
  1297 				}
  1438 				}
  1298 			} elseif ( ! $compatible_wp ) {
  1439 			} elseif ( ! $compatible_wp ) {
  1299 				_e( 'This plugin does not work with your version of WordPress.' );
  1440 				$incompatible_message .= __( 'This plugin does not work with your version of WordPress.' );
  1300 				if ( current_user_can( 'update_core' ) ) {
  1441 				if ( current_user_can( 'update_core' ) ) {
  1301 					printf(
  1442 					$incompatible_message .= sprintf(
  1302 						/* translators: %s: URL to WordPress Updates screen. */
  1443 						/* translators: %s: URL to WordPress Updates screen. */
  1303 						' ' . __( '<a href="%s">Please update WordPress</a>.' ),
  1444 						' ' . __( '<a href="%s">Please update WordPress</a>.' ),
  1304 						self_admin_url( 'update-core.php' )
  1445 						self_admin_url( 'update-core.php' )
  1305 					);
  1446 					);
  1306 				}
  1447 				}
  1307 			} elseif ( ! $compatible_php ) {
  1448 			} elseif ( ! $compatible_php ) {
  1308 				_e( 'This plugin does not work with your version of PHP.' );
  1449 				$incompatible_message .= __( 'This plugin does not work with your version of PHP.' );
  1309 				if ( current_user_can( 'update_php' ) ) {
  1450 				if ( current_user_can( 'update_php' ) ) {
  1310 					printf(
  1451 					$incompatible_message .= sprintf(
  1311 						/* translators: %s: URL to Update PHP page. */
  1452 						/* translators: %s: URL to Update PHP page. */
  1312 						' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
  1453 						' ' . __( '<a href="%s">Learn more about updating PHP</a>.' ),
  1313 						esc_url( wp_get_update_php_url() )
  1454 						esc_url( wp_get_update_php_url() )
  1314 					);
  1455 					);
  1315 					wp_update_php_annotation( '</p><p><em>', '</em>' );
  1456 					$incompatible_message .= wp_update_php_annotation( '</p><p><em>', '</em>', false );
  1316 				}
  1457 				}
  1317 			}
  1458 			}
  1318 
  1459 
  1319 			echo '</p></div></td></tr>';
  1460 			wp_admin_notice(
       
  1461 				$incompatible_message,
       
  1462 				array(
       
  1463 					'type'               => 'error',
       
  1464 					'additional_classes' => array( 'notice-alt', 'inline', 'update-message' ),
       
  1465 				)
       
  1466 			);
       
  1467 
       
  1468 			echo '</td></tr>';
  1320 		}
  1469 		}
  1321 
  1470 
  1322 		/**
  1471 		/**
  1323 		 * Fires after each row in the Plugins list table.
  1472 		 * Fires after each row in the Plugins list table.
  1324 		 *
  1473 		 *
  1325 		 * @since 2.3.0
  1474 		 * @since 2.3.0
  1326 		 * @since 5.5.0 Added 'auto-update-enabled' and 'auto-update-disabled'
  1475 		 * @since 5.5.0 Added 'auto-update-enabled' and 'auto-update-disabled'
  1327 		 *              to possible values for `$status`.
  1476 		 *              to possible values for `$status`.
  1328 		 *
  1477 		 *
  1329 		 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
  1478 		 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
  1330 		 * @param array  $plugin_data An array of plugin data. See `get_plugin_data()`
  1479 		 * @param array  $plugin_data An array of plugin data. See get_plugin_data()
  1331 		 *                            and the {@see 'plugin_row_meta'} filter for the list
  1480 		 *                            and the {@see 'plugin_row_meta'} filter for the list
  1332 		 *                            of possible values.
  1481 		 *                            of possible values.
  1333 		 * @param string $status      Status filter currently applied to the plugin list.
  1482 		 * @param string $status      Status filter currently applied to the plugin list.
  1334 		 *                            Possible values are: 'all', 'active', 'inactive',
  1483 		 *                            Possible values are: 'all', 'active', 'inactive',
  1335 		 *                            'recently_activated', 'upgrade', 'mustuse', 'dropins',
  1484 		 *                            'recently_activated', 'upgrade', 'mustuse', 'dropins',
  1346 		 * @since 2.7.0
  1495 		 * @since 2.7.0
  1347 		 * @since 5.5.0 Added 'auto-update-enabled' and 'auto-update-disabled'
  1496 		 * @since 5.5.0 Added 'auto-update-enabled' and 'auto-update-disabled'
  1348 		 *              to possible values for `$status`.
  1497 		 *              to possible values for `$status`.
  1349 		 *
  1498 		 *
  1350 		 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
  1499 		 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
  1351 		 * @param array  $plugin_data An array of plugin data. See `get_plugin_data()`
  1500 		 * @param array  $plugin_data An array of plugin data. See get_plugin_data()
  1352 		 *                            and the {@see 'plugin_row_meta'} filter for the list
  1501 		 *                            and the {@see 'plugin_row_meta'} filter for the list
  1353 		 *                            of possible values.
  1502 		 *                            of possible values.
  1354 		 * @param string $status      Status filter currently applied to the plugin list.
  1503 		 * @param string $status      Status filter currently applied to the plugin list.
  1355 		 *                            Possible values are: 'all', 'active', 'inactive',
  1504 		 *                            Possible values are: 'all', 'active', 'inactive',
  1356 		 *                            'recently_activated', 'upgrade', 'mustuse', 'dropins',
  1505 		 *                            'recently_activated', 'upgrade', 'mustuse', 'dropins',
  1367 	 * @return string Unalterable name for the primary column, in this case, 'name'.
  1516 	 * @return string Unalterable name for the primary column, in this case, 'name'.
  1368 	 */
  1517 	 */
  1369 	protected function get_primary_column_name() {
  1518 	protected function get_primary_column_name() {
  1370 		return 'name';
  1519 		return 'name';
  1371 	}
  1520 	}
       
  1521 
       
  1522 	/**
       
  1523 	 * Prints a list of other plugins that depend on the plugin.
       
  1524 	 *
       
  1525 	 * @since 6.5.0
       
  1526 	 *
       
  1527 	 * @param string $dependency The dependency's filepath, relative to the plugins directory.
       
  1528 	 */
       
  1529 	protected function add_dependents_to_dependency_plugin_row( $dependency ) {
       
  1530 		$dependent_names = WP_Plugin_Dependencies::get_dependent_names( $dependency );
       
  1531 
       
  1532 		if ( empty( $dependent_names ) ) {
       
  1533 			return;
       
  1534 		}
       
  1535 
       
  1536 		$dependency_note = __( 'Note: This plugin cannot be deactivated or deleted until the plugins that require it are deactivated or deleted.' );
       
  1537 
       
  1538 		$comma       = wp_get_list_item_separator();
       
  1539 		$required_by = sprintf(
       
  1540 			/* translators: %s: List of dependencies. */
       
  1541 			__( '<strong>Required by:</strong> %s' ),
       
  1542 			implode( $comma, $dependent_names )
       
  1543 		);
       
  1544 
       
  1545 		printf(
       
  1546 			'<div class="required-by"><p>%1$s</p><p>%2$s</p></div>',
       
  1547 			$required_by,
       
  1548 			$dependency_note
       
  1549 		);
       
  1550 	}
       
  1551 
       
  1552 	/**
       
  1553 	 * Prints a list of other plugins that the plugin depends on.
       
  1554 	 *
       
  1555 	 * @since 6.5.0
       
  1556 	 *
       
  1557 	 * @param string $dependent The dependent plugin's filepath, relative to the plugins directory.
       
  1558 	 */
       
  1559 	protected function add_dependencies_to_dependent_plugin_row( $dependent ) {
       
  1560 		$dependency_names = WP_Plugin_Dependencies::get_dependency_names( $dependent );
       
  1561 
       
  1562 		if ( array() === $dependency_names ) {
       
  1563 			return;
       
  1564 		}
       
  1565 
       
  1566 		$links = array();
       
  1567 		foreach ( $dependency_names as $slug => $name ) {
       
  1568 			$links[] = $this->get_dependency_view_details_link( $name, $slug );
       
  1569 		}
       
  1570 
       
  1571 		$is_active = is_multisite() ? is_plugin_active_for_network( $dependent ) : is_plugin_active( $dependent );
       
  1572 		$comma     = wp_get_list_item_separator();
       
  1573 		$requires  = sprintf(
       
  1574 			/* translators: %s: List of dependency names. */
       
  1575 			__( '<strong>Requires:</strong> %s' ),
       
  1576 			implode( $comma, $links )
       
  1577 		);
       
  1578 
       
  1579 		$notice        = '';
       
  1580 		$error_message = '';
       
  1581 		if ( WP_Plugin_Dependencies::has_unmet_dependencies( $dependent ) ) {
       
  1582 			if ( $is_active ) {
       
  1583 				$error_message = __( 'This plugin is active but may not function correctly because required plugins are missing or inactive.' );
       
  1584 			} else {
       
  1585 				$error_message = __( 'This plugin cannot be activated because required plugins are missing or inactive.' );
       
  1586 			}
       
  1587 			$notice = wp_get_admin_notice(
       
  1588 				$error_message,
       
  1589 				array(
       
  1590 					'type'               => 'error',
       
  1591 					'additional_classes' => array( 'inline', 'notice-alt' ),
       
  1592 				)
       
  1593 			);
       
  1594 		}
       
  1595 
       
  1596 		printf(
       
  1597 			'<div class="requires"><p>%1$s</p><p>%2$s</p></div>',
       
  1598 			$requires,
       
  1599 			$notice
       
  1600 		);
       
  1601 	}
       
  1602 
       
  1603 	/**
       
  1604 	 * Returns a 'View details' like link for a dependency.
       
  1605 	 *
       
  1606 	 * @since 6.5.0
       
  1607 	 *
       
  1608 	 * @param string $name The dependency's name.
       
  1609 	 * @param string $slug The dependency's slug.
       
  1610 	 * @return string A 'View details' link for the dependency.
       
  1611 	 */
       
  1612 	protected function get_dependency_view_details_link( $name, $slug ) {
       
  1613 		$dependency_data = WP_Plugin_Dependencies::get_dependency_data( $slug );
       
  1614 
       
  1615 		if ( false === $dependency_data
       
  1616 			|| $name === $slug
       
  1617 			|| $name !== $dependency_data['name']
       
  1618 			|| empty( $dependency_data['version'] )
       
  1619 		) {
       
  1620 			return $name;
       
  1621 		}
       
  1622 
       
  1623 		return $this->get_view_details_link( $name, $slug );
       
  1624 	}
       
  1625 
       
  1626 	/**
       
  1627 	 * Returns a 'View details' link for the plugin.
       
  1628 	 *
       
  1629 	 * @since 6.5.0
       
  1630 	 *
       
  1631 	 * @param string $name The plugin's name.
       
  1632 	 * @param string $slug The plugin's slug.
       
  1633 	 * @return string A 'View details' link for the plugin.
       
  1634 	 */
       
  1635 	protected function get_view_details_link( $name, $slug ) {
       
  1636 		$url = add_query_arg(
       
  1637 			array(
       
  1638 				'tab'       => 'plugin-information',
       
  1639 				'plugin'    => $slug,
       
  1640 				'TB_iframe' => 'true',
       
  1641 				'width'     => '600',
       
  1642 				'height'    => '550',
       
  1643 			),
       
  1644 			network_admin_url( 'plugin-install.php' )
       
  1645 		);
       
  1646 
       
  1647 		$name_attr = esc_attr( $name );
       
  1648 		return sprintf(
       
  1649 			"<a href='%s' class='thickbox open-plugin-details-modal' aria-label='%s' data-title='%s'>%s</a>",
       
  1650 			esc_url( $url ),
       
  1651 			/* translators: %s: Plugin name. */
       
  1652 			sprintf( __( 'More information about %s' ), $name_attr ),
       
  1653 			$name_attr,
       
  1654 			esc_html( $name )
       
  1655 		);
       
  1656 	}
  1372 }
  1657 }