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