Make WordPress Core

Ticket #32504: 32504.2.diff

File 32504.2.diff, 40.9 KB (added by flixos90, 8 years ago)

fixed double quotes, added unit tests

  • src/wp-includes/class-wp-network-query.php

     
     1<?php
     2/**
     3 * Network API: WP_Network_Query class
     4 *
     5 * @package WordPress
     6 * @subpackage Multisite
     7 * @since 4.6.0
     8 */
     9
     10/**
     11 * Core class used for querying networks.
     12 *
     13 * @since 3.1.0
     14 *
     15 * @see WP_Network_Query::__construct() for accepted arguments.
     16 */
     17class WP_Network_Query {
     18
     19        /**
     20         * SQL for database query.
     21         *
     22         * @since 4.6.0
     23         * @access public
     24         * @var string
     25         */
     26        public $request;
     27
     28        /**
     29         * Metadata query container
     30         *
     31         * @since 4.6.0
     32         * @access public
     33         * @var object WP_Meta_Query
     34         */
     35        public $meta_query = false;
     36
     37        /**
     38         * Metadata query clauses.
     39         *
     40         * @since 4.6.0
     41         * @access protected
     42         * @var array
     43         */
     44        protected $meta_query_clauses;
     45
     46        /**
     47         * SQL query clauses.
     48         *
     49         * @since 4.6.0
     50         * @access protected
     51         * @var array
     52         */
     53        protected $sql_clauses = array(
     54                'select'  => '',
     55                'from'    => '',
     56                'where'   => array(),
     57                'groupby' => '',
     58                'orderby' => '',
     59                'limits'  => '',
     60        );
     61
     62        /**
     63         * Query vars set by the user.
     64         *
     65         * @since 4.6.0
     66         * @access public
     67         * @var array
     68         */
     69        public $query_vars;
     70
     71        /**
     72         * Default values for query vars.
     73         *
     74         * @since 4.6.0
     75         * @access public
     76         * @var array
     77         */
     78        public $query_var_defaults;
     79
     80        /**
     81         * List of networks located by the query.
     82         *
     83         * @since 4.6.0
     84         * @access public
     85         * @var array
     86         */
     87        public $networks;
     88
     89        /**
     90         * The amount of found networks for the current query.
     91         *
     92         * @since 4.6.0
     93         * @access public
     94         * @var int
     95         */
     96        public $found_networks = 0;
     97
     98        /**
     99         * The number of pages.
     100         *
     101         * @since 4.6.0
     102         * @access public
     103         * @var int
     104         */
     105        public $max_num_pages = 0;
     106
     107        /**
     108         * Constructor.
     109         *
     110         * Sets up the network query, based on the query vars passed.
     111         *
     112         * @since 4.6.0
     113         * @access public
     114         *
     115         * @param string|array $query {
     116         *     Optional. Array or query string of network query parameters. Default empty.
     117         *
     118         *     @type array        $network__in               Array of network IDs to include. Default empty.
     119         *     @type array        $network__not_in           Array of network IDs to exclude. Default empty.
     120         *     @type bool         $count                     Whether to return a network count (true) or array of network objects.
     121         *                                                   Default false.
     122         *     @type string       $fields                    Network fields to return. Accepts 'ids' for network IDs only or empty
     123         *                                                   for all fields. Default empty.
     124         *     @type int          $number                    Maximum number of networks to retrieve. Default null (no limit).
     125         *     @type int          $offset                    Number of networks to offset the query. Used to build LIMIT clause.
     126         *                                                   Default 0.
     127         *     @type bool         $no_found_rows             Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true.
     128         *     @type string|array $orderby                   Network status or array of statuses. To use 'meta_value' or
     129         *                                                   'meta_value_num', `$meta_key` must also be defined. To sort by a
     130         *                                                   specific `$meta_query` clause, use that clause's array key. Accepts
     131         *                                                   'id', 'domain', 'path', 'domain_length', 'path_length', 'network__in',
     132         *                                                   'meta_value', 'meta_value_num', the value of $meta_key, and the array keys
     133         *                                                   of `$meta_query`. Also accepts false, an empty array, or 'none' to disable
     134         *                                                   `ORDER BY` clause. Default 'id'.
     135         *     @type string       $order                     How to order retrieved networks. Accepts 'ASC', 'DESC'. Default 'ASC'.
     136         *     @type string       $domain                    Limit results to those affiliated with a given network ID.
     137         *                                                   Default current network ID.
     138         *     @type array        $domain__in                Array of domains to include affiliated networks for. Default empty.
     139         *     @type array        $domain__not_in            Array of domains to exclude affiliated networks for. Default empty.
     140         *     @type string       $path                      Limit results to those affiliated with a given network ID.
     141         *                                                   Default current network ID.
     142         *     @type array        $path__in                  Array of paths to include affiliated networks for. Default empty.
     143         *     @type array        $path__not_in              Array of paths to exclude affiliated networks for. Default empty.
     144         *     @type string       $search                    Search term(s) to retrieve matching networks for. Default empty.
     145         *     @type string       $meta_key                  Include networks with a matching network meta key.
     146         *                                                   Default empty.
     147         *     @type string       $meta_value                Include networks with a matching network meta value.
     148         *                                                   Requires `$meta_key` to be set. Default empty.
     149         *     @type array        $meta_query                Meta query clauses to limit retrieved networks by.
     150         *                                                   See WP_Meta_Query. Default empty.
     151         *     @type bool         $update_network_cache      Whether to prime the cache for found networks. Default true.
     152         *     @type bool         $update_network_meta_cache Whether to prime metadata cache for found networks. Default true.
     153         * }
     154         */
     155        public function __construct( $query = '' ) {
     156                $this->query_var_defaults = array(
     157                        'network__in'               => '',
     158                        'network__not_in'           => '',
     159                        'count'                     => false,
     160                        'fields'                    => '',
     161                        'number'                    => '',
     162                        'offset'                    => '',
     163                        'no_found_rows'             => true,
     164                        'orderby'                   => '',
     165                        'order'                     => 'ASC',
     166                        'domain'                    => '',
     167                        'domain__in'                => '',
     168                        'domain__not_in'            => '',
     169                        'path'                      => '',
     170                        'path__in'                  => '',
     171                        'path__not_in'              => '',
     172                        'search'                    => '',
     173                        'meta_key'                  => '',
     174                        'meta_value'                => '',
     175                        'meta_query'                => '',
     176                        'update_network_cache'      => true,
     177                        'update_network_meta_cache' => true,
     178                );
     179
     180                if ( ! empty( $query ) ) {
     181                        $this->query( $query );
     182                }
     183        }
     184
     185        /**
     186         * Parse arguments passed to the network query with default query parameters.
     187         *
     188         * @since 4.6.0
     189         *
     190         * @access public
     191         *
     192         * @param string|array $query WP_Network_Query arguments. See WP_Network_Query::__construct()
     193         */
     194        public function parse_query( $query = '' ) {
     195                if ( empty( $query ) ) {
     196                        $query = $this->query_vars;
     197                }
     198
     199                $this->query_vars = wp_parse_args( $query, $this->query_var_defaults );
     200
     201                /**
     202                 * Fires after the network query vars have been parsed.
     203                 *
     204                 * @since 4.6.0
     205                 *
     206                 * @param WP_Network_Query &$this The WP_Network_Query instance (passed by reference).
     207                 */
     208                do_action_ref_array( 'parse_network_query', array( &$this ) );
     209        }
     210
     211        /**
     212         * Sets up the WordPress query for retrieving networks.
     213         *
     214         * @since 4.6.0
     215         * @access public
     216         *
     217         * @param string|array $query Array or URL query string of parameters.
     218         * @return array|int List of networks, or number of networks when 'count' is passed as a query var.
     219         */
     220        public function query( $query ) {
     221                $this->query_vars = wp_parse_args( $query );
     222                return $this->get_networks();
     223        }
     224
     225        /**
     226         * Get a list of networks matching the query vars.
     227         *
     228         * @since 4.6.0
     229         * @access public
     230         *
     231         * @global wpdb $wpdb WordPress database abstraction object.
     232         *
     233         * @return int|array The list of networks.
     234         */
     235        public function get_networks() {
     236                global $wpdb;
     237
     238                $this->parse_query();
     239
     240                // Parse meta query
     241                $this->meta_query = new WP_Meta_Query();
     242                $this->meta_query->parse_query_vars( $this->query_vars );
     243
     244                /**
     245                 * Fires before networks are retrieved.
     246                 *
     247                 * @since 4.6.0
     248                 *
     249                 * @param WP_Network_Query &$this Current instance of WP_Network_Query, passed by reference.
     250                 */
     251                do_action_ref_array( 'pre_get_networks', array( &$this ) );
     252
     253                // Reparse query vars, in case they were modified in a 'pre_get_networks' callback.
     254                $this->meta_query->parse_query_vars( $this->query_vars );
     255                if ( ! empty( $this->meta_query->queries ) ) {
     256                        $this->meta_query_clauses = $this->meta_query->get_sql( 'site', $wpdb->site, 'id', $this );
     257                }
     258
     259                // $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
     260                $key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) );
     261                $last_changed = wp_cache_get( 'last_changed', 'networks' );
     262                if ( ! $last_changed ) {
     263                        $last_changed = microtime();
     264                        wp_cache_set( 'last_changed', $last_changed, 'networks' );
     265                }
     266                $cache_key = "get_network_ids:$key:$last_changed";
     267
     268                $network_ids = wp_cache_get( $cache_key, 'networks' );
     269                if ( false === $network_ids ) {
     270                        $network_ids = $this->get_network_ids();
     271                        wp_cache_add( $cache_key, $network_ids, 'networks' );
     272                }
     273
     274                // If querying for a count only, there's nothing more to do.
     275                if ( $this->query_vars['count'] ) {
     276                        // $network_ids is actually a count in this case.
     277                        return intval( $network_ids );
     278                }
     279
     280                $network_ids = array_map( 'intval', $network_ids );
     281
     282                $this->network_count = count( $this->networks );
     283
     284                if ( $network_ids && $this->query_vars['number'] && ! $this->query_vars['no_found_rows'] ) {
     285                        /**
     286                         * Filter the query used to retrieve found network count.
     287                         *
     288                         * @since 4.6.0
     289                         *
     290                         * @param string           $found_networks_query SQL query. Default 'SELECT FOUND_ROWS()'.
     291                         * @param WP_Network_Query $network_query        The `WP_Network_Query` instance.
     292                         */
     293                        $found_networks_query = apply_filters( 'found_networks_query', 'SELECT FOUND_ROWS()', $this );
     294                        $this->found_networks = (int) $wpdb->get_var( $found_networks_query );
     295
     296                        $this->max_num_pages = ceil( $this->found_networks / $this->query_vars['number'] );
     297                }
     298
     299                if ( 'ids' == $this->query_vars['fields'] ) {
     300                        $this->networks = $network_ids;
     301                        return $this->networks;
     302                }
     303
     304                if ( $this->query_vars['update_network_cache'] ) {
     305                        _prime_network_caches( $network_ids, $this->query_vars['update_network_meta_cache'] );
     306                }
     307
     308                // Fetch full network objects from the primed cache.
     309                $_networks = array();
     310                foreach ( $network_ids as $network_id ) {
     311                        if ( $_network = get_network( $network_id ) ) {
     312                                $_networks[] = $_network;
     313                        }
     314                }
     315
     316                /**
     317                 * Filter the network query results.
     318                 *
     319                 * @since 4.6.0
     320                 *
     321                 * @param array            $results  An array of networks.
     322                 * @param WP_Network_Query &$this    Current instance of WP_Network_Query, passed by reference.
     323                 */
     324                $_networks = apply_filters_ref_array( 'the_networks', array( $_networks, &$this ) );
     325
     326                // Convert to WP_Network instances
     327                $this->networks = array_map( 'get_network', $_networks );
     328
     329                return $this->networks;
     330        }
     331
     332        /**
     333         * Used internally to get a list of network IDs matching the query vars.
     334         *
     335         * @since 4.6.0
     336         * @access protected
     337         *
     338         * @global wpdb $wpdb WordPress database abstraction object.
     339         */
     340        protected function get_network_ids() {
     341                global $wpdb;
     342
     343                $order = $this->parse_order( $this->query_vars['order'] );
     344
     345                // Disable ORDER BY with 'none', an empty array, or boolean false.
     346                if ( in_array( $this->query_vars['orderby'], array( 'none', array(), false ), true ) ) {
     347                        $orderby = '';
     348                } elseif ( ! empty( $this->query_vars['orderby'] ) ) {
     349                        $ordersby = is_array( $this->query_vars['orderby'] ) ?
     350                                $this->query_vars['orderby'] :
     351                                preg_split( '/[,\s]/', $this->query_vars['orderby'] );
     352
     353                        $orderby_array         = array();
     354                        foreach ( $ordersby as $_key => $_value ) {
     355                                if ( ! $_value ) {
     356                                        continue;
     357                                }
     358
     359                                if ( is_int( $_key ) ) {
     360                                        $_orderby = $_value;
     361                                        $_order   = $order;
     362                                } else {
     363                                        $_orderby = $_key;
     364                                        $_order   = $_value;
     365                                }
     366
     367                                $parsed = $this->parse_orderby( $_orderby );
     368
     369                                if ( ! $parsed ) {
     370                                        continue;
     371                                }
     372
     373                                if ( 'network__in' === $_orderby ) {
     374                                        $orderby_array[] = $parsed;
     375                                        continue;
     376                                }
     377
     378                                $orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
     379                        }
     380
     381                        $orderby = implode( ', ', $orderby_array );
     382                } else {
     383                        $orderby = "$wpdb->site.id $order";
     384                }
     385
     386                $number = absint( $this->query_vars['number'] );
     387                $offset = absint( $this->query_vars['offset'] );
     388
     389                if ( ! empty( $number ) ) {
     390                        if ( $offset ) {
     391                                $limits = 'LIMIT ' . $offset . ',' . $number;
     392                        } else {
     393                                $limits = 'LIMIT ' . $number;
     394                        }
     395                }
     396
     397                if ( $this->query_vars['count'] ) {
     398                        $fields = 'COUNT(*)';
     399                } else {
     400                        $fields = "$wpdb->site.id";
     401                }
     402
     403                // Parse network IDs for an IN clause.
     404                if ( ! empty( $this->query_vars['network__in'] ) ) {
     405                        $this->sql_clauses['where']['network__in'] = "$wpdb->site.id IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['network__in'] ) ) . ' )';
     406                }
     407
     408                // Parse network IDs for a NOT IN clause.
     409                if ( ! empty( $this->query_vars['network__not_in'] ) ) {
     410                        $this->sql_clauses['where']['network__not_in'] = "$wpdb->site.id NOT IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['network__not_in'] ) ) . ' )';
     411                }
     412
     413                if ( ! empty( $this->query_vars['domain'] ) ) {
     414                        $this->sql_clauses['where']['domain'] = $wpdb->prepare( "$wpdb->site.domain = %s", $this->query_vars['domain'] );
     415                }
     416
     417                // Parse network domain for an IN clause.
     418                if ( is_array( $this->query_vars['domain__in'] ) ) {
     419                        $this->sql_clauses['where']['domain__in'] = "$wpdb->site.domain IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['domain__in'] ) ) . "' )";
     420                }
     421
     422                // Parse network domain for a NOT IN clause.
     423                if ( is_array( $this->query_vars['domain__not_in'] ) ) {
     424                        $this->sql_clauses['where']['domain__not_in'] = "$wpdb->site.domain NOT IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['domain__not_in'] ) ) . "' )";
     425                }
     426
     427                if ( ! empty( $this->query_vars['path'] ) ) {
     428                        $this->sql_clauses['where']['path'] = $wpdb->prepare( "$wpdb->site.path = %s", $this->query_vars['path'] );
     429                }
     430
     431                // Parse network path for an IN clause.
     432                if ( is_array( $this->query_vars['path__in'] ) ) {
     433                        $this->sql_clauses['where']['path__in'] = "$wpdb->site.path IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['path__in'] ) ) . "' )";
     434                }
     435
     436                // Parse network path for a NOT IN clause.
     437                if ( is_array( $this->query_vars['path__not_in'] ) ) {
     438                        $this->sql_clauses['where']['path__not_in'] = "$wpdb->site.path NOT IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['path__not_in'] ) ) . "' )";
     439                }
     440
     441                // Falsey search strings are ignored.
     442                if ( strlen( $this->query_vars['search'] ) ) {
     443                        $this->sql_clauses['where']['search'] = $this->get_search_sql(
     444                                $this->query_vars['search'],
     445                                array( "$wpdb->site.domain", "$wpdb->site.path" )
     446                        );
     447                }
     448
     449                $join = '';
     450
     451                if ( ! empty( $this->meta_query_clauses ) ) {
     452                        $join .= $this->meta_query_clauses['join'];
     453
     454                        // Strip leading 'AND'.
     455                        $this->sql_clauses['where']['meta_query'] = preg_replace( '/^\s*AND\s*/', '', $this->meta_query_clauses['where'] );
     456
     457                        if ( ! $this->query_vars['count'] ) {
     458                                $groupby = "{$wpdb->site}.id";
     459                        }
     460                }
     461
     462                $where = implode( ' AND ', $this->sql_clauses['where'] );
     463
     464                $pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' );
     465
     466                /**
     467                 * Filters the network query clauses.
     468                 *
     469                 * @since 4.6.0
     470                 *
     471                 * @param array            $pieces A compacted array of network query clauses.
     472                 * @param WP_Network_Query &$this  Current instance of WP_Network_Query, passed by reference.
     473                 */
     474                $clauses = apply_filters_ref_array( 'networks_clauses', array( compact( $pieces ), &$this ) );
     475
     476                $fields  = isset( $clauses['fields'] ) ? $clauses['fields'] : '';
     477                $join    = isset( $clauses['join'] ) ? $clauses['join'] : '';
     478                $where   = isset( $clauses['where'] ) ? $clauses['where'] : '';
     479                $orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : '';
     480                $limits  = isset( $clauses['limits'] ) ? $clauses['limits'] : '';
     481                $groupby = isset( $clauses['groupby'] ) ? $clauses['groupby'] : '';
     482
     483                if ( $where ) {
     484                        $where = 'WHERE ' . $where;
     485                }
     486
     487                if ( $groupby ) {
     488                        $groupby = 'GROUP BY ' . $groupby;
     489                }
     490
     491                if ( $orderby ) {
     492                        $orderby = "ORDER BY $orderby";
     493                }
     494
     495                $found_rows = '';
     496                if ( ! $this->query_vars['no_found_rows'] ) {
     497                        $found_rows = 'SQL_CALC_FOUND_ROWS';
     498                }
     499
     500                $this->sql_clauses['select']  = "SELECT $found_rows $fields";
     501                $this->sql_clauses['from']    = "FROM $wpdb->site $join";
     502                $this->sql_clauses['groupby'] = $groupby;
     503                $this->sql_clauses['orderby'] = $orderby;
     504                $this->sql_clauses['limits']  = $limits;
     505
     506                $this->request = "{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['groupby']} {$this->sql_clauses['orderby']} {$this->sql_clauses['limits']}";
     507
     508                if ( $this->query_vars['count'] ) {
     509                        return intval( $wpdb->get_var( $this->request ) );
     510                }
     511
     512                $network_ids = $wpdb->get_col( $this->request );
     513
     514                return array_map( 'intval', $network_ids );
     515        }
     516
     517        /**
     518         * Used internally to generate an SQL string for searching across multiple columns
     519         *
     520         * @since 4.6.0
     521         * @access protected
     522         *
     523         * @global wpdb  $wpdb WordPress database abstraction object.
     524         *
     525         * @param string $string  Search string.
     526         * @param array  $columns Columns to search.
     527         *
     528         * @return string Search SQL.
     529         */
     530        protected function get_search_sql( $string, $columns ) {
     531                global $wpdb;
     532
     533                $like = '%' . $wpdb->esc_like( $string ) . '%';
     534
     535                $searches = array();
     536                foreach ( $columns as $column ) {
     537                        $searches[] = $wpdb->prepare( "$column LIKE %s", $like );
     538                }
     539
     540                return '(' . implode( ' OR ', $searches ) . ')';
     541        }
     542
     543        /**
     544         * Parses and sanitizes 'orderby' keys passed to the network query.
     545         *
     546         * @since 4.6.0
     547         * @access protected
     548         *
     549         * @global wpdb $wpdb WordPress database abstraction object.
     550         *
     551         * @param string $orderby Alias for the field to order by.
     552         * @return string|false Value to used in the ORDER clause. False otherwise.
     553         */
     554        protected function parse_orderby( $orderby ) {
     555                global $wpdb;
     556
     557                $allowed_keys = array(
     558                        'id',
     559                        'domain',
     560                        'path',
     561                );
     562
     563                if ( ! empty( $this->query_vars['meta_key'] ) ) {
     564                        $allowed_keys[] = $this->query_vars['meta_key'];
     565                        $allowed_keys[] = 'meta_value';
     566                        $allowed_keys[] = 'meta_value_num';
     567                }
     568
     569                $meta_query_clauses = $this->meta_query->get_clauses();
     570                if ( $meta_query_clauses ) {
     571                        $allowed_keys = array_merge( $allowed_keys, array_keys( $meta_query_clauses ) );
     572                }
     573
     574                $parsed = false;
     575                if ( $orderby == $this->query_vars['meta_key'] || $orderby == 'meta_value' ) {
     576                        $parsed = "$wpdb->sitemeta.meta_value";
     577                } elseif ( $orderby == 'meta_value_num' ) {
     578                        $parsed = "$wpdb->sitemeta.meta_value+0";
     579                } elseif ( $orderby == 'network__in' ) {
     580                        $network__in = implode( ',', array_map( 'absint', $this->query_vars['network__in'] ) );
     581                        $parsed = "FIELD( {$wpdb->site}.id, $network__in )";
     582                } elseif ( $orderby == 'domain_length' || $orderby == 'path_length' ) {
     583                        $field = substr( $orderby, 0, -7 );
     584                        $parsed = "CHAR_LENGTH($wpdb->site.$field)";
     585                } elseif ( in_array( $orderby, $allowed_keys ) ) {
     586                        if ( isset( $meta_query_clauses[ $orderby ] ) ) {
     587                                $meta_clause = $meta_query_clauses[ $orderby ];
     588                                $parsed = sprintf( "CAST(%s.meta_value AS %s)", esc_sql( $meta_clause['alias'] ), esc_sql( $meta_clause['cast'] ) );
     589                        } else {
     590                                $parsed = "$wpdb->site.$orderby";
     591                        }
     592                }
     593
     594                return $parsed;
     595        }
     596
     597        /**
     598         * Parses an 'order' query variable and cast it to 'ASC' or 'DESC' as necessary.
     599         *
     600         * @since 4.6.0
     601         * @access protected
     602         *
     603         * @param string $order The 'order' query variable.
     604         * @return string The sanitized 'order' query variable.
     605         */
     606        protected function parse_order( $order ) {
     607                if ( ! is_string( $order ) || empty( $order ) ) {
     608                        return 'ASC';
     609                }
     610
     611                if ( 'ASC' === strtoupper( $order ) ) {
     612                        return 'ASC';
     613                } else {
     614                        return 'DESC';
     615                }
     616        }
     617}
  • src/wp-includes/class-wp-network.php

    Property changes on: src/wp-includes/class-wp-network-query.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
    138138        }
    139139
    140140        /**
     141         * Convert object to array.
     142         *
     143         * @since 4.6.0
     144         * @access public
     145         *
     146         * @return array Object as array.
     147         */
     148        public function to_array() {
     149                return get_object_vars( $this );
     150        }
     151
     152        /**
    141153         * Set the site name assigned to the network if one has not been populated.
    142154         *
    143155         * @since 4.4.0
  • src/wp-includes/ms-blogs.php

     
    973973}
    974974
    975975/**
     976 * Retrieve a list of networks.
     977 *
     978 * @since 4.6.0
     979 *
     980 * @param string|array $args Optional. Array or string of arguments. See {@see WP_Network_Query::parse_query()}
     981 *                           for information on accepted arguments. Default empty.
     982 *
     983 * @return int|array List of networks or number of found networks if `$count` argument is true.
     984 */
     985function get_networks( $args = '' ) {
     986        $query = new WP_Network_Query();
     987        return $query->query( $args );
     988}
     989
     990/**
     991 * Retrieves network data given a network ID or network object.
     992 *
     993 * If an object is passed then the network data will be cached and then returned
     994 * after being passed through a filter. If the network is empty, then the
     995 * current network will be used, if it is set.
     996 *
     997 * @since 4.6.0
     998 *
     999 * @global WP_Network $current_site
     1000 *
     1001 * @param WP_Network|string|int $network Network to retrieve.
     1002 * @param string                $output  Optional. OBJECT or ARRAY_A or ARRAY_N constants.
     1003 *
     1004 * @return WP_Network|array|null Depends on $output value.
     1005 */
     1006function get_network( &$network = null, $output = OBJECT ) {
     1007        if ( empty( $network ) && isset( $GLOBALS['current_site'] ) ) {
     1008                $network = $GLOBALS['current_site'];
     1009        }
     1010
     1011        if ( $network instanceof WP_Network ) {
     1012                $_network = $network;
     1013        } elseif ( is_object( $network ) ) {
     1014                $_network = new WP_Network( $network );
     1015        } else {
     1016                $_network = WP_Network::get_instance( $network );
     1017        }
     1018
     1019        if ( ! $_network ) {
     1020                return null;
     1021        }
     1022
     1023        /**
     1024         * Fires after a network is retrieved.
     1025         *
     1026         * @since 4.6.0
     1027         *
     1028         * @param mixed $_network Network data.
     1029         */
     1030        $_network = apply_filters( 'get_network', $_network );
     1031
     1032        if ( $output == OBJECT ) {
     1033                return $_network;
     1034        } elseif ( $output == ARRAY_A ) {
     1035                return $_network->to_array();
     1036        } elseif ( $output == ARRAY_N ) {
     1037                return array_values( $_network->to_array() );
     1038        }
     1039        return $_network;
     1040}
     1041
     1042/**
     1043 * Removes a network from the object cache.
     1044 *
     1045 * @since 4.6.0
     1046 *
     1047 * @param int|array $ids Network ID or an array of network IDs to remove from cache.
     1048 */
     1049function clean_network_cache( $ids ) {
     1050        foreach ( (array) $ids as $id ) {
     1051                wp_cache_delete( $id, 'networks' );
     1052
     1053                /**
     1054                 * Fires immediately after a network has been removed from the object cache.
     1055                 *
     1056                 * @since 4.6.0
     1057                 *
     1058                 * @param int $id Network ID.
     1059                 */
     1060                do_action( 'clean_network_cache', $id );
     1061        }
     1062
     1063        wp_cache_set( 'last_changed', microtime(), 'networks' );
     1064}
     1065
     1066/**
     1067 * Updates the network cache of given networks.
     1068 *
     1069 * Will add the networks in $networks to the cache. If network ID already exists
     1070 * in the network cache then it will not be updated. The network is added to the
     1071 * cache using the network group with the key using the ID of the networks.
     1072 *
     1073 * @since 4.6.0
     1074 *
     1075 * @param array $networks          Array of network row objects
     1076 * @param bool  $update_meta_cache Whether to update network meta cache. Default true.
     1077 */
     1078function update_network_cache( $networks, $update_meta_cache = true ) {
     1079        foreach ( (array) $networks as $network )
     1080                wp_cache_add( $network->id, $network, 'networks' );
     1081
     1082        if ( $update_meta_cache ) {
     1083                // Avoid `wp_list_pluck()` in case `$networks` is passed by reference.
     1084                $network_ids = array();
     1085                foreach ( $networks as $network ) {
     1086                        $network_ids[] = $network->id;
     1087                }
     1088                update_meta_cache( 'site', $network_ids );
     1089        }
     1090}
     1091
     1092/**
     1093 * Adds any networks from the given IDs to the cache that do not already exist in cache.
     1094 *
     1095 * @since 4.6.0
     1096 * @access private
     1097 *
     1098 * @see update_network_cache()
     1099 * @global wpdb $wpdb WordPress database abstraction object.
     1100 *
     1101 * @param array $network_ids       Array of network IDs.
     1102 * @param bool  $update_meta_cache Optional. Whether to update the meta cache. Default true.
     1103 */
     1104function _prime_network_caches( $network_ids, $update_meta_cache = true ) {
     1105        global $wpdb;
     1106
     1107        $non_cached_ids = _get_non_cached_ids( $network_ids, 'networks' );
     1108        if ( !empty( $non_cached_ids ) ) {
     1109                $fresh_networks = $wpdb->get_results( sprintf( "SELECT $wpdb->site.* FROM $wpdb->site WHERE id IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) );
     1110
     1111                update_network_cache( $fresh_networks, $update_meta_cache );
     1112        }
     1113}
     1114
     1115/**
    9761116 * Handler for updating the blog date when a post is published or an already published post is changed.
    9771117 *
    9781118 * @since 3.3.0
  • src/wp-includes/ms-settings.php

     
    2828/** WP_Site class */
    2929require_once( ABSPATH . WPINC . '/class-wp-site.php' );
    3030
     31/** WP_Network_Query class */
     32require_once( ABSPATH . WPINC . '/class-wp-network-query.php' );
     33
    3134/** Multisite loader */
    3235require_once( ABSPATH . WPINC . '/ms-load.php' );
    3336
  • tests/phpunit/tests/multisite/networkQuery.php

     
     1<?php
     2
     3if ( is_multisite() ) :
     4
     5/**
     6 * Test network query functionality in multisite.
     7 *
     8 * @group ms-network
     9 * @group ms-network-query
     10 * @group multisite
     11 */
     12class Tests_Multisite_Network_Query extends WP_UnitTestCase {
     13        protected static $network_ids;
     14
     15        protected $suppress = false;
     16
     17        function setUp() {
     18                global $wpdb;
     19                parent::setUp();
     20                $this->suppress = $wpdb->suppress_errors();
     21        }
     22
     23        function tearDown() {
     24                global $wpdb;
     25                $wpdb->suppress_errors( $this->suppress );
     26                parent::tearDown();
     27        }
     28
     29        public static function wpSetUpBeforeClass( $factory ) {
     30                self::$network_ids = array(
     31                        'wordpress.org/'         => array( 'domain' => 'wordpress.org',      'path' => '/' ),
     32                        'make.wordpress.org/'    => array( 'domain' => 'make.wordpress.org', 'path' => '/' ),
     33                        'www.wordpress.net/'     => array( 'domain' => 'www.wordpress.net',  'path' => '/' ),
     34                        'www.w.org/foo/'         => array( 'domain' => 'www.w.org',          'path' => '/foo/' ),
     35                );
     36
     37                foreach ( self::$network_ids as &$id ) {
     38                        $id = $factory->network->create( $id );
     39                }
     40                unset( $id );
     41        }
     42
     43        public static function wpTearDownAfterClass() {
     44                global $wpdb;
     45
     46                foreach( self::$network_ids as $id ) {
     47                        $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->sitemeta} WHERE site_id = %d", $id ) );
     48                        $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->site} WHERE id= %d", $id ) );
     49                }
     50        }
     51
     52        public function test_wp_network_query_by_number() {
     53                $q = new WP_Network_Query();
     54                $found = $q->query( array(
     55                        'fields'   => 'ids',
     56                        'number'   => 3,
     57                ) );
     58
     59                $this->assertEquals( 3, count( $found ) );
     60        }
     61
     62        public function test_wp_network_query_by_network__in_with_single_id() {
     63                $expected = array( self::$network_ids['wordpress.org/'] );
     64
     65                $q = new WP_Network_Query();
     66                $found = $q->query( array(
     67                        'fields'      => 'ids',
     68                        'network__in' => $expected,
     69                ) );
     70
     71                $this->assertEqualSets( $expected, $found );
     72        }
     73
     74        public function test_wp_network_query_by_network__in_with_multiple_ids() {
     75                $expected = array( self::$network_ids['wordpress.org/'], self::$network_ids['www.wordpress.net/'] );
     76
     77                $q = new WP_Network_Query();
     78                $found = $q->query( array(
     79                        'fields'      => 'ids',
     80                        'network__in' => $expected,
     81                ) );
     82
     83                $this->assertEqualSets( $expected, $found );
     84        }
     85
     86        public function test_wp_network_query_by_network__in_and_count_with_multiple_ids() {
     87                $expected = array( self::$network_ids['wordpress.org/'], self::$network_ids['make.wordpress.org/'] );
     88
     89                $q = new WP_Network_Query();
     90                $found = $q->query( array(
     91                        'fields'      => 'ids',
     92                        'count'       => true,
     93                        'network__in' => $expected,
     94                ) );
     95
     96                $this->assertEquals( 2, $found );
     97        }
     98
     99        public function test_wp_network_query_by_network__not_in_with_single_id() {
     100                $excluded = array( self::$network_ids['wordpress.org/'] );
     101                $expected = array_diff( self::$network_ids, $excluded );
     102
     103                // Exclude main network since we don't have control over it here.
     104                $excluded[] = 1;
     105
     106                $q = new WP_Network_Query();
     107                $found = $q->query( array(
     108                        'fields'          => 'ids',
     109                        'network__not_in' => $excluded,
     110                ) );
     111
     112                $this->assertEqualSets( $expected, $found );
     113        }
     114
     115        public function test_wp_network_query_by_network__not_in_with_multiple_ids() {
     116                $excluded = array( self::$network_ids['wordpress.org/'], self::$network_ids['www.w.org/foo/'] );
     117                $expected = array_diff( self::$network_ids, $excluded );
     118
     119                // Exclude main network since we don't have control over it here.
     120                $excluded[] = 1;
     121
     122                $q = new WP_Network_Query();
     123                $found = $q->query( array(
     124                        'fields'          => 'ids',
     125                        'network__not_in' => $excluded,
     126                ) );
     127
     128                $this->assertEqualSets( $expected, $found );
     129        }
     130
     131        public function test_wp_network_query_by_domain() {
     132                $q = new WP_Network_Query();
     133                $found = $q->query( array(
     134                        'fields'       => 'ids',
     135                        'domain'       => 'www.w.org',
     136                ) );
     137
     138                $expected = array(
     139                        self::$network_ids['www.w.org/foo/'],
     140                );
     141
     142                $this->assertEqualSets( $expected, $found );
     143        }
     144
     145        public function test_wp_network_query_by_domain__in_with_single_domain() {
     146                $q = new WP_Network_Query();
     147                $found = $q->query( array(
     148                        'fields'     => 'ids',
     149                        'domain__in' => array( 'make.wordpress.org' ),
     150                ));
     151
     152                $expected = array(
     153                        self::$network_ids['make.wordpress.org/'],
     154                );
     155
     156                $this->assertEqualSets( $expected, $found );
     157        }
     158
     159        public function test_wp_network_query_by_domain__in_with_multiple_domains() {
     160                $q = new WP_Network_Query();
     161                $found = $q->query( array(
     162                        'fields'     => 'ids',
     163                        'domain__in' => array( 'wordpress.org', 'make.wordpress.org' ),
     164                ));
     165
     166                $expected = array(
     167                        self::$network_ids['wordpress.org/'],
     168                        self::$network_ids['make.wordpress.org/'],
     169                );
     170
     171                $this->assertEqualSets( $expected, $found );
     172        }
     173
     174        public function test_wp_network_query_by_domain__in_with_multiple_domains_and_number() {
     175                $q = new WP_Network_Query();
     176                $found = $q->query( array(
     177                        'fields'     => 'ids',
     178                        'number'     => 1,
     179                        'domain__in' => array( 'wordpress.org', 'make.wordpress.org' ),
     180                ));
     181
     182                $expected = array(
     183                        self::$network_ids['wordpress.org/'],
     184                );
     185
     186                $this->assertEqualSets( $expected, $found );
     187        }
     188
     189        public function test_wp_network_query_by_domain__in_with_multiple_domains_and_number_and_offset() {
     190                $q = new WP_Network_Query();
     191                $found = $q->query( array(
     192                        'fields'     => 'ids',
     193                        'number'     => 1,
     194                        'offset'     => 1,
     195                        'domain__in' => array( 'wordpress.org', 'make.wordpress.org' ),
     196                ));
     197
     198                $expected = array(
     199                        self::$network_ids['make.wordpress.org/'],
     200                );
     201
     202                $this->assertEqualSets( $expected, $found );
     203        }
     204
     205        public function test_wp_network_query_by_domain__not_in_with_single_domain() {
     206                $q = new WP_Network_Query();
     207                $found = $q->query( array(
     208                        'fields'         => 'ids',
     209                        'domain__not_in' => array( 'www.w.org' ),
     210                ));
     211
     212                $expected = array(
     213                        get_current_site()->id, // Account for the initial network added by the test suite.
     214                        self::$network_ids['wordpress.org/'],
     215                        self::$network_ids['make.wordpress.org/'],
     216                        self::$network_ids['www.wordpress.net/'],
     217                );
     218
     219                $this->assertEqualSets( $expected, $found );
     220        }
     221
     222        public function test_wp_network_query_by_domain__not_in_with_multiple_domains() {
     223                $q = new WP_Network_Query();
     224                $found = $q->query( array(
     225                        'fields'         => 'ids',
     226                        'domain__not_in' => array( 'wordpress.org', 'www.w.org' ),
     227                ));
     228
     229                $expected = array(
     230                        get_current_site()->id, // Account for the initial network added by the test suite.
     231                        self::$network_ids['make.wordpress.org/'],
     232                        self::$network_ids['www.wordpress.net/'],
     233                );
     234
     235                $this->assertEqualSets( $expected, $found );
     236        }
     237
     238        public function test_wp_network_query_by_domain__not_in_with_multiple_domains_and_number() {
     239                $q = new WP_Network_Query();
     240                $found = $q->query( array(
     241                        'fields'         => 'ids',
     242                        'number'         => 2,
     243                        'domain__not_in' => array( 'wordpress.org', 'www.w.org' ),
     244                ));
     245
     246                $expected = array(
     247                        get_current_site()->id, // Account for the initial network added by the test suite.
     248                        self::$network_ids['make.wordpress.org/'],
     249                );
     250
     251                $this->assertEqualSets( $expected, $found );
     252        }
     253
     254        public function test_wp_network_query_by_domain__not_in_with_multiple_domains_and_number_and_offset() {
     255                $q = new WP_Network_Query();
     256                $found = $q->query( array(
     257                        'fields'         => 'ids',
     258                        'number'         => 2,
     259                        'offset'         => 1,
     260                        'domain__not_in' => array( 'wordpress.org', 'www.w.org' ),
     261                ));
     262
     263                $expected = array(
     264                        self::$network_ids['make.wordpress.org/'],
     265                        self::$network_ids['www.wordpress.net/'],
     266                );
     267
     268                $this->assertEqualSets( $expected, $found );
     269        }
     270
     271        public function test_wp_network_query_by_path_with_expected_results() {
     272                $q = new WP_Network_Query();
     273                $found = $q->query( array(
     274                        'fields'          => 'ids',
     275                        'path'            => '/',
     276                        'network__not_in' => get_current_site()->id, // Exclude the initial network added by the test suite.
     277                ) );
     278
     279                $expected = array(
     280                        self::$network_ids['wordpress.org/'],
     281                        self::$network_ids['make.wordpress.org/'],
     282                        self::$network_ids['www.wordpress.net/'],
     283                );
     284
     285                $this->assertEqualSets( $expected, $found );
     286        }
     287
     288        public function test_wp_network_query_by_path_and_number_and_offset_with_expected_results() {
     289                $q = new WP_Network_Query();
     290                $found = $q->query( array(
     291                        'fields'          => 'ids',
     292                        'number'          => 1,
     293                        'offset'          => 2,
     294                        'path'            => '/',
     295                        'network__not_in' => get_current_site()->id, // Exclude the initial network added by the test suite.
     296                ) );
     297
     298                $expected = array(
     299                        self::$network_ids['www.wordpress.net/'],
     300                );
     301
     302                $this->assertEqualSets( $expected, $found );
     303        }
     304
     305        public function test_wp_network_query_by_path_with_no_expected_results() {
     306                $q = new WP_Network_Query();
     307                $found = $q->query( array(
     308                        'fields'       => 'ids',
     309                        'path'         => '/bar/',
     310                ) );
     311
     312                $this->assertEmpty( $found );
     313        }
     314
     315        public function test_wp_network_query_by_search_with_text_in_domain() {
     316                $q = new WP_Network_Query();
     317                $found = $q->query( array(
     318                        'fields'       => 'ids',
     319                        'search'       => 'ww.word',
     320                ) );
     321
     322                $expected = array(
     323                        self::$network_ids['www.wordpress.net/'],
     324                );
     325
     326                $this->assertEqualSets( $expected, $found );
     327        }
     328
     329        public function test_wp_network_query_by_search_with_text_in_path() {
     330                $q = new WP_Network_Query();
     331                $found = $q->query( array(
     332                        'fields'       => 'ids',
     333                        'search'       => 'foo',
     334                ) );
     335
     336                $expected = array(
     337                        self::$network_ids['www.w.org/foo/'],
     338                );
     339
     340                $this->assertEqualSets( $expected, $found );
     341        }
     342
     343        public function test_wp_network_query_by_path_order_by_domain_desc() {
     344                $q = new WP_Network_Query();
     345                $found = $q->query( array(
     346                        'fields'          => 'ids',
     347                        'path'            => '/',
     348                        'network__not_in' => get_current_site()->id, // Exclude the initial network added by the test suite.
     349                        'order'           => 'DESC',
     350                        'orderby'         => 'domain',
     351                ) );
     352
     353                $expected = array(
     354                        self::$network_ids['www.wordpress.net/'],
     355                        self::$network_ids['wordpress.org/'],
     356                        self::$network_ids['make.wordpress.org/'],
     357                );
     358
     359                $this->assertEquals( $expected, $found );
     360        }
     361
     362        public function test_wp_network_query_by_meta_query_key_value_combination() {
     363                update_network_option( self::$network_ids['wordpress.org/'], 'key1', 'value1' );
     364                update_network_option( self::$network_ids['www.w.org/foo/'], 'key1', 'value1' );
     365                update_network_option( self::$network_ids['make.wordpress.org/'], 'key1', 'value2' );
     366                update_network_option( self::$network_ids['make.wordpress.org/'], 'key2', 'value1' );
     367
     368                $q = new WP_Network_Query();
     369                $found = $q->query( array(
     370                        'fields'     => 'ids',
     371                        'meta_query' => array(
     372                                'relation' => 'AND',
     373                                array(
     374                                        'key'   => 'key1',
     375                                        'value' => 'value1',
     376                                ),
     377                        ),
     378                ) );
     379
     380                $expected = array(
     381                        self::$network_ids['wordpress.org/'],
     382                        self::$network_ids['www.w.org/foo/'],
     383                );
     384
     385                $this->assertEqualSets( $expected, $found );
     386        }
     387
     388        public function test_wp_network_query_by_meta_query_key_exists() {
     389                update_network_option( self::$network_ids['wordpress.org/'], 'key1', 'value1' );
     390                update_network_option( self::$network_ids['www.w.org/foo/'], 'key1', 'value1' );
     391                update_network_option( self::$network_ids['make.wordpress.org/'], 'key1', 'value2' );
     392                update_network_option( self::$network_ids['make.wordpress.org/'], 'key2', 'value1' );
     393
     394                $q = new WP_Network_Query();
     395                $found = $q->query( array(
     396                        'fields'     => 'ids',
     397                        'meta_query' => array(
     398                                'relation' => 'AND',
     399                                array(
     400                                        'key'     => 'key1',
     401                                        'compare' => 'EXISTS',
     402                                ),
     403                        ),
     404                ) );
     405
     406                $expected = array(
     407                        self::$network_ids['wordpress.org/'],
     408                        self::$network_ids['make.wordpress.org/'],
     409                        self::$network_ids['www.w.org/foo/'],
     410                );
     411
     412                $this->assertEqualSets( $expected, $found );
     413        }
     414
     415        public function test_wp_network_query_by_meta_query_key_value_combination_and_other_key_exists() {
     416                update_network_option( self::$network_ids['wordpress.org/'], 'key1', 'value1' );
     417                update_network_option( self::$network_ids['www.w.org/foo/'], 'key1', 'value1' );
     418                update_network_option( self::$network_ids['make.wordpress.org/'], 'key1', 'value2' );
     419                update_network_option( self::$network_ids['make.wordpress.org/'], 'key2', 'value1' );
     420
     421                $q = new WP_Network_Query();
     422                $found = $q->query( array(
     423                        'fields'     => 'ids',
     424                        'meta_query' => array(
     425                                'relation' => 'AND',
     426                                array(
     427                                        'key'     => 'key1',
     428                                        'value'   => 'value2',
     429                                ),
     430                                array(
     431                                        'key'     => 'key2',
     432                                        'compare' => 'EXISTS',
     433                                ),
     434                        ),
     435                ) );
     436
     437                $expected = array(
     438                        self::$network_ids['make.wordpress.org/'],
     439                );
     440
     441                $this->assertEqualSets( $expected, $found );
     442        }
     443
     444        public function test_wp_network_query_by_meta_query_key_value_combination_or_other_key_exists() {
     445                update_network_option( self::$network_ids['wordpress.org/'], 'key1', 'value1' );
     446                update_network_option( self::$network_ids['www.w.org/foo/'], 'key1', 'value1' );
     447                update_network_option( self::$network_ids['make.wordpress.org/'], 'key1', 'value2' );
     448                update_network_option( self::$network_ids['make.wordpress.org/'], 'key2', 'value1' );
     449
     450                $q = new WP_Network_Query();
     451                $found = $q->query( array(
     452                        'fields'     => 'ids',
     453                        'meta_query' => array(
     454                                'relation' => 'OR',
     455                                array(
     456                                        'key'     => 'key1',
     457                                        'value'   => 'value1',
     458                                ),
     459                                array(
     460                                        'key'     => 'key2',
     461                                        'compare' => 'EXISTS',
     462                                ),
     463                        ),
     464                ) );
     465
     466                $expected = array(
     467                        self::$network_ids['wordpress.org/'],
     468                        self::$network_ids['make.wordpress.org/'],
     469                        self::$network_ids['www.w.org/foo/'],
     470                );
     471
     472                $this->assertEqualSets( $expected, $found );
     473        }
     474
     475        public function test_wp_network_query_orderby_meta() {
     476                update_network_option( self::$network_ids['wordpress.org/'], 'key', 'value1' );
     477                update_network_option( self::$network_ids['www.w.org/foo/'], 'key', 'value4' );
     478                update_network_option( self::$network_ids['make.wordpress.org/'], 'key', 'something' );
     479
     480                $q = new WP_Network_Query();
     481                $found = $q->query( array(
     482                        'fields'   => 'ids',
     483                        'meta_key' => 'key',
     484                        'orderby'  => array( 'meta_value' ),
     485                        'order'    => 'DESC',
     486                ) );
     487
     488                $expected = array(
     489                        self::$network_ids['www.w.org/foo/'],
     490                        self::$network_ids['wordpress.org/'],
     491                        self::$network_ids['make.wordpress.org/'],
     492                );
     493
     494                $this->assertEquals( $expected, $found );
     495        }
     496}
     497
     498endif;