PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-admin/includes/class-wp-plugins-list-table.php

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