WordPress 4.5
[autoinstalls/wordpress.git] / wp-admin / includes / class-wp-ms-sites-list-table.php
1 <?php
2 /**
3  * List Table API: WP_MS_Sites_List_Table class
4  *
5  * @package WordPress
6  * @subpackage Administration
7  * @since 3.1.0
8  */
9
10 /**
11  * Core class used to implement displaying sites in a list table for the network admin.
12  *
13  * @since 3.1.0
14  * @access private
15  *
16  * @see WP_List_Table
17  */
18 class WP_MS_Sites_List_Table extends WP_List_Table {
19
20         /**
21          * Site status list.
22          *
23          * @since 4.3.0
24          * @access public
25          * @var array
26          */
27         public $status_list;
28
29         /**
30          * Constructor.
31          *
32          * @since 3.1.0
33          * @access public
34          *
35          * @see WP_List_Table::__construct() for more information on default arguments.
36          *
37          * @param array $args An associative array of arguments.
38          */
39         public function __construct( $args = array() ) {
40                 $this->status_list = array(
41                         'archived' => array( 'site-archived', __( 'Archived' ) ),
42                         'spam'     => array( 'site-spammed', _x( 'Spam', 'site' ) ),
43                         'deleted'  => array( 'site-deleted', __( 'Deleted' ) ),
44                         'mature'   => array( 'site-mature', __( 'Mature' ) )
45                 );
46
47                 parent::__construct( array(
48                         'plural' => 'sites',
49                         'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
50                 ) );
51         }
52
53         /**
54          *
55          * @return bool
56          */
57         public function ajax_user_can() {
58                 return current_user_can( 'manage_sites' );
59         }
60
61         /**
62          *
63          * @global string $s
64          * @global string $mode
65          * @global wpdb   $wpdb
66          */
67         public function prepare_items() {
68                 global $s, $mode, $wpdb;
69
70                 $current_site = get_current_site();
71
72                 if ( ! empty( $_REQUEST['mode'] ) ) {
73                         $mode = $_REQUEST['mode'] === 'excerpt' ? 'excerpt' : 'list';
74                         set_user_setting( 'sites_list_mode', $mode );
75                 } else {
76                         $mode = get_user_setting( 'sites_list_mode', 'list' );
77                 }
78
79                 $per_page = $this->get_items_per_page( 'sites_network_per_page' );
80
81                 $pagenum = $this->get_pagenum();
82
83                 $s = isset( $_REQUEST['s'] ) ? wp_unslash( trim( $_REQUEST[ 's' ] ) ) : '';
84                 $wild = '';
85                 if ( false !== strpos($s, '*') ) {
86                         $wild = '%';
87                         $s = trim($s, '*');
88                 }
89
90                 /*
91                  * If the network is large and a search is not being performed, show only
92                  * the latest sites with no paging in order to avoid expensive count queries.
93                  */
94                 if ( !$s && wp_is_large_network() ) {
95                         if ( !isset($_REQUEST['orderby']) )
96                                 $_GET['orderby'] = $_REQUEST['orderby'] = '';
97                         if ( !isset($_REQUEST['order']) )
98                                 $_GET['order'] = $_REQUEST['order'] = 'DESC';
99                 }
100
101                 $query = "SELECT * FROM {$wpdb->blogs} WHERE site_id = '{$wpdb->siteid}' ";
102
103                 if ( empty($s) ) {
104                         // Nothing to do.
105                 } elseif ( preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $s ) ||
106                                         preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.?$/', $s ) ||
107                                         preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.?$/', $s ) ||
108                                         preg_match( '/^[0-9]{1,3}\.$/', $s ) ) {
109                         // IPv4 address
110                         $sql = $wpdb->prepare( "SELECT blog_id FROM {$wpdb->registration_log} WHERE {$wpdb->registration_log}.IP LIKE %s", $wpdb->esc_like( $s ) . $wild );
111                         $reg_blog_ids = $wpdb->get_col( $sql );
112
113                         if ( !$reg_blog_ids )
114                                 $reg_blog_ids = array( 0 );
115
116                         $query = "SELECT *
117                                 FROM {$wpdb->blogs}
118                                 WHERE site_id = '{$wpdb->siteid}'
119                                 AND {$wpdb->blogs}.blog_id IN (" . implode( ', ', $reg_blog_ids ) . ")";
120                 } else {
121                         if ( is_numeric($s) && empty( $wild ) ) {
122                                 $query .= $wpdb->prepare( " AND ( {$wpdb->blogs}.blog_id = %s )", $s );
123                         } elseif ( is_subdomain_install() ) {
124                                 $blog_s = str_replace( '.' . $current_site->domain, '', $s );
125                                 $blog_s = $wpdb->esc_like( $blog_s ) . $wild . $wpdb->esc_like( '.' . $current_site->domain );
126                                 $query .= $wpdb->prepare( " AND ( {$wpdb->blogs}.domain LIKE %s ) ", $blog_s );
127                         } else {
128                                 if ( $s != trim('/', $current_site->path) ) {
129                                         $blog_s = $wpdb->esc_like( $current_site->path . $s ) . $wild . $wpdb->esc_like( '/' );
130                                 } else {
131                                         $blog_s = $wpdb->esc_like( $s );
132                                 }
133                                 $query .= $wpdb->prepare( " AND  ( {$wpdb->blogs}.path LIKE %s )", $blog_s );
134                         }
135                 }
136
137                 $order_by = isset( $_REQUEST['orderby'] ) ? $_REQUEST['orderby'] : '';
138                 if ( $order_by === 'registered' ) {
139                         $query .= ' ORDER BY registered ';
140                 } elseif ( $order_by === 'lastupdated' ) {
141                         $query .= ' ORDER BY last_updated ';
142                 } elseif ( $order_by === 'blogname' ) {
143                         if ( is_subdomain_install() ) {
144                                 $query .= ' ORDER BY domain ';
145                         } else {
146                                 $query .= ' ORDER BY path ';
147                         }
148                 } elseif ( $order_by === 'blog_id' ) {
149                         $query .= ' ORDER BY blog_id ';
150                 } else {
151                         $order_by = null;
152                 }
153
154                 if ( isset( $order_by ) ) {
155                         $order = ( isset( $_REQUEST['order'] ) && 'DESC' === strtoupper( $_REQUEST['order'] ) ) ? "DESC" : "ASC";
156                         $query .= $order;
157                 }
158
159                 // Don't do an unbounded count on large networks
160                 if ( ! wp_is_large_network() )
161                         $total = $wpdb->get_var( str_replace( 'SELECT *', 'SELECT COUNT( blog_id )', $query ) );
162
163                 $query .= " LIMIT " . intval( ( $pagenum - 1 ) * $per_page ) . ", " . intval( $per_page );
164                 $this->items = $wpdb->get_results( $query, ARRAY_A );
165
166                 if ( wp_is_large_network() )
167                         $total = count($this->items);
168
169                 $this->set_pagination_args( array(
170                         'total_items' => $total,
171                         'per_page' => $per_page,
172                 ) );
173         }
174
175         /**
176          * @access public
177          */
178         public function no_items() {
179                 _e( 'No sites found.' );
180         }
181
182         /**
183          *
184          * @return array
185          */
186         protected function get_bulk_actions() {
187                 $actions = array();
188                 if ( current_user_can( 'delete_sites' ) )
189                         $actions['delete'] = __( 'Delete' );
190                 $actions['spam'] = _x( 'Mark as Spam', 'site' );
191                 $actions['notspam'] = _x( 'Not Spam', 'site' );
192
193                 return $actions;
194         }
195
196         /**
197          * @global string $mode
198          *
199          * @param string $which
200          */
201         protected function pagination( $which ) {
202                 global $mode;
203
204                 parent::pagination( $which );
205
206                 if ( 'top' === $which )
207                         $this->view_switcher( $mode );
208         }
209
210         /**
211          * @return array
212          */
213         public function get_columns() {
214                 $sites_columns = array(
215                         'cb'          => '<input type="checkbox" />',
216                         'blogname'    => __( 'URL' ),
217                         'lastupdated' => __( 'Last Updated' ),
218                         'registered'  => _x( 'Registered', 'site' ),
219                         'users'       => __( 'Users' ),
220                 );
221
222                 if ( has_filter( 'wpmublogsaction' ) ) {
223                         $sites_columns['plugins'] = __( 'Actions' );
224                 }
225
226                 /**
227                  * Filter the displayed site columns in Sites list table.
228                  *
229                  * @since MU
230                  *
231                  * @param array $sites_columns An array of displayed site columns. Default 'cb',
232                  *                             'blogname', 'lastupdated', 'registered', 'users'.
233                  */
234                 return apply_filters( 'wpmu_blogs_columns', $sites_columns );
235         }
236
237         /**
238          * @return array
239          */
240         protected function get_sortable_columns() {
241                 return array(
242                         'blogname'    => 'blogname',
243                         'lastupdated' => 'lastupdated',
244                         'registered'  => 'blog_id',
245                 );
246         }
247
248         /**
249          * Handles the checkbox column output.
250          *
251          * @since 4.3.0
252          * @access public
253          *
254          * @param array $blog Current site.
255          */
256         public function column_cb( $blog ) {
257                 if ( ! is_main_site( $blog['blog_id'] ) ) :
258                         $blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
259                 ?>
260                         <label class="screen-reader-text" for="blog_<?php echo $blog['blog_id']; ?>"><?php
261                                 printf( __( 'Select %s' ), $blogname );
262                         ?></label>
263                         <input type="checkbox" id="blog_<?php echo $blog['blog_id'] ?>" name="allblogs[]" value="<?php echo esc_attr( $blog['blog_id'] ) ?>" />
264                 <?php endif;
265         }
266
267         /**
268          * Handles the ID column output.
269          *
270          * @since 4.4.0
271          * @access public
272          *
273          * @param array $blog Current site.
274          */
275         public function column_id( $blog ) {
276                 echo $blog['blog_id'];
277         }
278
279         /**
280          * Handles the site name column output.
281          *
282          * @since 4.3.0
283          * @access public
284          *
285          * @global string $mode
286          *
287          * @param array $blog Current site.
288          */
289         public function column_blogname( $blog ) {
290                 global $mode;
291
292                 $blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
293                 $blog_states = array();
294                 reset( $this->status_list );
295
296                 foreach ( $this->status_list as $status => $col ) {
297                         if ( $blog[ $status ] == 1 ) {
298                                 $blog_states[] = $col[1];
299                         }
300                 }
301                 $blog_state = '';
302                 if ( ! empty( $blog_states ) ) {
303                         $state_count = count( $blog_states );
304                         $i = 0;
305                         $blog_state .= ' - ';
306                         foreach ( $blog_states as $state ) {
307                                 ++$i;
308                                 $sep = ( $i == $state_count ) ? '' : ', ';
309                                 $blog_state .= "<span class='post-state'>$state$sep</span>";
310                         }
311                 }
312
313                 ?>
314                 <a href="<?php echo esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ); ?>" class="edit"><?php echo $blogname . $blog_state; ?></a>
315                 <?php
316                 if ( 'list' !== $mode ) {
317                         switch_to_blog( $blog['blog_id'] );
318                         echo '<p>';
319                         printf(
320                                 /* translators: 1: site name, 2: site tagline. */
321                                 __( '%1$s &#8211; %2$s' ),
322                                 get_option( 'blogname' ),
323                                 '<em>' . get_option( 'blogdescription ' ) . '</em>'
324                         );
325                         echo '</p>';
326                         restore_current_blog();
327                 }
328         }
329
330         /**
331          * Handles the lastupdated column output.
332          *
333          * @since 4.3.0
334          * @access public
335          *
336          * @param array $blog Current site.
337          */
338         public function column_lastupdated( $blog ) {
339                 global $mode;
340
341                 if ( 'list' === $mode ) {
342                         $date = __( 'Y/m/d' );
343                 } else {
344                         $date = __( 'Y/m/d g:i:s a' );
345                 }
346
347                 echo ( $blog['last_updated'] === '0000-00-00 00:00:00' ) ? __( 'Never' ) : mysql2date( $date, $blog['last_updated'] );
348         }
349
350         /**
351          * Handles the registered column output.
352          *
353          * @since 4.3.0
354          * @access public
355          *
356          * @param array $blog Current site.
357          */
358         public function column_registered( $blog ) {
359                 global $mode;
360
361                 if ( 'list' === $mode ) {
362                         $date = __( 'Y/m/d' );
363                 } else {
364                         $date = __( 'Y/m/d g:i:s a' );
365                 }
366
367                 if ( $blog['registered'] === '0000-00-00 00:00:00' ) {
368                         echo '&#x2014;';
369                 } else {
370                         echo mysql2date( $date, $blog['registered'] );
371                 }
372         }
373
374         /**
375          * Handles the users column output.
376          *
377          * @since 4.3.0
378          * @access public
379          *
380          * @param array $blog Current site.
381          */
382         public function column_users( $blog ) {
383                 $user_count = wp_cache_get( $blog['blog_id'] . '_user_count', 'blog-details' );
384                 if ( ! $user_count ) {
385                         $blog_users = get_users( array( 'blog_id' => $blog['blog_id'], 'fields' => 'ID' ) );
386                         $user_count = count( $blog_users );
387                         unset( $blog_users );
388                         wp_cache_set( $blog['blog_id'] . '_user_count', $user_count, 'blog-details', 12 * HOUR_IN_SECONDS );
389                 }
390
391                 printf(
392                         '<a href="%s">%s</a>',
393                         esc_url( network_admin_url( 'site-users.php?id=' . $blog['blog_id'] ) ),
394                         number_format_i18n( $user_count )
395                 );
396         }
397
398         /**
399          * Handles the plugins column output.
400          *
401          * @since 4.3.0
402          * @access public
403          *
404          * @param array $blog Current site.
405          */
406         public function column_plugins( $blog ) {
407                 if ( has_filter( 'wpmublogsaction' ) ) {
408                         /**
409                          * Fires inside the auxiliary 'Actions' column of the Sites list table.
410                          *
411                          * By default this column is hidden unless something is hooked to the action.
412                          *
413                          * @since MU
414                          *
415                          * @param int $blog_id The site ID.
416                          */
417                         do_action( 'wpmublogsaction', $blog['blog_id'] );
418                 }
419         }
420
421         /**
422          * Handles output for the default column.
423          *
424          * @since 4.3.0
425          * @access public
426          *
427          * @param array  $blog        Current site.
428          * @param string $column_name Current column name.
429          */
430         public function column_default( $blog, $column_name ) {
431                 /**
432                  * Fires for each registered custom column in the Sites list table.
433                  *
434                  * @since 3.1.0
435                  *
436                  * @param string $column_name The name of the column to display.
437                  * @param int    $blog_id     The site ID.
438                  */
439                 do_action( 'manage_sites_custom_column', $column_name, $blog['blog_id'] );
440         }
441
442         /**
443          *
444          * @global string $mode
445          */
446         public function display_rows() {
447                 foreach ( $this->items as $blog ) {
448                         $class = '';
449                         reset( $this->status_list );
450
451                         foreach ( $this->status_list as $status => $col ) {
452                                 if ( $blog[ $status ] == 1 ) {
453                                         $class = " class='{$col[0]}'";
454                                 }
455                         }
456
457                         echo "<tr{$class}>";
458
459                         $this->single_row_columns( $blog );
460
461                         echo '</tr>';
462                 }
463         }
464
465         /**
466          * Gets the name of the default primary column.
467          *
468          * @since 4.3.0
469          * @access protected
470          *
471          * @return string Name of the default primary column, in this case, 'blogname'.
472          */
473         protected function get_default_primary_column_name() {
474                 return 'blogname';
475         }
476
477         /**
478          * Generates and displays row action links.
479          *
480          * @since 4.3.0
481          * @access protected
482          *
483          * @param object $blog        Site being acted upon.
484          * @param string $column_name Current column name.
485          * @param string $primary     Primary column name.
486          * @return string Row actions output.
487          */
488         protected function handle_row_actions( $blog, $column_name, $primary ) {
489                 if ( $primary !== $column_name ) {
490                         return;
491                 }
492
493                 $blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
494
495                 // Preordered.
496                 $actions = array(
497                         'edit' => '', 'backend' => '',
498                         'activate' => '', 'deactivate' => '',
499                         'archive' => '', 'unarchive' => '',
500                         'spam' => '', 'unspam' => '',
501                         'delete' => '',
502                         'visit' => '',
503                 );
504
505                 $actions['edit']        = '<a href="' . esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ) . '">' . __( 'Edit' ) . '</a>';
506                 $actions['backend']     = "<a href='" . esc_url( get_admin_url( $blog['blog_id'] ) ) . "' class='edit'>" . __( 'Dashboard' ) . '</a>';
507                 if ( get_current_site()->blog_id != $blog['blog_id'] ) {
508                         if ( $blog['deleted'] == '1' ) {
509                                 $actions['activate']   = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=activateblog&amp;id=' . $blog['blog_id'] ), 'activateblog_' . $blog['blog_id'] ) ) . '">' . __( 'Activate' ) . '</a>';
510                         } else {
511                                 $actions['deactivate'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=deactivateblog&amp;id=' . $blog['blog_id'] ), 'deactivateblog_' . $blog['blog_id'] ) ) . '">' . __( 'Deactivate' ) . '</a>';
512                         }
513
514                         if ( $blog['archived'] == '1' ) {
515                                 $actions['unarchive'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=unarchiveblog&amp;id=' . $blog['blog_id'] ), 'unarchiveblog_' . $blog['blog_id'] ) ) . '">' . __( 'Unarchive' ) . '</a>';
516                         } else {
517                                 $actions['archive']   = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=archiveblog&amp;id=' . $blog['blog_id'] ), 'archiveblog_' . $blog['blog_id'] ) ) . '">' . _x( 'Archive', 'verb; site' ) . '</a>';
518                         }
519
520                         if ( $blog['spam'] == '1' ) {
521                                 $actions['unspam'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=unspamblog&amp;id=' . $blog['blog_id'] ), 'unspamblog_' . $blog['blog_id'] ) ) . '">' . _x( 'Not Spam', 'site' ) . '</a>';
522                         } else {
523                                 $actions['spam']   = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=spamblog&amp;id=' . $blog['blog_id'] ), 'spamblog_' . $blog['blog_id'] ) ) . '">' . _x( 'Spam', 'site' ) . '</a>';
524                         }
525
526                         if ( current_user_can( 'delete_site', $blog['blog_id'] ) ) {
527                                 $actions['delete'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=deleteblog&amp;id=' . $blog['blog_id'] ), 'deleteblog_' . $blog['blog_id'] ) ) . '">' . __( 'Delete' ) . '</a>';
528                         }
529                 }
530
531                 $actions['visit']       = "<a href='" . esc_url( get_home_url( $blog['blog_id'], '/' ) ) . "' rel='permalink'>" . __( 'Visit' ) . '</a>';
532
533                 /**
534                  * Filter the action links displayed for each site in the Sites list table.
535                  *
536                  * The 'Edit', 'Dashboard', 'Delete', and 'Visit' links are displayed by
537                  * default for each site. The site's status determines whether to show the
538                  * 'Activate' or 'Deactivate' link, 'Unarchive' or 'Archive' links, and
539                  * 'Not Spam' or 'Spam' link for each site.
540                  *
541                  * @since 3.1.0
542                  *
543                  * @param array  $actions  An array of action links to be displayed.
544                  * @param int    $blog_id  The site ID.
545                  * @param string $blogname Site path, formatted depending on whether it is a sub-domain
546                  *                         or subdirectory multisite install.
547                  */
548                 $actions = apply_filters( 'manage_sites_action_links', array_filter( $actions ), $blog['blog_id'], $blogname );
549                 return $this->row_actions( $actions );
550         }
551 }