From dfeadc373f6900d8787e109b94ffc15dba83e79a Mon Sep 17 00:00:00 2001
From: Paul Biron <paul@sparrowhawkcomputing.com>
Date: Thu, 4 May 2017 20:39:22 -0600
Subject: [PATCH] trac ticket 38071

---
 wp-admin/includes/class-wp-ms-sites-list-table.php | 122 ++++++++++++++++++++-
 wp-admin/network/sites.php                         |   3 +
 wp-includes/ms-functions.php                       |  50 +++++++++
 3 files changed, 174 insertions(+), 1 deletion(-)

diff --git a/wp-admin/includes/class-wp-ms-sites-list-table.php b/wp-admin/includes/class-wp-ms-sites-list-table.php
index 4a43775..8993795 100644
--- a/wp-admin/includes/class-wp-ms-sites-list-table.php
+++ b/wp-admin/includes/class-wp-ms-sites-list-table.php
@@ -11,6 +11,7 @@
  * Core class used to implement displaying sites in a list table for the network admin.
  *
  * @since 3.1.0
+ * @since 4.8.x Added Site Status views, like on wp-admin/edit.php
  * @access private
  *
  * @see WP_List_Table
@@ -21,6 +22,7 @@ class WP_MS_Sites_List_Table extends WP_List_Table {
 	 * Site status list.
 	 *
 	 * @since 4.3.0
+	 * @since 4.8.x Now used to display Site Status views, like on wp-admin/edit.php
 	 * @access public
 	 * @var array
 	 */
@@ -38,6 +40,7 @@ class WP_MS_Sites_List_Table extends WP_List_Table {
 	 */
 	public function __construct( $args = array() ) {
 		$this->status_list = array(
+			'public' => array( 'site-public', __( 'Public' ) ),
 			'archived' => array( 'site-archived', __( 'Archived' ) ),
 			'spam'     => array( 'site-spammed', _x( 'Spam', 'site' ) ),
 			'deleted'  => array( 'site-deleted', __( 'Deleted' ) ),
@@ -166,6 +169,10 @@ class WP_MS_Sites_List_Table extends WP_List_Table {
 		 */
 		$args = apply_filters( 'ms_sites_list_table_query_args', $args );
 
+		if ( isset( $_REQUEST['site_status'] ) && ! empty( $_REQUEST['site_status'] ) ) {
+			$args[$_REQUEST['site_status']] = 1;
+		}
+
 		$_sites = get_sites( $args );
 		if ( is_array( $_sites ) ) {
 			update_site_cache( $_sites );
@@ -193,6 +200,116 @@ class WP_MS_Sites_List_Table extends WP_List_Table {
 	}
 
 	/**
+	 * Determine if the current view is the "All" view.
+	 *
+	 * @since 4.8.x
+	 *
+	 * @return bool Whether the current view is the "All" view.
+	 */
+	protected function is_base_request() {
+		$vars = $_GET;
+		unset( $vars['paged'] );
+
+		if ( empty( $vars ) ) {
+			return true;
+		} elseif ( ! empty( $vars['site_status'] ) ) {
+			return false;
+		}
+
+		return true;
+	}
+	
+	/**
+	 * Helper to create links to sites.php with params.
+	 *
+	 * @since 4.8.x
+	 * @access protected
+	 *
+	 * @param array  $args  URL parameters for the link.
+	 * @param string $label Link text.
+	 * @param string $class Optional. Class attribute. Default empty string.
+	 * @return string The formatted link string.
+	 */
+	protected function get_edit_link( $args, $label, $class = '' ) {
+		$url = add_query_arg( $args, 'sites.php' );
+
+		$class_html = '';
+		if ( ! empty( $class ) ) {
+			 $class_html = sprintf(
+				' class="%s"',
+				esc_attr( $class )
+			);
+		}
+
+		return sprintf(
+			'<a href="%s"%s>%s</a>',
+			esc_url( $url ),
+			$class_html,
+			$label
+		);
+	}
+
+	/**
+	 * Get an associative array ( id => link ) with the list of views available on this table.
+	 *
+	 * @since 4.8.x
+	 * @return array
+	 */
+	protected function get_views() {
+		$num_sites = wp_count_sites();
+		$total_sites = get_sites( array( 'count' => true, 'number' => 0 ) ) ;
+
+		$class = '';
+		if ( $this->is_base_request() ) {
+			$class = 'current';
+		}
+
+		$all_inner_html = sprintf(
+			_nx(
+				'All <span class="count">(%s)</span>',
+				'All <span class="count">(%s)</span>',
+				$total_sites,
+				'sites'
+			),
+			number_format_i18n( $total_sites )
+		);
+
+		$status_links = array() ;
+
+		$status_links['all'] = $this->get_edit_link( array (), $all_inner_html, $class );
+
+		foreach ( $this->status_list as $status => $status_name ) {
+			if ( ! $num_sites->{$status} ) {
+				continue;
+			}
+
+			$class = '';
+			if ( isset( $_REQUEST['site_status'] ) && $status === $_REQUEST['site_status'] ) {
+				$class = 'current';
+			}
+
+			$status_args = array(
+				'site_status' => $status,
+			);
+
+			$status_name = $status_name[1];
+			$status_inner_html = sprintf(
+				_nx(
+					$status_name . ' <span class="count">(%s)</span>',
+					$status_name . ' <span class="count">(%s)</span>',
+					$num_sites->{$status},
+					'sites'
+				),
+				number_format_i18n( $num_sites->{$status} )
+			);
+
+			$status_links[$status] = $this->get_edit_link( $status_args, $status_inner_html, $class );
+			}
+		
+		return $status_links;
+	}
+
+	/**
 	 *
 	 * @return array
 	 */
@@ -307,6 +424,9 @@ class WP_MS_Sites_List_Table extends WP_List_Table {
 		reset( $this->status_list );
 
 		foreach ( $this->status_list as $status => $col ) {
+			if ( isset( $_REQUEST['site_status'] ) && $status === $_REQUEST['site_status'] ) {
+				continue;
+			}
 			if ( $blog[ $status ] == 1 ) {
 				$blog_states[] = $col[1];
 			}
@@ -319,7 +439,7 @@ class WP_MS_Sites_List_Table extends WP_List_Table {
 			foreach ( $blog_states as $state ) {
 				++$i;
 				$sep = ( $i == $state_count ) ? '' : ', ';
-				$blog_state .= "<span class='post-state'>$state$sep</span>";
+				$blog_state .= "<span class='site-state'>$state$sep</span>";
 			}
 		}
 
diff --git a/wp-admin/network/sites.php b/wp-admin/network/sites.php
index a0ec407..730c3ca 100644
--- a/wp-admin/network/sites.php
+++ b/wp-admin/network/sites.php
@@ -5,6 +5,7 @@
  * @package WordPress
  * @subpackage Multisite
  * @since 3.0.0
+ * @since 4.8.x Added Site Status views, like on wp-admin/edit.php
  */
 
 /** Load WordPress Administration Bootstrap */
@@ -309,6 +310,8 @@ if ( isset( $_REQUEST['s'] ) && strlen( $_REQUEST['s'] ) ) {
 <input type="hidden" name="action" value="blogs" />
 </form>
 
+<?php $wp_list_table->views(); ?>
+
 <form id="form-site-list" action="sites.php?action=allblogs" method="post">
 	<?php $wp_list_table->display(); ?>
 </form>
diff --git a/wp-includes/ms-functions.php b/wp-includes/ms-functions.php
index d209435..3356030 100644
--- a/wp-includes/ms-functions.php
+++ b/wp-includes/ms-functions.php
@@ -2527,3 +2527,53 @@ function get_subdirectory_reserved_names() {
 	 */
 	return apply_filters( 'subdirectory_reserved_names', $names );
 }
+
+/**
+ * Count number of sites of a site status.
+ *
+ * This function provides an efficient method of finding the amount of sites
+ *
+ * @since 4.8.x
+ *
+ * @global wpdb $wpdb WordPress database abstraction object.
+ *
+ * @return object Number of sites for each status.
+ */
+function wp_count_sites( $network_id = null ) {
+	global $wpdb;
+
+	if ( is_null( $network_id ) ) {
+		// Get current network ID
+		$network_id = get_current_network_id();
+	}
+
+	// Bail if counts already cached
+	$counts = wp_cache_get( "sites-{$network_id}", 'networks' );
+	if ( false !== $counts ) {
+		return apply_filters( 'wp_count_sites', $counts, $network_id );
+	}
+
+	// Query for site statuses
+	$query = $wpdb->prepare(
+			"SELECT
+				SUM(public) AS `public`, 
+				SUM(archived) AS `archived`, 
+				SUM(mature) AS `mature`, 
+				SUM(spam) AS `spam`, 
+				SUM(deleted) as `deleted` 
+			FROM shc_blogs WHERE site_id = %d",
+		$network_id );
+	$counts  = $wpdb->get_row( $query );
+
+	wp_cache_set( "sites-{$network_id}", $counts, 'networks' );
+
+	/**
+	 * Filter site counts by status for the current network.
+	 *
+	 * @since 4.8.x
+	 *
+	 * @param object $counts An object containing the current network's site
+	 *		       counts by status.
+	 */
+	return apply_filters( 'wp_count_sites', $counts, $network_id );
+}
-- 
2.7.0.windows.1

