wp/wp-admin/includes/class-wp-plugins-list-table.php
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
4:346c88efed21 5:5e2f62d02dcd
     7  * @since 3.1.0
     7  * @since 3.1.0
     8  * @access private
     8  * @access private
     9  */
     9  */
    10 class WP_Plugins_List_Table extends WP_List_Table {
    10 class WP_Plugins_List_Table extends WP_List_Table {
    11 
    11 
    12 	function __construct( $args = array() ) {
    12 	/**
       
    13 	 * Constructor.
       
    14 	 *
       
    15 	 * @since 3.1.0
       
    16 	 * @access public
       
    17 	 *
       
    18 	 * @see WP_List_Table::__construct() for more information on default arguments.
       
    19 	 *
       
    20 	 * @param array $args An associative array of arguments.
       
    21 	 */
       
    22 	public function __construct( $args = array() ) {
    13 		global $status, $page;
    23 		global $status, $page;
    14 
    24 
    15 		parent::__construct( array(
    25 		parent::__construct( array(
    16 			'plural' => 'plugins',
    26 			'plural' => 'plugins',
    17 			'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
    27 			'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
    25 			$_SERVER['REQUEST_URI'] = add_query_arg('s', wp_unslash($_REQUEST['s']) );
    35 			$_SERVER['REQUEST_URI'] = add_query_arg('s', wp_unslash($_REQUEST['s']) );
    26 
    36 
    27 		$page = $this->get_pagenum();
    37 		$page = $this->get_pagenum();
    28 	}
    38 	}
    29 
    39 
    30 	function get_table_classes() {
    40 	protected function get_table_classes() {
    31 		return array( 'widefat', $this->_args['plural'] );
    41 		return array( 'widefat', $this->_args['plural'] );
    32 	}
    42 	}
    33 
    43 
    34 	function ajax_user_can() {
    44 	public function ajax_user_can() {
    35 		return current_user_can('activate_plugins');
    45 		return current_user_can('activate_plugins');
    36 	}
    46 	}
    37 
    47 
    38 	function prepare_items() {
    48 	public function prepare_items() {
    39 		global $status, $plugins, $totals, $page, $orderby, $order, $s;
    49 		global $status, $plugins, $totals, $page, $orderby, $order, $s;
    40 
    50 
    41 		wp_reset_vars( array( 'orderby', 'order', 's' ) );
    51 		wp_reset_vars( array( 'orderby', 'order', 's' ) );
    42 
    52 
       
    53 		/**
       
    54 		 * Filter the full array of plugins to list in the Plugins list table.
       
    55 		 *
       
    56 		 * @since 3.0.0
       
    57 		 *
       
    58 		 * @see get_plugins()
       
    59 		 *
       
    60 		 * @param array $plugins An array of plugins to display in the list table.
       
    61 		 */
    43 		$plugins = array(
    62 		$plugins = array(
    44 			'all' => apply_filters( 'all_plugins', get_plugins() ),
    63 			'all' => apply_filters( 'all_plugins', get_plugins() ),
    45 			'search' => array(),
    64 			'search' => array(),
    46 			'active' => array(),
    65 			'active' => array(),
    47 			'inactive' => array(),
    66 			'inactive' => array(),
    52 		);
    71 		);
    53 
    72 
    54 		$screen = $this->screen;
    73 		$screen = $this->screen;
    55 
    74 
    56 		if ( ! is_multisite() || ( $screen->in_admin( 'network' ) && current_user_can( 'manage_network_plugins' ) ) ) {
    75 		if ( ! is_multisite() || ( $screen->in_admin( 'network' ) && current_user_can( 'manage_network_plugins' ) ) ) {
    57 			if ( apply_filters( 'show_advanced_plugins', true, 'mustuse' ) )
    76 
       
    77 			/**
       
    78 			 * Filter whether to display the advanced plugins list table.
       
    79 			 *
       
    80 			 * There are two types of advanced plugins - must-use and drop-ins -
       
    81 			 * which can be used in a single site or Multisite network.
       
    82 			 *
       
    83 			 * The $type parameter allows you to differentiate between the type of advanced
       
    84 			 * plugins to filter the display of. Contexts include 'mustuse' and 'dropins'.
       
    85 			 *
       
    86 			 * @since 3.0.0
       
    87 			 *
       
    88 			 * @param bool   $show Whether to show the advanced plugins for the specified
       
    89 			 *                     plugin type. Default true.
       
    90 			 * @param string $type The plugin type. Accepts 'mustuse', 'dropins'.
       
    91 			 */
       
    92 			if ( apply_filters( 'show_advanced_plugins', true, 'mustuse' ) ) {
    58 				$plugins['mustuse'] = get_mu_plugins();
    93 				$plugins['mustuse'] = get_mu_plugins();
       
    94 			}
       
    95 
       
    96 			/** This action is documented in wp-admin/includes/class-wp-plugins-list-table.php */
    59 			if ( apply_filters( 'show_advanced_plugins', true, 'dropins' ) )
    97 			if ( apply_filters( 'show_advanced_plugins', true, 'dropins' ) )
    60 				$plugins['dropins'] = get_dropins();
    98 				$plugins['dropins'] = get_dropins();
    61 
    99 
    62 			if ( current_user_can( 'update_plugins' ) ) {
   100 			if ( current_user_can( 'update_plugins' ) ) {
    63 				$current = get_site_transient( 'update_plugins' );
   101 				$current = get_site_transient( 'update_plugins' );
    79 				if ( $time + WEEK_IN_SECONDS < time() )
   117 				if ( $time + WEEK_IN_SECONDS < time() )
    80 					unset( $recently_activated[$key] );
   118 					unset( $recently_activated[$key] );
    81 			update_option( 'recently_activated', $recently_activated );
   119 			update_option( 'recently_activated', $recently_activated );
    82 		}
   120 		}
    83 
   121 
       
   122 		$plugin_info = get_site_transient( 'update_plugins' );
       
   123 
    84 		foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
   124 		foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
       
   125 			// Extra info if known. array_merge() ensures $plugin_data has precedence if keys collide.
       
   126 			if ( isset( $plugin_info->response[ $plugin_file ] ) ) {
       
   127 				$plugins['all'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->response[ $plugin_file ], $plugin_data );
       
   128 				// Make sure that $plugins['upgrade'] also receives the extra info since it is used on ?plugin_status=upgrade
       
   129 				if ( isset( $plugins['upgrade'][ $plugin_file ] ) ) {
       
   130 					$plugins['upgrade'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->response[ $plugin_file ], $plugin_data );
       
   131 				}
       
   132 
       
   133 			} elseif ( isset( $plugin_info->no_update[ $plugin_file ] ) ) {
       
   134 				$plugins['all'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->no_update[ $plugin_file ], $plugin_data );
       
   135 				// Make sure that $plugins['upgrade'] also receives the extra info since it is used on ?plugin_status=upgrade
       
   136 				if ( isset( $plugins['upgrade'][ $plugin_file ] ) ) {
       
   137 					$plugins['upgrade'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->no_update[ $plugin_file ], $plugin_data );
       
   138 				}
       
   139 			}
       
   140 
    85 			// Filter into individual sections
   141 			// Filter into individual sections
    86 			if ( is_multisite() && ! $screen->in_admin( 'network' ) && is_network_only_plugin( $plugin_file ) ) {
   142 			if ( is_multisite() && ! $screen->in_admin( 'network' ) && is_network_only_plugin( $plugin_file ) && ! is_plugin_active( $plugin_file ) ) {
       
   143 				// On the non-network screen, filter out network-only plugins as long as they're not individually activated
    87 				unset( $plugins['all'][ $plugin_file ] );
   144 				unset( $plugins['all'][ $plugin_file ] );
    88 			} elseif ( ! $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) {
   145 			} elseif ( ! $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) {
       
   146 				// On the non-network screen, filter out network activated plugins
    89 				unset( $plugins['all'][ $plugin_file ] );
   147 				unset( $plugins['all'][ $plugin_file ] );
    90 			} elseif ( ( ! $screen->in_admin( 'network' ) && is_plugin_active( $plugin_file ) )
   148 			} elseif ( ( ! $screen->in_admin( 'network' ) && is_plugin_active( $plugin_file ) )
    91 				|| ( $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) ) {
   149 				|| ( $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) ) {
       
   150 				// On the non-network screen, populate the active list with plugins that are individually activated
       
   151 				// On the network-admin screen, populate the active list with plugins that are network activated
    92 				$plugins['active'][ $plugin_file ] = $plugin_data;
   152 				$plugins['active'][ $plugin_file ] = $plugin_data;
    93 			} else {
   153 			} else {
    94 				if ( ! $screen->in_admin( 'network' ) && isset( $recently_activated[ $plugin_file ] ) ) // Was the plugin recently activated?
   154 				if ( ! $screen->in_admin( 'network' ) && isset( $recently_activated[ $plugin_file ] ) ) {
       
   155 					// On the non-network screen, populate the recently activated list with plugins that have been recently activated
    95 					$plugins['recently_activated'][ $plugin_file ] = $plugin_data;
   156 					$plugins['recently_activated'][ $plugin_file ] = $plugin_data;
       
   157 				}
       
   158 				// Populate the inactive list with plugins that aren't activated
    96 				$plugins['inactive'][ $plugin_file ] = $plugin_data;
   159 				$plugins['inactive'][ $plugin_file ] = $plugin_data;
    97 			}
   160 			}
    98 		}
   161 		}
    99 
   162 
   100 		if ( $s ) {
   163 		if ( $s ) {
   135 			'total_items' => $total_this_page,
   198 			'total_items' => $total_this_page,
   136 			'per_page' => $plugins_per_page,
   199 			'per_page' => $plugins_per_page,
   137 		) );
   200 		) );
   138 	}
   201 	}
   139 
   202 
   140 	function _search_callback( $plugin ) {
   203 	/**
       
   204 	 * @staticvar string $term
       
   205 	 * @param array $plugin
       
   206 	 * @return boolean
       
   207 	 */
       
   208 	public function _search_callback( $plugin ) {
   141 		static $term;
   209 		static $term;
   142 		if ( is_null( $term ) )
   210 		if ( is_null( $term ) )
   143 			$term = wp_unslash( $_REQUEST['s'] );
   211 			$term = wp_unslash( $_REQUEST['s'] );
   144 
   212 
   145 		foreach ( $plugin as $value )
   213 		foreach ( $plugin as $value ) {
   146 			if ( stripos( $value, $term ) !== false )
   214 			if ( false !== stripos( strip_tags( $value ), $term ) ) {
   147 				return true;
   215 				return true;
       
   216 			}
       
   217 		}
   148 
   218 
   149 		return false;
   219 		return false;
   150 	}
   220 	}
   151 
   221 
   152 	function _order_callback( $plugin_a, $plugin_b ) {
   222 	/**
       
   223 	 * @global string $orderby
       
   224 	 * @global string $order
       
   225 	 * @param array $plugin_a
       
   226 	 * @param array $plugin_b
       
   227 	 * @return int
       
   228 	 */
       
   229 	public function _order_callback( $plugin_a, $plugin_b ) {
   153 		global $orderby, $order;
   230 		global $orderby, $order;
   154 
   231 
   155 		$a = $plugin_a[$orderby];
   232 		$a = $plugin_a[$orderby];
   156 		$b = $plugin_b[$orderby];
   233 		$b = $plugin_b[$orderby];
   157 
   234 
   162 			return ( $a < $b ) ? 1 : -1;
   239 			return ( $a < $b ) ? 1 : -1;
   163 		else
   240 		else
   164 			return ( $a < $b ) ? -1 : 1;
   241 			return ( $a < $b ) ? -1 : 1;
   165 	}
   242 	}
   166 
   243 
   167 	function no_items() {
   244 	public function no_items() {
   168 		global $plugins;
   245 		global $plugins;
   169 
   246 
   170 		if ( !empty( $plugins['all'] ) )
   247 		if ( !empty( $plugins['all'] ) )
   171 			_e( 'No plugins found.' );
   248 			_e( 'No plugins found.' );
   172 		else
   249 		else
   173 			_e( 'You do not appear to have any plugins available at this time.' );
   250 			_e( 'You do not appear to have any plugins available at this time.' );
   174 	}
   251 	}
   175 
   252 
   176 	function get_columns() {
   253 	public function get_columns() {
   177 		global $status;
   254 		global $status;
   178 
   255 
   179 		return array(
   256 		return array(
   180 			'cb'          => !in_array( $status, array( 'mustuse', 'dropins' ) ) ? '<input type="checkbox" />' : '',
   257 			'cb'          => !in_array( $status, array( 'mustuse', 'dropins' ) ) ? '<input type="checkbox" />' : '',
   181 			'name'        => __( 'Plugin' ),
   258 			'name'        => __( 'Plugin' ),
   182 			'description' => __( 'Description' ),
   259 			'description' => __( 'Description' ),
   183 		);
   260 		);
   184 	}
   261 	}
   185 
   262 
   186 	function get_sortable_columns() {
   263 	protected function get_sortable_columns() {
   187 		return array();
   264 		return array();
   188 	}
   265 	}
   189 
   266 
   190 	function get_views() {
   267 	protected function get_views() {
   191 		global $totals, $status;
   268 		global $totals, $status;
   192 
   269 
   193 		$status_links = array();
   270 		$status_links = array();
   194 		foreach ( $totals as $type => $count ) {
   271 		foreach ( $totals as $type => $count ) {
   195 			if ( !$count )
   272 			if ( !$count )
   229 		}
   306 		}
   230 
   307 
   231 		return $status_links;
   308 		return $status_links;
   232 	}
   309 	}
   233 
   310 
   234 	function get_bulk_actions() {
   311 	protected function get_bulk_actions() {
   235 		global $status;
   312 		global $status;
   236 
   313 
   237 		$actions = array();
   314 		$actions = array();
   238 
   315 
   239 		if ( 'active' != $status )
   316 		if ( 'active' != $status )
   250 		}
   327 		}
   251 
   328 
   252 		return $actions;
   329 		return $actions;
   253 	}
   330 	}
   254 
   331 
   255 	function bulk_actions() {
   332 	/**
       
   333 	 * @global string $status
       
   334 	 * @param string $which
       
   335 	 * @return null
       
   336 	 */
       
   337 	public function bulk_actions( $which = '' ) {
   256 		global $status;
   338 		global $status;
   257 
   339 
   258 		if ( in_array( $status, array( 'mustuse', 'dropins' ) ) )
   340 		if ( in_array( $status, array( 'mustuse', 'dropins' ) ) )
   259 			return;
   341 			return;
   260 
   342 
   261 		parent::bulk_actions();
   343 		parent::bulk_actions( $which );
   262 	}
   344 	}
   263 
   345 
   264 	function extra_tablenav( $which ) {
   346 	/**
       
   347 	 * @global string $status
       
   348 	 * @param string $which
       
   349 	 * @return null
       
   350 	 */
       
   351 	protected function extra_tablenav( $which ) {
   265 		global $status;
   352 		global $status;
   266 
   353 
   267 		if ( ! in_array($status, array('recently_activated', 'mustuse', 'dropins') ) )
   354 		if ( ! in_array($status, array('recently_activated', 'mustuse', 'dropins') ) )
   268 			return;
   355 			return;
   269 
   356 
   277 			echo '<p>' . sprintf( __( 'Drop-ins are advanced plugins in the <code>%s</code> directory that replace WordPress functionality when present.' ), str_replace( ABSPATH, '', WP_CONTENT_DIR ) ) . '</p>';
   364 			echo '<p>' . sprintf( __( 'Drop-ins are advanced plugins in the <code>%s</code> directory that replace WordPress functionality when present.' ), str_replace( ABSPATH, '', WP_CONTENT_DIR ) ) . '</p>';
   278 
   365 
   279 		echo '</div>';
   366 		echo '</div>';
   280 	}
   367 	}
   281 
   368 
   282 	function current_action() {
   369 	public function current_action() {
   283 		if ( isset($_POST['clear-recent-list']) )
   370 		if ( isset($_POST['clear-recent-list']) )
   284 			return 'clear-recent-list';
   371 			return 'clear-recent-list';
   285 
   372 
   286 		return parent::current_action();
   373 		return parent::current_action();
   287 	}
   374 	}
   288 
   375 
   289 	function display_rows() {
   376 	public function display_rows() {
   290 		global $status;
   377 		global $status;
   291 
   378 
   292 		if ( is_multisite() && ! $this->screen->in_admin( 'network' ) && in_array( $status, array( 'mustuse', 'dropins' ) ) )
   379 		if ( is_multisite() && ! $this->screen->in_admin( 'network' ) && in_array( $status, array( 'mustuse', 'dropins' ) ) )
   293 			return;
   380 			return;
   294 
   381 
   295 		foreach ( $this->items as $plugin_file => $plugin_data )
   382 		foreach ( $this->items as $plugin_file => $plugin_data )
   296 			$this->single_row( array( $plugin_file, $plugin_data ) );
   383 			$this->single_row( array( $plugin_file, $plugin_data ) );
   297 	}
   384 	}
   298 
   385 
   299 	function single_row( $item ) {
   386 	/**
       
   387 	 * @global string $status
       
   388 	 * @global int $page
       
   389 	 * @global string $s
       
   390 	 * @global array $totals
       
   391 	 * @param array $item
       
   392 	 */
       
   393 	public function single_row( $item ) {
   300 		global $status, $page, $s, $totals;
   394 		global $status, $page, $s, $totals;
   301 
   395 
   302 		list( $plugin_file, $plugin_data ) = $item;
   396 		list( $plugin_file, $plugin_data ) = $item;
   303 		$context = $status;
   397 		$context = $status;
   304 		$screen = $this->screen;
   398 		$screen = $this->screen;
   305 
   399 
   306 		// preorder
   400 		// Pre-order.
   307 		$actions = array(
   401 		$actions = array(
   308 			'deactivate' => '',
   402 			'deactivate' => '',
   309 			'activate' => '',
   403 			'activate' => '',
       
   404 			'details' => '',
   310 			'edit' => '',
   405 			'edit' => '',
   311 			'delete' => '',
   406 			'delete' => '',
   312 		);
   407 		);
   313 
   408 
   314 		if ( 'mustuse' == $context ) {
   409 		if ( 'mustuse' == $context ) {
   353 					$actions['activate'] = '<a href="' . wp_nonce_url('plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Activate this plugin') . '" class="edit">' . __('Activate') . '</a>';
   448 					$actions['activate'] = '<a href="' . wp_nonce_url('plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Activate this plugin') . '" class="edit">' . __('Activate') . '</a>';
   354 
   449 
   355 					if ( ! is_multisite() && current_user_can('delete_plugins') )
   450 					if ( ! is_multisite() && current_user_can('delete_plugins') )
   356 						$actions['delete'] = '<a href="' . wp_nonce_url('plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins') . '" title="' . esc_attr__('Delete this plugin') . '" class="delete">' . __('Delete') . '</a>';
   451 						$actions['delete'] = '<a href="' . wp_nonce_url('plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins') . '" title="' . esc_attr__('Delete this plugin') . '" class="delete">' . __('Delete') . '</a>';
   357 				} // end if $is_active
   452 				} // end if $is_active
       
   453 
   358 			 } // end if $screen->in_admin( 'network' )
   454 			 } // end if $screen->in_admin( 'network' )
   359 
   455 
   360 			if ( ( ! is_multisite() || $screen->in_admin( 'network' ) ) && current_user_can('edit_plugins') && is_writable(WP_PLUGIN_DIR . '/' . $plugin_file) )
   456 			if ( ( ! is_multisite() || $screen->in_admin( 'network' ) ) && current_user_can('edit_plugins') && is_writable(WP_PLUGIN_DIR . '/' . $plugin_file) )
   361 				$actions['edit'] = '<a href="plugin-editor.php?file=' . $plugin_file . '" title="' . esc_attr__('Open this file in the Plugin Editor') . '" class="edit">' . __('Edit') . '</a>';
   457 				$actions['edit'] = '<a href="plugin-editor.php?file=' . $plugin_file . '" title="' . esc_attr__('Open this file in the Plugin Editor') . '" class="edit">' . __('Edit') . '</a>';
   362 		} // end if $context
   458 		} // end if $context
   363 
   459 
   364 		$prefix = $screen->in_admin( 'network' ) ? 'network_admin_' : '';
   460 		$prefix = $screen->in_admin( 'network' ) ? 'network_admin_' : '';
       
   461 
       
   462 		/**
       
   463 		 * Filter the action links displayed for each plugin in the Plugins list table.
       
   464 		 *
       
   465 		 * The dynamic portion of the hook name, `$prefix`, refers to the context the
       
   466 		 * action links are displayed in. The 'network_admin_' prefix is used if the
       
   467 		 * current screen is the Network plugins list table. The prefix is empty ('')
       
   468 		 * if the current screen is the site plugins list table.
       
   469 		 *
       
   470 		 * The default action links for the Network plugins list table include
       
   471 		 * 'Network Activate', 'Network Deactivate', 'Edit', and 'Delete'.
       
   472 		 *
       
   473 		 * The default action links for the site plugins list table include
       
   474 		 * 'Activate', 'Deactivate', and 'Edit', for a network site, and
       
   475 		 * 'Activate', 'Deactivate', 'Edit', and 'Delete' for a single site.
       
   476 		 *
       
   477 		 * @since 2.5.0
       
   478 		 *
       
   479 		 * @param array  $actions     An array of plugin action links.
       
   480 		 * @param string $plugin_file Path to the plugin file.
       
   481 		 * @param array  $plugin_data An array of plugin data.
       
   482 		 * @param string $context     The plugin context. Defaults are 'All', 'Active',
       
   483 		 *                            'Inactive', 'Recently Activated', 'Upgrade',
       
   484 		 *                            'Must-Use', 'Drop-ins', 'Search'.
       
   485 		 */
   365 		$actions = apply_filters( $prefix . 'plugin_action_links', array_filter( $actions ), $plugin_file, $plugin_data, $context );
   486 		$actions = apply_filters( $prefix . 'plugin_action_links', array_filter( $actions ), $plugin_file, $plugin_data, $context );
       
   487 
       
   488 		/**
       
   489 		 * Filter the list of action links displayed for a specific plugin.
       
   490 		 *
       
   491 		 * The first dynamic portion of the hook name, $prefix, refers to the context
       
   492 		 * the action links are displayed in. The 'network_admin_' prefix is used if the
       
   493 		 * current screen is the Network plugins list table. The prefix is empty ('')
       
   494 		 * if the current screen is the site plugins list table.
       
   495 		 *
       
   496 		 * The second dynamic portion of the hook name, $plugin_file, refers to the path
       
   497 		 * to the plugin file, relative to the plugins directory.
       
   498 		 *
       
   499 		 * @since 2.7.0
       
   500 		 *
       
   501 		 * @param array  $actions     An array of plugin action links.
       
   502 		 * @param string $plugin_file Path to the plugin file.
       
   503 		 * @param array  $plugin_data An array of plugin data.
       
   504 		 * @param string $context     The plugin context. Defaults are 'All', 'Active',
       
   505 		 *                            'Inactive', 'Recently Activated', 'Upgrade',
       
   506 		 *                            'Must-Use', 'Drop-ins', 'Search'.
       
   507 		 */
   366 		$actions = apply_filters( $prefix . "plugin_action_links_$plugin_file", $actions, $plugin_file, $plugin_data, $context );
   508 		$actions = apply_filters( $prefix . "plugin_action_links_$plugin_file", $actions, $plugin_file, $plugin_data, $context );
   367 
   509 
   368 		$class = $is_active ? 'active' : 'inactive';
   510 		$class = $is_active ? 'active' : 'inactive';
   369 		$checkbox_id =  "checkbox_" . md5($plugin_data['Name']);
   511 		$checkbox_id =  "checkbox_" . md5($plugin_data['Name']);
   370 		if ( in_array( $status, array( 'mustuse', 'dropins' ) ) ) {
   512 		if ( in_array( $status, array( 'mustuse', 'dropins' ) ) ) {
   380 
   522 
   381 		$id = sanitize_title( $plugin_name );
   523 		$id = sanitize_title( $plugin_name );
   382 		if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] ) )
   524 		if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] ) )
   383 			$class .= ' update';
   525 			$class .= ' update';
   384 
   526 
   385 		echo "<tr id='$id' class='$class'>";
   527 		$plugin_slug = ( isset( $plugin_data['slug'] ) ) ? $plugin_data['slug'] : '';
       
   528 		printf( "<tr id='%s' class='%s' data-slug='%s'>",
       
   529 			$id,
       
   530 			$class,
       
   531 			$plugin_slug
       
   532 		);
   386 
   533 
   387 		list( $columns, $hidden ) = $this->get_column_info();
   534 		list( $columns, $hidden ) = $this->get_column_info();
   388 
   535 
   389 		foreach ( $columns as $column_name => $column_display_name ) {
   536 		foreach ( $columns as $column_name => $column_display_name ) {
   390 			$style = '';
   537 			$style = '';
   409 					if ( !empty( $plugin_data['Version'] ) )
   556 					if ( !empty( $plugin_data['Version'] ) )
   410 						$plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
   557 						$plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
   411 					if ( !empty( $plugin_data['Author'] ) ) {
   558 					if ( !empty( $plugin_data['Author'] ) ) {
   412 						$author = $plugin_data['Author'];
   559 						$author = $plugin_data['Author'];
   413 						if ( !empty( $plugin_data['AuthorURI'] ) )
   560 						if ( !empty( $plugin_data['AuthorURI'] ) )
   414 							$author = '<a href="' . $plugin_data['AuthorURI'] . '" title="' . esc_attr__( 'Visit author homepage' ) . '">' . $plugin_data['Author'] . '</a>';
   561 							$author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
   415 						$plugin_meta[] = sprintf( __( 'By %s' ), $author );
   562 						$plugin_meta[] = sprintf( __( 'By %s' ), $author );
   416 					}
   563 					}
   417 					if ( ! empty( $plugin_data['PluginURI'] ) )
   564 
   418 						$plugin_meta[] = '<a href="' . $plugin_data['PluginURI'] . '" title="' . esc_attr__( 'Visit plugin site' ) . '">' . __( 'Visit plugin site' ) . '</a>';
   565 					// Details link using API info, if available
   419 
   566 					if ( isset( $plugin_data['slug'] ) && current_user_can( 'install_plugins' ) ) {
       
   567 						$plugin_meta[] = sprintf( '<a href="%s" class="thickbox" aria-label="%s" data-title="%s">%s</a>',
       
   568 							esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $plugin_data['slug'] .
       
   569 								'&TB_iframe=true&width=600&height=550' ) ),
       
   570 							esc_attr( sprintf( __( 'More information about %s' ), $plugin_name ) ),
       
   571 							esc_attr( $plugin_name ),
       
   572 							__( 'View details' )
       
   573 						);
       
   574 					} elseif ( ! empty( $plugin_data['PluginURI'] ) ) {
       
   575 						$plugin_meta[] = sprintf( '<a href="%s">%s</a>',
       
   576 							esc_url( $plugin_data['PluginURI'] ),
       
   577 							__( 'Visit plugin site' )
       
   578 						);
       
   579 					}
       
   580 
       
   581 					/**
       
   582 					 * Filter the array of row meta for each plugin in the Plugins list table.
       
   583 					 *
       
   584 					 * @since 2.8.0
       
   585 					 *
       
   586 					 * @param array  $plugin_meta An array of the plugin's metadata,
       
   587 					 *                            including the version, author,
       
   588 					 *                            author URI, and plugin URI.
       
   589 					 * @param string $plugin_file Path to the plugin file, relative to the plugins directory.
       
   590 					 * @param array  $plugin_data An array of plugin data.
       
   591 					 * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
       
   592 					 *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
       
   593 					 *                            'Drop-ins', 'Search'.
       
   594 					 */
   420 					$plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
   595 					$plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
   421 					echo implode( ' | ', $plugin_meta );
   596 					echo implode( ' | ', $plugin_meta );
   422 
   597 
   423 					echo "</div></td>";
   598 					echo "</div></td>";
   424 					break;
   599 					break;
   425 				default:
   600 				default:
   426 					echo "<td class='$column_name column-$column_name'$style>";
   601 					echo "<td class='$column_name column-$column_name'$style>";
       
   602 
       
   603 					/**
       
   604 					 * Fires inside each custom column of the Plugins list table.
       
   605 					 *
       
   606 					 * @since 3.1.0
       
   607 					 *
       
   608 					 * @param string $column_name Name of the column.
       
   609 					 * @param string $plugin_file Path to the plugin file.
       
   610 					 * @param array  $plugin_data An array of plugin data.
       
   611 					 */
   427 					do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
   612 					do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
   428 					echo "</td>";
   613 					echo "</td>";
   429 			}
   614 			}
   430 		}
   615 		}
   431 
   616 
   432 		echo "</tr>";
   617 		echo "</tr>";
   433 
   618 
       
   619 		/**
       
   620 		 * Fires after each row in the Plugins list table.
       
   621 		 *
       
   622 		 * @since 2.3.0
       
   623 		 *
       
   624 		 * @param string $plugin_file Path to the plugin file, relative to the plugins directory.
       
   625 		 * @param array  $plugin_data An array of plugin data.
       
   626 		 * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
       
   627 		 *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
       
   628 		 *                            'Drop-ins', 'Search'.
       
   629 		 */
   434 		do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
   630 		do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
       
   631 
       
   632 		/**
       
   633 		 * Fires after each specific row in the Plugins list table.
       
   634 		 *
       
   635 		 * The dynamic portion of the hook name, `$plugin_file`, refers to the path
       
   636 		 * to the plugin file, relative to the plugins directory.
       
   637 		 *
       
   638 		 * @since 2.7.0
       
   639 		 *
       
   640 		 * @param string $plugin_file Path to the plugin file, relative to the plugins directory.
       
   641 		 * @param array  $plugin_data An array of plugin data.
       
   642 		 * @param string $status      Status of the plugin. Defaults are 'All', 'Active',
       
   643 		 *                            'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
       
   644 		 *                            'Drop-ins', 'Search'.
       
   645 		 */
   435 		do_action( "after_plugin_row_$plugin_file", $plugin_file, $plugin_data, $status );
   646 		do_action( "after_plugin_row_$plugin_file", $plugin_file, $plugin_data, $status );
   436 	}
   647 	}
   437 }
   648 }