PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-admin/includes/class-wp-ms-themes-list-table.php

https://gitlab.com/webkod3r/tripolis
PHP | 727 lines | 379 code | 105 blank | 243 comment | 71 complexity | d0f4bfec5843115b2143d2adf0ec7985 MD5 | raw file
  1. <?php
  2. /**
  3. * List Table API: WP_MS_Themes_List_Table class
  4. *
  5. * @package WordPress
  6. * @subpackage Administration
  7. * @since 3.1.0
  8. */
  9. /**
  10. * Core class used to implement displaying themes in a list table for the network admin.
  11. *
  12. * @since 3.1.0
  13. * @access private
  14. *
  15. * @see WP_List_Table
  16. */
  17. class WP_MS_Themes_List_Table extends WP_List_Table {
  18. public $site_id;
  19. public $is_site_themes;
  20. private $has_items;
  21. /**
  22. * Constructor.
  23. *
  24. * @since 3.1.0
  25. * @access public
  26. *
  27. * @see WP_List_Table::__construct() for more information on default arguments.
  28. *
  29. * @global string $status
  30. * @global int $page
  31. *
  32. * @param array $args An associative array of arguments.
  33. */
  34. public function __construct( $args = array() ) {
  35. global $status, $page;
  36. parent::__construct( array(
  37. 'plural' => 'themes',
  38. 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
  39. ) );
  40. $status = isset( $_REQUEST['theme_status'] ) ? $_REQUEST['theme_status'] : 'all';
  41. if ( !in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken' ) ) )
  42. $status = 'all';
  43. $page = $this->get_pagenum();
  44. $this->is_site_themes = ( 'site-themes-network' === $this->screen->id ) ? true : false;
  45. if ( $this->is_site_themes )
  46. $this->site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
  47. }
  48. /**
  49. *
  50. * @return array
  51. */
  52. protected function get_table_classes() {
  53. // todo: remove and add CSS for .themes
  54. return array( 'widefat', 'plugins' );
  55. }
  56. /**
  57. *
  58. * @return bool
  59. */
  60. public function ajax_user_can() {
  61. if ( $this->is_site_themes )
  62. return current_user_can( 'manage_sites' );
  63. else
  64. return current_user_can( 'manage_network_themes' );
  65. }
  66. /**
  67. *
  68. * @global string $status
  69. * @global array $totals
  70. * @global int $page
  71. * @global string $orderby
  72. * @global string $order
  73. * @global string $s
  74. */
  75. public function prepare_items() {
  76. global $status, $totals, $page, $orderby, $order, $s;
  77. wp_reset_vars( array( 'orderby', 'order', 's' ) );
  78. $themes = array(
  79. /**
  80. * Filter the full array of WP_Theme objects to list in the Multisite
  81. * themes list table.
  82. *
  83. * @since 3.1.0
  84. *
  85. * @param array $all An array of WP_Theme objects to display in the list table.
  86. */
  87. 'all' => apply_filters( 'all_themes', wp_get_themes() ),
  88. 'search' => array(),
  89. 'enabled' => array(),
  90. 'disabled' => array(),
  91. 'upgrade' => array(),
  92. 'broken' => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ),
  93. );
  94. if ( $this->is_site_themes ) {
  95. $themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' );
  96. $allowed_where = 'site';
  97. } else {
  98. $themes_per_page = $this->get_items_per_page( 'themes_network_per_page' );
  99. $allowed_where = 'network';
  100. }
  101. $maybe_update = current_user_can( 'update_themes' ) && ! $this->is_site_themes && $current = get_site_transient( 'update_themes' );
  102. foreach ( (array) $themes['all'] as $key => $theme ) {
  103. if ( $this->is_site_themes && $theme->is_allowed( 'network' ) ) {
  104. unset( $themes['all'][ $key ] );
  105. continue;
  106. }
  107. if ( $maybe_update && isset( $current->response[ $key ] ) ) {
  108. $themes['all'][ $key ]->update = true;
  109. $themes['upgrade'][ $key ] = $themes['all'][ $key ];
  110. }
  111. $filter = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled';
  112. $themes[ $filter ][ $key ] = $themes['all'][ $key ];
  113. }
  114. if ( $s ) {
  115. $status = 'search';
  116. $themes['search'] = array_filter( array_merge( $themes['all'], $themes['broken'] ), array( $this, '_search_callback' ) );
  117. }
  118. $totals = array();
  119. foreach ( $themes as $type => $list )
  120. $totals[ $type ] = count( $list );
  121. if ( empty( $themes[ $status ] ) && !in_array( $status, array( 'all', 'search' ) ) )
  122. $status = 'all';
  123. $this->items = $themes[ $status ];
  124. WP_Theme::sort_by_name( $this->items );
  125. $this->has_items = ! empty( $themes['all'] );
  126. $total_this_page = $totals[ $status ];
  127. if ( $orderby ) {
  128. $orderby = ucfirst( $orderby );
  129. $order = strtoupper( $order );
  130. if ( $orderby === 'Name' ) {
  131. if ( 'ASC' === $order ) {
  132. $this->items = array_reverse( $this->items );
  133. }
  134. } else {
  135. uasort( $this->items, array( $this, '_order_callback' ) );
  136. }
  137. }
  138. $start = ( $page - 1 ) * $themes_per_page;
  139. if ( $total_this_page > $themes_per_page )
  140. $this->items = array_slice( $this->items, $start, $themes_per_page, true );
  141. $this->set_pagination_args( array(
  142. 'total_items' => $total_this_page,
  143. 'per_page' => $themes_per_page,
  144. ) );
  145. }
  146. /**
  147. * @staticvar string $term
  148. * @param WP_Theme $theme
  149. * @return bool
  150. */
  151. public function _search_callback( $theme ) {
  152. static $term = null;
  153. if ( is_null( $term ) )
  154. $term = wp_unslash( $_REQUEST['s'] );
  155. foreach ( array( 'Name', 'Description', 'Author', 'Author', 'AuthorURI' ) as $field ) {
  156. // Don't mark up; Do translate.
  157. if ( false !== stripos( $theme->display( $field, false, true ), $term ) )
  158. return true;
  159. }
  160. if ( false !== stripos( $theme->get_stylesheet(), $term ) )
  161. return true;
  162. if ( false !== stripos( $theme->get_template(), $term ) )
  163. return true;
  164. return false;
  165. }
  166. // Not used by any core columns.
  167. /**
  168. * @global string $orderby
  169. * @global string $order
  170. * @param array $theme_a
  171. * @param array $theme_b
  172. * @return int
  173. */
  174. public function _order_callback( $theme_a, $theme_b ) {
  175. global $orderby, $order;
  176. $a = $theme_a[ $orderby ];
  177. $b = $theme_b[ $orderby ];
  178. if ( $a == $b )
  179. return 0;
  180. if ( 'DESC' === $order )
  181. return ( $a < $b ) ? 1 : -1;
  182. else
  183. return ( $a < $b ) ? -1 : 1;
  184. }
  185. /**
  186. * @access public
  187. */
  188. public function no_items() {
  189. if ( $this->has_items ) {
  190. _e( 'No themes found.' );
  191. } else {
  192. _e( 'You do not appear to have any themes available at this time.' );
  193. }
  194. }
  195. /**
  196. *
  197. * @return array
  198. */
  199. public function get_columns() {
  200. return array(
  201. 'cb' => '<input type="checkbox" />',
  202. 'name' => __( 'Theme' ),
  203. 'description' => __( 'Description' ),
  204. );
  205. }
  206. /**
  207. *
  208. * @return array
  209. */
  210. protected function get_sortable_columns() {
  211. return array(
  212. 'name' => 'name',
  213. );
  214. }
  215. /**
  216. * Gets the name of the primary column.
  217. *
  218. * @since 4.3.0
  219. * @access protected
  220. *
  221. * @return string Unalterable name of the primary column name, in this case, 'name'.
  222. */
  223. protected function get_primary_column_name() {
  224. return 'name';
  225. }
  226. /**
  227. *
  228. * @global array $totals
  229. * @global string $status
  230. * @return array
  231. */
  232. protected function get_views() {
  233. global $totals, $status;
  234. $status_links = array();
  235. foreach ( $totals as $type => $count ) {
  236. if ( !$count )
  237. continue;
  238. switch ( $type ) {
  239. case 'all':
  240. $text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'themes' );
  241. break;
  242. case 'enabled':
  243. $text = _n( 'Enabled <span class="count">(%s)</span>', 'Enabled <span class="count">(%s)</span>', $count );
  244. break;
  245. case 'disabled':
  246. $text = _n( 'Disabled <span class="count">(%s)</span>', 'Disabled <span class="count">(%s)</span>', $count );
  247. break;
  248. case 'upgrade':
  249. $text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
  250. break;
  251. case 'broken' :
  252. $text = _n( 'Broken <span class="count">(%s)</span>', 'Broken <span class="count">(%s)</span>', $count );
  253. break;
  254. }
  255. if ( $this->is_site_themes )
  256. $url = 'site-themes.php?id=' . $this->site_id;
  257. else
  258. $url = 'themes.php';
  259. if ( 'search' != $type ) {
  260. $status_links[$type] = sprintf( "<a href='%s' %s>%s</a>",
  261. esc_url( add_query_arg('theme_status', $type, $url) ),
  262. ( $type === $status ) ? ' class="current"' : '',
  263. sprintf( $text, number_format_i18n( $count ) )
  264. );
  265. }
  266. }
  267. return $status_links;
  268. }
  269. /**
  270. * @global string $status
  271. *
  272. * @return array
  273. */
  274. protected function get_bulk_actions() {
  275. global $status;
  276. $actions = array();
  277. if ( 'enabled' != $status )
  278. $actions['enable-selected'] = $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' );
  279. if ( 'disabled' != $status )
  280. $actions['disable-selected'] = $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' );
  281. if ( ! $this->is_site_themes ) {
  282. if ( current_user_can( 'update_themes' ) )
  283. $actions['update-selected'] = __( 'Update' );
  284. if ( current_user_can( 'delete_themes' ) )
  285. $actions['delete-selected'] = __( 'Delete' );
  286. }
  287. return $actions;
  288. }
  289. /**
  290. * @access public
  291. */
  292. public function display_rows() {
  293. foreach ( $this->items as $theme )
  294. $this->single_row( $theme );
  295. }
  296. /**
  297. * Handles the checkbox column output.
  298. *
  299. * @since 4.3.0
  300. * @access public
  301. *
  302. * @param WP_Theme $theme The current WP_Theme object.
  303. */
  304. public function column_cb( $theme ) {
  305. $checkbox_id = 'checkbox_' . md5( $theme->get('Name') );
  306. ?>
  307. <input type="checkbox" name="checked[]" value="<?php echo esc_attr( $theme->get_stylesheet() ) ?>" id="<?php echo $checkbox_id ?>" />
  308. <label class="screen-reader-text" for="<?php echo $checkbox_id ?>" ><?php _e( 'Select' ) ?> <?php echo $theme->display( 'Name' ) ?></label>
  309. <?php
  310. }
  311. /**
  312. * Handles the name column output.
  313. *
  314. * @since 4.3.0
  315. * @access public
  316. *
  317. * @global string $status
  318. * @global int $page
  319. * @global string $s
  320. *
  321. * @param WP_Theme $theme The current WP_Theme object.
  322. */
  323. public function column_name( $theme ) {
  324. global $status, $page, $s;
  325. $context = $status;
  326. if ( $this->is_site_themes ) {
  327. $url = "site-themes.php?id={$this->site_id}&amp;";
  328. $allowed = $theme->is_allowed( 'site', $this->site_id );
  329. } else {
  330. $url = 'themes.php?';
  331. $allowed = $theme->is_allowed( 'network' );
  332. }
  333. // Pre-order.
  334. $actions = array(
  335. 'enable' => '',
  336. 'disable' => '',
  337. 'edit' => '',
  338. 'delete' => ''
  339. );
  340. $stylesheet = $theme->get_stylesheet();
  341. $theme_key = urlencode( $stylesheet );
  342. if ( ! $allowed ) {
  343. if ( ! $theme->errors() ) {
  344. $url = add_query_arg( array(
  345. 'action' => 'enable',
  346. 'theme' => $theme_key,
  347. 'paged' => $page,
  348. 's' => $s,
  349. ), $url );
  350. if ( $this->is_site_themes ) {
  351. /* translators: %s: theme name */
  352. $aria_label = sprintf( __( 'Enable %s' ), $theme->display( 'Name' ) );
  353. } else {
  354. /* translators: %s: theme name */
  355. $aria_label = sprintf( __( 'Network Enable %s' ), $theme->display( 'Name' ) );
  356. }
  357. $actions['enable'] = sprintf( '<a href="%s" class="edit" aria-label="%s">%s</a>',
  358. esc_url( wp_nonce_url( $url, 'enable-theme_' . $stylesheet ) ),
  359. esc_attr( $aria_label ),
  360. ( $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ) )
  361. );
  362. }
  363. } else {
  364. $url = add_query_arg( array(
  365. 'action' => 'disable',
  366. 'theme' => $theme_key,
  367. 'paged' => $page,
  368. 's' => $s,
  369. ), $url );
  370. if ( $this->is_site_themes ) {
  371. /* translators: %s: theme name */
  372. $aria_label = sprintf( __( 'Disable %s' ), $theme->display( 'Name' ) );
  373. } else {
  374. /* translators: %s: theme name */
  375. $aria_label = sprintf( __( 'Network Disable %s' ), $theme->display( 'Name' ) );
  376. }
  377. $actions['disable'] = sprintf( '<a href="%s" aria-label="%s">%s</a>',
  378. esc_url( wp_nonce_url( $url, 'disable-theme_' . $stylesheet ) ),
  379. esc_attr( $aria_label ),
  380. ( $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ) )
  381. );
  382. }
  383. if ( current_user_can('edit_themes') ) {
  384. $url = add_query_arg( array(
  385. 'theme' => $theme_key,
  386. ), 'theme-editor.php' );
  387. /* translators: %s: theme name */
  388. $aria_label = sprintf( __( 'Open %s in the Theme Editor' ), $theme->display( 'Name' ) );
  389. $actions['edit'] = sprintf( '<a href="%s" class="edit" aria-label="%s">%s</a>',
  390. esc_url( $url ),
  391. esc_attr( $aria_label ),
  392. __( 'Edit' )
  393. );
  394. }
  395. if ( ! $allowed && current_user_can( 'delete_themes' ) && ! $this->is_site_themes && $stylesheet != get_option( 'stylesheet' ) && $stylesheet != get_option( 'template' ) ) {
  396. $url = add_query_arg( array(
  397. 'action' => 'delete-selected',
  398. 'checked[]' => $theme_key,
  399. 'theme_status' => $context,
  400. 'paged' => $page,
  401. 's' => $s,
  402. ), 'themes.php' );
  403. /* translators: %s: theme name */
  404. $aria_label = sprintf( __( 'Delete %s' ), $theme->display( 'Name' ) );
  405. $actions['delete'] = sprintf( '<a href="%s" class="delete" aria-label="%s">%s</a>',
  406. esc_url( wp_nonce_url( $url, 'bulk-themes' ) ),
  407. esc_attr( $aria_label ),
  408. __( 'Delete' )
  409. );
  410. }
  411. /**
  412. * Filter the action links displayed for each theme in the Multisite
  413. * themes list table.
  414. *
  415. * The action links displayed are determined by the theme's status, and
  416. * which Multisite themes list table is being displayed - the Network
  417. * themes list table (themes.php), which displays all installed themes,
  418. * or the Site themes list table (site-themes.php), which displays the
  419. * non-network enabled themes when editing a site in the Network admin.
  420. *
  421. * The default action links for the Network themes list table include
  422. * 'Network Enable', 'Network Disable', 'Edit', and 'Delete'.
  423. *
  424. * The default action links for the Site themes list table include
  425. * 'Enable', 'Disable', and 'Edit'.
  426. *
  427. * @since 2.8.0
  428. *
  429. * @param array $actions An array of action links.
  430. * @param WP_Theme $theme The current WP_Theme object.
  431. * @param string $context Status of the theme.
  432. */
  433. $actions = apply_filters( 'theme_action_links', array_filter( $actions ), $theme, $context );
  434. /**
  435. * Filter the action links of a specific theme in the Multisite themes
  436. * list table.
  437. *
  438. * The dynamic portion of the hook name, `$stylesheet`, refers to the
  439. * directory name of the theme, which in most cases is synonymous
  440. * with the template name.
  441. *
  442. * @since 3.1.0
  443. *
  444. * @param array $actions An array of action links.
  445. * @param WP_Theme $theme The current WP_Theme object.
  446. * @param string $context Status of the theme.
  447. */
  448. $actions = apply_filters( "theme_action_links_$stylesheet", $actions, $theme, $context );
  449. echo $this->row_actions( $actions, true );
  450. }
  451. /**
  452. * Handles the description column output.
  453. *
  454. * @since 4.3.0
  455. * @access public
  456. *
  457. * @global string $status
  458. * @global array $totals
  459. *
  460. * @param WP_Theme $theme The current WP_Theme object.
  461. */
  462. public function column_description( $theme ) {
  463. global $status, $totals;
  464. if ( $theme->errors() ) {
  465. $pre = $status === 'broken' ? __( 'Broken Theme:' ) . ' ' : '';
  466. echo '<p><strong class="error-message">' . $pre . $theme->errors()->get_error_message() . '</strong></p>';
  467. }
  468. if ( $this->is_site_themes ) {
  469. $allowed = $theme->is_allowed( 'site', $this->site_id );
  470. } else {
  471. $allowed = $theme->is_allowed( 'network' );
  472. }
  473. $class = ! $allowed ? 'inactive' : 'active';
  474. if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) )
  475. $class .= ' update';
  476. echo "<div class='theme-description'><p>" . $theme->display( 'Description' ) . "</p></div>
  477. <div class='$class second theme-version-author-uri'>";
  478. $stylesheet = $theme->get_stylesheet();
  479. $theme_meta = array();
  480. if ( $theme->get('Version') ) {
  481. $theme_meta[] = sprintf( __( 'Version %s' ), $theme->display('Version') );
  482. }
  483. $theme_meta[] = sprintf( __( 'By %s' ), $theme->display('Author') );
  484. if ( $theme->get('ThemeURI') ) {
  485. /* translators: %s: theme name */
  486. $aria_label = sprintf( __( 'Visit %s homepage' ), $theme->display( 'Name' ) );
  487. $theme_meta[] = sprintf( '<a href="%s" aria-label="%s">%s</a>',
  488. $theme->display( 'ThemeURI' ),
  489. esc_attr( $aria_label ),
  490. __( 'Visit Theme Site' )
  491. );
  492. }
  493. /**
  494. * Filter the array of row meta for each theme in the Multisite themes
  495. * list table.
  496. *
  497. * @since 3.1.0
  498. *
  499. * @param array $theme_meta An array of the theme's metadata,
  500. * including the version, author, and
  501. * theme URI.
  502. * @param string $stylesheet Directory name of the theme.
  503. * @param WP_Theme $theme WP_Theme object.
  504. * @param string $status Status of the theme.
  505. */
  506. $theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status );
  507. echo implode( ' | ', $theme_meta );
  508. echo '</div>';
  509. }
  510. /**
  511. * Handles default column output.
  512. *
  513. * @since 4.3.0
  514. * @access public
  515. *
  516. * @param WP_Theme $theme The current WP_Theme object.
  517. * @param string $column_name The current column name.
  518. */
  519. public function column_default( $theme, $column_name ) {
  520. $stylesheet = $theme->get_stylesheet();
  521. /**
  522. * Fires inside each custom column of the Multisite themes list table.
  523. *
  524. * @since 3.1.0
  525. *
  526. * @param string $column_name Name of the column.
  527. * @param string $stylesheet Directory name of the theme.
  528. * @param WP_Theme $theme Current WP_Theme object.
  529. */
  530. do_action( 'manage_themes_custom_column', $column_name, $stylesheet, $theme );
  531. }
  532. /**
  533. * Handles the output for a single table row.
  534. *
  535. * @since 4.3.0
  536. * @access public
  537. *
  538. * @param WP_Theme $item The current WP_Theme object.
  539. */
  540. public function single_row_columns( $item ) {
  541. list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
  542. foreach ( $columns as $column_name => $column_display_name ) {
  543. $extra_classes = '';
  544. if ( in_array( $column_name, $hidden ) ) {
  545. $extra_classes .= ' hidden';
  546. }
  547. switch ( $column_name ) {
  548. case 'cb':
  549. echo '<th scope="row" class="check-column">';
  550. $this->column_cb( $item );
  551. echo '</th>';
  552. break;
  553. case 'name':
  554. echo "<td class='theme-title column-primary{$extra_classes}'><strong>" . $item->display('Name') . "</strong>";
  555. $this->column_name( $item );
  556. echo "</td>";
  557. break;
  558. case 'description':
  559. echo "<td class='column-description desc{$extra_classes}'>";
  560. $this->column_description( $item );
  561. echo '</td>';
  562. break;
  563. default:
  564. echo "<td class='$column_name column-$column_name{$extra_classes}'>";
  565. $this->column_default( $item, $column_name );
  566. echo "</td>";
  567. break;
  568. }
  569. }
  570. }
  571. /**
  572. * @global string $status
  573. * @global array $totals
  574. *
  575. * @param WP_Theme $theme
  576. */
  577. public function single_row( $theme ) {
  578. global $status, $totals;
  579. if ( $this->is_site_themes ) {
  580. $allowed = $theme->is_allowed( 'site', $this->site_id );
  581. } else {
  582. $allowed = $theme->is_allowed( 'network' );
  583. }
  584. $stylesheet = $theme->get_stylesheet();
  585. $class = ! $allowed ? 'inactive' : 'active';
  586. if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) ) {
  587. $class .= ' update';
  588. }
  589. printf( '<tr class="%s" data-slug="%s">',
  590. esc_attr( $class ),
  591. esc_attr( $stylesheet )
  592. );
  593. $this->single_row_columns( $theme );
  594. echo "</tr>";
  595. if ( $this->is_site_themes )
  596. remove_action( "after_theme_row_$stylesheet", 'wp_theme_update_row' );
  597. /**
  598. * Fires after each row in the Multisite themes list table.
  599. *
  600. * @since 3.1.0
  601. *
  602. * @param string $stylesheet Directory name of the theme.
  603. * @param WP_Theme $theme Current WP_Theme object.
  604. * @param string $status Status of the theme.
  605. */
  606. do_action( 'after_theme_row', $stylesheet, $theme, $status );
  607. /**
  608. * Fires after each specific row in the Multisite themes list table.
  609. *
  610. * The dynamic portion of the hook name, `$stylesheet`, refers to the
  611. * directory name of the theme, most often synonymous with the template
  612. * name of the theme.
  613. *
  614. * @since 3.5.0
  615. *
  616. * @param string $stylesheet Directory name of the theme.
  617. * @param WP_Theme $theme Current WP_Theme object.
  618. * @param string $status Status of the theme.
  619. */
  620. do_action( "after_theme_row_$stylesheet", $stylesheet, $theme, $status );
  621. }
  622. }