WordPress.org

Make WordPress Core

Ticket #45749: 45749.8.diff

File 45749.8.diff, 17.5 KB (added by adamsilverstein, 19 months ago)
  • src/wp-includes/class-wp-network-query.php

    diff --git src/wp-includes/class-wp-network-query.php src/wp-includes/class-wp-network-query.php
    index d381e60117..c245660b88 100644
     
    22/**
    33 * Network API: WP_Network_Query class
    44 *
    5  * @package WordPress
     5 * @package    WordPress
    66 * @subpackage Multisite
    7  * @since 4.6.0
     7 * @since      4.6.0
    88 */
    99
    1010/**
     
    1212 *
    1313 * @since 4.6.0
    1414 *
    15  * @see WP_Network_Query::__construct() for accepted arguments.
     15 * @see   WP_Network_Query::__construct() for accepted arguments.
    1616 */
    1717class WP_Network_Query {
    1818
    class WP_Network_Query { 
    6363         */
    6464        public $networks;
    6565
     66        /**
     67         * List of network ids in the query.
     68         *
     69         * @since 5.2.0
     70         * @var array|null
     71         */
     72        public $network_ids = null;
     73
    6674        /**
    6775         * The amount of found networks for the current query.
    6876         *
    class WP_Network_Query { 
    8694         *
    8795         * @since 4.6.0
    8896         *
    89          * @param string|array $query {
    90          *     Optional. Array or query string of network query parameters. Default empty.
     97         * @param string|array $query                {
     98         *                                           Optional. Array or query string of network query parameters. Default empty.
    9199         *
    92          *     @type array        $network__in          Array of network IDs to include. Default empty.
    93          *     @type array        $network__not_in      Array of network IDs to exclude. Default empty.
    94          *     @type bool         $count                Whether to return a network count (true) or array of network objects.
     100         * @type array         $network__in          Array of network IDs to include. Default empty.
     101         * @type array         $network__not_in      Array of network IDs to exclude. Default empty.
     102         * @type bool          $count                Whether to return a network count (true) or array of network objects.
    95103         *                                              Default false.
    96          *     @type string       $fields               Network fields to return. Accepts 'ids' (returns an array of network IDs)
     104         * @type string        $fields               Network fields to return. Accepts 'ids' (returns an array of network IDs)
    97105         *                                              or empty (returns an array of complete network objects). Default empty.
    98          *     @type int          $number               Maximum number of networks to retrieve. Default empty (no limit).
    99          *     @type int          $offset               Number of networks to offset the query. Used to build LIMIT clause.
     106         * @type int           $number               Maximum number of networks to retrieve. Default empty (no limit).
     107         * @type int           $offset               Number of networks to offset the query. Used to build LIMIT clause.
    100108         *                                              Default 0.
    101          *     @type bool         $no_found_rows        Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true.
    102          *     @type string|array $orderby              Network status or array of statuses. Accepts 'id', 'domain', 'path',
     109         * @type bool          $no_found_rows        Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true.
     110         * @type string|array $orderby              Network status or array of statuses. Accepts 'id', 'domain', 'path',
    103111         *                                              'domain_length', 'path_length' and 'network__in'. Also accepts false,
    104112         *                                              an empty array, or 'none' to disable `ORDER BY` clause. Default 'id'.
    105          *     @type string       $order                How to order retrieved networks. Accepts 'ASC', 'DESC'. Default 'ASC'.
    106          *     @type string       $domain               Limit results to those affiliated with a given domain. Default empty.
    107          *     @type array        $domain__in           Array of domains to include affiliated networks for. Default empty.
    108          *     @type array        $domain__not_in       Array of domains to exclude affiliated networks for. Default empty.
    109          *     @type string       $path                 Limit results to those affiliated with a given path. Default empty.
    110          *     @type array        $path__in             Array of paths to include affiliated networks for. Default empty.
    111          *     @type array        $path__not_in         Array of paths to exclude affiliated networks for. Default empty.
    112          *     @type string       $search               Search term(s) to retrieve matching networks for. Default empty.
    113          *     @type bool         $update_network_cache Whether to prime the cache for found networks. Default true.
     113         * @type string        $order                How to order retrieved networks. Accepts 'ASC', 'DESC'. Default 'ASC'.
     114         * @type string        $domain               Limit results to those affiliated with a given domain. Default empty.
     115         * @type array         $domain__in           Array of domains to include affiliated networks for. Default empty.
     116         * @type array         $domain__not_in       Array of domains to exclude affiliated networks for. Default empty.
     117         * @type string        $path                 Limit results to those affiliated with a given path. Default empty.
     118         * @type array         $path__in             Array of paths to include affiliated networks for. Default empty.
     119         * @type array         $path__not_in         Array of paths to exclude affiliated networks for. Default empty.
     120         * @type string        $search               Search term(s) to retrieve matching networks for. Default empty.
     121         * @type bool          $update_network_cache Whether to prime the cache for found networks. Default true.
    114122         * }
    115123         */
    116124        public function __construct( $query = '' ) {
    class WP_Network_Query { 
    169177         * @since 4.6.0
    170178         *
    171179         * @param string|array $query Array or URL query string of parameters.
     180         *
    172181         * @return array|int List of WP_Network objects, a list of network ids when 'fields' is set to 'ids',
    173182         *                   or the number of networks when 'count' is passed as a query var.
    174183         */
    175184        public function query( $query ) {
    176185                $this->query_vars = wp_parse_args( $query );
     186
    177187                return $this->get_networks();
    178188        }
    179189
    class WP_Network_Query { 
    197207                 */
    198208                do_action_ref_array( 'pre_get_networks', array( &$this ) );
    199209
    200                 // $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
    201                 $_args = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) );
     210                /**
     211                 * Filter the sites array before the query takes place.
     212                 *
     213                 * Return a non-null value to bypass WordPress's default site queries.
     214                 *
     215                 *
     216                 * @since 5.2.0
     217                 *
     218                 * @param array|null       $site_ids Return an array of site data to short-circuit WP's site query,
     219                 *                                   or null to allow WP to run its normal queries.
     220                 * @param WP_Network_Query $this     The WP_Network_Query instance, passed by reference.
     221                 */
     222                $this->network_ids = apply_filters_ref_array( 'networks_pre_query', array( $this->network_ids, &$this ) );
    202223
    203                 // Ignore the $fields argument as the queried result will be the same regardless.
    204                 unset( $_args['fields'] );
     224                if ( null === $this->network_ids ) {
    205225
    206                 $key          = md5( serialize( $_args ) );
    207                 $last_changed = wp_cache_get_last_changed( 'networks' );
     226                        // $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
     227                        $_args = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) );
    208228
    209                 $cache_key   = "get_network_ids:$key:$last_changed";
    210                 $cache_value = wp_cache_get( $cache_key, 'networks' );
     229                        // Ignore the $fields argument as the queried result will be the same regardless.
     230                        unset( $_args['fields'] );
    211231
    212                 if ( false === $cache_value ) {
    213                         $network_ids = $this->get_network_ids();
    214                         if ( $network_ids ) {
    215                                 $this->set_found_networks();
    216                         }
     232                        $key          = md5( serialize( $_args ) );
     233                        $last_changed = wp_cache_get_last_changed( 'networks' );
    217234
    218                         $cache_value = array(
    219                                 'network_ids'    => $network_ids,
    220                                 'found_networks' => $this->found_networks,
    221                         );
    222                         wp_cache_add( $cache_key, $cache_value, 'networks' );
    223                 } else {
    224                         $network_ids          = $cache_value['network_ids'];
    225                         $this->found_networks = $cache_value['found_networks'];
     235                        $cache_key   = "get_network_ids:$key:$last_changed";
     236                        $cache_value = wp_cache_get( $cache_key, 'networks' );
     237
     238                        if ( false === $cache_value ) {
     239                                $this->network_ids = $this->get_network_ids();
     240                                if ( $this->network_ids ) {
     241                                        $this->set_found_networks();
     242                                }
     243
     244                                $cache_value = array(
     245                                        'network_ids'    => $this->network_ids,
     246                                        'found_networks' => $this->found_networks,
     247                                );
     248                                wp_cache_add( $cache_key, $cache_value, 'networks' );
     249                        } else {
     250                                $this->network_ids    = $cache_value['network_ids'];
     251                                $this->found_networks = $cache_value['found_networks'];
     252                        }
    226253                }
    227254
    228255                if ( $this->found_networks && $this->query_vars['number'] ) {
    class WP_Network_Query { 
    232259                // If querying for a count only, there's nothing more to do.
    233260                if ( $this->query_vars['count'] ) {
    234261                        // $network_ids is actually a count in this case.
    235                         return intval( $network_ids );
     262                        return intval( $this->network_ids );
    236263                }
    237264
    238                 $network_ids = array_map( 'intval', $network_ids );
     265                $this->network_ids = array_map( 'intval', $this->network_ids );
    239266
    240267                if ( 'ids' == $this->query_vars['fields'] ) {
    241                         $this->networks = $network_ids;
     268                        $this->networks = $this->network_ids;
     269
    242270                        return $this->networks;
    243271                }
    244272
    245273                if ( $this->query_vars['update_network_cache'] ) {
    246                         _prime_network_caches( $network_ids );
     274                        _prime_network_caches( $this->network_ids );
    247275                }
    248276
    249277                // Fetch full network objects from the primed cache.
    250278                $_networks = array();
    251                 foreach ( $network_ids as $network_id ) {
     279                foreach ( $this->network_ids as $network_id ) {
    252280                        if ( $_network = get_network( $network_id ) ) {
    253281                                $_networks[] = $_network;
    254282                        }
    class WP_Network_Query { 
    479507         *
    480508         * @since 4.6.0
    481509         *
    482          * @global wpdb  $wpdb WordPress database abstraction object.
     510         * @global wpdb    $wpdb    WordPress database abstraction object.
    483511         *
    484512         * @param string   $string  Search string.
    485513         * @param string[] $columns Array of columns to search.
    class WP_Network_Query { 
    504532         *
    505533         * @since 4.6.0
    506534         *
    507          * @global wpdb $wpdb WordPress database abstraction object.
     535         * @global wpdb  $wpdb    WordPress database abstraction object.
    508536         *
    509537         * @param string $orderby Alias for the field to order by.
     538         *
    510539         * @return string|false Value to used in the ORDER clause. False otherwise.
    511540         */
    512541        protected function parse_orderby( $orderby ) {
    class WP_Network_Query { 
    538567         * @since 4.6.0
    539568         *
    540569         * @param string $order The 'order' query variable.
     570         *
    541571         * @return string The sanitized 'order' query variable.
    542572         */
    543573        protected function parse_order( $order ) {
  • src/wp-includes/class-wp-site-query.php

    diff --git src/wp-includes/class-wp-site-query.php src/wp-includes/class-wp-site-query.php
    index bc3e3519a3..88337ff823 100644
    class WP_Site_Query { 
    8787         */
    8888        public $sites;
    8989
     90        /**
     91         * List of site ids in the query.
     92         *
     93         * @since 5.2.0
     94         * @var array|null
     95         */
     96        public $site_ids = null;
     97
    9098        /**
    9199         * The amount of found sites for the current query.
    92100         *
    class WP_Site_Query { 
    288296                        $this->meta_query_clauses = $this->meta_query->get_sql( 'blog', $wpdb->blogs, 'blog_id', $this );
    289297                }
    290298
    291                 // $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
    292                 $_args = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) );
     299                /**
     300                 * Filter the sites array before the query takes place.
     301                 *
     302                 * Return a non-null value to bypass WordPress's default site queries.
     303                 *
     304                 *
     305                 * @since 5.2.0
     306                 *
     307                 * @param array|null    $site_ids Return an array of site data to short-circuit WP's site query,
     308                 *                                or null to allow WP to run its normal queries.
     309                 * @param WP_Site_Query $this The WP_Site_Query instance, passed by reference.
     310                 */
     311                $this->site_ids = apply_filters_ref_array( 'sites_pre_query', array( $this->site_ids, &$this ) );
    293312
    294                 // Ignore the $fields argument as the queried result will be the same regardless.
    295                 unset( $_args['fields'] );
     313                if ( null === $this->site_ids ) {
    296314
    297                 $key          = md5( serialize( $_args ) );
    298                 $last_changed = wp_cache_get_last_changed( 'sites' );
     315                        // $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
     316                        $_args = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) );
    299317
    300                 $cache_key   = "get_sites:$key:$last_changed";
    301                 $cache_value = wp_cache_get( $cache_key, 'sites' );
     318                        // Ignore the $fields argument as the queried result will be the same regardless.
     319                        unset( $_args['fields'] );
    302320
    303                 if ( false === $cache_value ) {
    304                         $site_ids = $this->get_site_ids();
    305                         if ( $site_ids ) {
    306                                 $this->set_found_sites();
    307                         }
     321                        $key          = md5( serialize( $_args ) );
     322                        $last_changed = wp_cache_get_last_changed( 'sites' );
    308323
    309                         $cache_value = array(
    310                                 'site_ids'    => $site_ids,
    311                                 'found_sites' => $this->found_sites,
    312                         );
    313                         wp_cache_add( $cache_key, $cache_value, 'sites' );
    314                 } else {
    315                         $site_ids          = $cache_value['site_ids'];
    316                         $this->found_sites = $cache_value['found_sites'];
     324                        $cache_key   = "get_sites:$key:$last_changed";
     325                        $cache_value = wp_cache_get( $cache_key, 'sites' );
     326
     327                        if ( false === $cache_value ) {
     328                                $this->site_ids = $this->get_site_ids();
     329                                if ( $this->site_ids ) {
     330                                        $this->set_found_sites();
     331                                }
     332
     333                                $cache_value = array(
     334                                        'site_ids'    => $this->site_ids,
     335                                        'found_sites' => $this->found_sites,
     336                                );
     337                                wp_cache_add( $cache_key, $cache_value, 'sites' );
     338                        } else {
     339                                $this->site_ids    = $cache_value['site_ids'];
     340                                $this->found_sites = $cache_value['found_sites'];
     341                        }
    317342                }
    318343
    319344                if ( $this->found_sites && $this->query_vars['number'] ) {
    class WP_Site_Query { 
    323348                // If querying for a count only, there's nothing more to do.
    324349                if ( $this->query_vars['count'] ) {
    325350                        // $site_ids is actually a count in this case.
    326                         return intval( $site_ids );
     351                        return intval( $this->site_ids );
    327352                }
    328353
    329                 $site_ids = array_map( 'intval', $site_ids );
     354                $this->site_ids = array_map( 'intval', $this->site_ids );
    330355
    331356                if ( 'ids' == $this->query_vars['fields'] ) {
    332                         $this->sites = $site_ids;
     357                        $this->sites = $this->site_ids;
    333358
    334359                        return $this->sites;
    335360                }
    336361
    337362                // Prime site network caches.
    338363                if ( $this->query_vars['update_site_cache'] ) {
    339                         _prime_site_caches( $site_ids, $this->query_vars['update_site_meta_cache'] );
     364                        _prime_site_caches( $this->site_ids, $this->query_vars['update_site_meta_cache'] );
    340365                }
    341366
    342367                // Fetch full site objects from the primed cache.
    343368                $_sites = array();
    344                 foreach ( $site_ids as $site_id ) {
     369                foreach ( $this->site_ids as $site_id ) {
    345370                        if ( $_site = get_site( $site_id ) ) {
    346371                                $_sites[] = $_site;
    347372                        }
  • tests/phpunit/tests/multisite/networkQuery.php

    diff --git tests/phpunit/tests/multisite/networkQuery.php tests/phpunit/tests/multisite/networkQuery.php
    index 6ec7f16c42..0b48fdc8d5 100644
    if ( is_multisite() ) : 
    522522                        );
    523523                        $this->assertEquals( $number_of_queries + 1, $wpdb->num_queries );
    524524                }
     525
     526                /**
     527                 * @ticket 45749
     528                 */
     529                public function test_networks_pre_query_filter_should_bypass_database_query() {
     530                        global $wpdb;
     531
     532                        add_filter( 'networks_pre_query', array( __CLASS__, 'filter_networks_pre_query' ), 10, 2 );
     533
     534                        $num_queries = $wpdb->num_queries;
     535
     536                        $q       = new WP_Network_Query();
     537                        $results = $q->query(
     538                                array(
     539                                        'fields' => 'ids',
     540                                )
     541                        );
     542
     543                        remove_filter( 'networks_pre_query', array( __CLASS__, 'filter_networks_pre_query' ), 10, 2 );
     544
     545                        // Make sure no queries were executed.
     546                        $this->assertSame( $num_queries, $wpdb->num_queries );
     547
     548                        // We manually inserted a non-existing site and overrode the results with it.
     549                        $this->assertSame( array( 555 ), $q->networks );
     550
     551                        // Make sure manually setting total_users doesn't get overwritten.
     552                        $this->assertEquals( 1, $q->found_networks );
     553                }
     554
     555                public static function filter_networks_pre_query( $networks, $query ) {
     556                        $query->found_networks = 1;
     557
     558                        return array( 555 );
     559                }
    525560        }
    526561
    527562endif;
  • tests/phpunit/tests/multisite/siteQuery.php

    diff --git tests/phpunit/tests/multisite/siteQuery.php tests/phpunit/tests/multisite/siteQuery.php
    index bac9269ff4..c17f977932 100644
    if ( is_multisite() ) : 
    911911                        }
    912912                }
    913913
     914
     915                /**
     916                 * @ticket 45749
     917                 */
     918                public function test_sites_pre_query_filter_should_bypass_database_query() {
     919                        global $wpdb;
     920
     921                        add_filter( 'sites_pre_query', array( __CLASS__, 'filter_sites_pre_query' ), 10, 2 );
     922
     923                        $num_queries = $wpdb->num_queries;
     924
     925                        $q       = new WP_Site_Query();
     926                        $results = $q->query(
     927                                array(
     928                                        'fields' => 'ids',
     929                                )
     930                        );
     931
     932                        remove_filter( 'sites_pre_query', array( __CLASS__, 'filter_sites_pre_query' ), 10, 2 );
     933
     934                        // Make sure no queries were executed.
     935                        $this->assertSame( $num_queries, $wpdb->num_queries );
     936
     937                        // We manually inserted a non-existing site and overrode the results with it.
     938                        $this->assertSame( array( 555 ), $q->sites );
     939
     940                        // Make sure manually setting total_users doesn't get overwritten.
     941                        $this->assertEquals( 1, $q->found_sites );
     942                }
     943
     944                public static function filter_sites_pre_query( $sites, $query ) {
     945                        $query->found_sites = 1;
     946
     947                        return array( 555 );
     948                }
     949
    914950                public function data_wp_site_query_meta_query() {
    915951                        return array(
    916952                                array(