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