Make WordPress Core

Changeset 43010


Ignore:
Timestamp:
04/27/2018 11:40:35 AM (7 years ago)
Author:
flixos90
Message:

Multisite: Add meta query functionality to WP_Site_Query.

After the introduction of site metadata in [42836], it should be possible to query sites by that data.

Fixes #40229.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-site-query.php

    r42876 r43010  
    4141
    4242    /**
     43     * Metadata query container.
     44     *
     45     * @since 5.0.0
     46     * @var WP_Meta_Query
     47     */
     48    public $meta_query = false;
     49
     50    /**
     51     * Metadata query clauses.
     52     *
     53     * @since 5.0.0
     54     * @var array
     55     */
     56    protected $meta_query_clauses;
     57
     58    /**
    4359     * Date query container.
    4460     *
     
    93109     * @since 4.6.0
    94110     * @since 4.8.0 Introduced the 'lang_id', 'lang__in', and 'lang__not_in' parameters.
    95      * @since 5.0.0 Introduced the 'update_site_meta_cache' parameter.
     111     * @since 5.0.0 Introduced the 'update_site_meta_cache', 'meta_query', 'meta_key',
     112     *              'meta_value', 'meta_type' and 'meta_compare' parameters.
    96113     *
    97114     * @param string|array $query {
     
    140157     *     @type bool         $update_site_cache      Whether to prime the cache for found sites. Default true.
    141158     *     @type bool         $update_site_meta_cache Whether to prime the metadata cache for found sites. Default true.
     159     *     @type array        $meta_query             Meta query clauses to limit retrieved sites by. See `WP_Meta_Query`.
     160     *                                                Default empty.
     161     *     @type string       $meta_key               Limit sites to those matching a specific metadata key.
     162     *                                                Can be used in conjunction with `$meta_value`. Default empty.
     163     *     @type string       $meta_value             Limit sites to those matching a specific metadata value.
     164     *                                                Usually used in conjunction with `$meta_key`. Default empty.
     165     *     @type string       $meta_type              Data type that the `$meta_value` column will be CAST to for
     166     *                                                comparisons. Default empty.
     167     *     @type string       $meta_compare           Comparison operator to test the `$meta_value`. Default empty.
    142168     * }
    143169     */
     
    176202            'update_site_cache'      => true,
    177203            'update_site_meta_cache' => true,
     204            'meta_query'             => '',
     205            'meta_key'               => '',
     206            'meta_value'             => '',
     207            'meta_type'              => '',
     208            'meta_compare'           => '',
    178209        );
    179210
     
    229260     * @since 4.6.0
    230261     *
     262     * @global wpdb $wpdb WordPress database abstraction object.
     263     *
    231264     * @return array|int List of WP_Site objects, a list of site ids when 'fields' is set to 'ids',
    232265     *                   or the number of sites when 'count' is passed as a query var.
    233266     */
    234267    public function get_sites() {
     268        global $wpdb;
     269
    235270        $this->parse_query();
     271
     272        // Parse meta query.
     273        $this->meta_query = new WP_Meta_Query();
     274        $this->meta_query->parse_query_vars( $this->query_vars );
    236275
    237276        /**
     
    243282         */
    244283        do_action_ref_array( 'pre_get_sites', array( &$this ) );
     284
     285        // Reparse query vars, in case they were modified in a 'pre_get_sites' callback.
     286        $this->meta_query->parse_query_vars( $this->query_vars );
     287        if ( ! empty( $this->meta_query->queries ) ) {
     288            $this->meta_query_clauses = $this->meta_query->get_sql( 'blog', $wpdb->blogs, 'blog_id', $this );
     289        }
    245290
    246291        // $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
     
    371416            $orderby = implode( ', ', $orderby_array );
    372417        } else {
    373             $orderby = "blog_id $order";
     418            $orderby = "{$wpdb->blogs}.blog_id $order";
    374419        }
    375420
     
    388433            $fields = 'COUNT(*)';
    389434        } else {
    390             $fields = 'blog_id';
     435            $fields = "{$wpdb->blogs}.blog_id";
    391436        }
    392437
     
    394439        $site_id = absint( $this->query_vars['ID'] );
    395440        if ( ! empty( $site_id ) ) {
    396             $this->sql_clauses['where']['ID'] = $wpdb->prepare( 'blog_id = %d', $site_id );
     441            $this->sql_clauses['where']['ID'] = $wpdb->prepare( "{$wpdb->blogs}.blog_id = %d", $site_id );
    397442        }
    398443
    399444        // Parse site IDs for an IN clause.
    400445        if ( ! empty( $this->query_vars['site__in'] ) ) {
    401             $this->sql_clauses['where']['site__in'] = 'blog_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['site__in'] ) ) . ' )';
     446            $this->sql_clauses['where']['site__in'] = "{$wpdb->blogs}.blog_id IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__in'] ) ) . ' )';
    402447        }
    403448
    404449        // Parse site IDs for a NOT IN clause.
    405450        if ( ! empty( $this->query_vars['site__not_in'] ) ) {
    406             $this->sql_clauses['where']['site__not_in'] = 'blog_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['site__not_in'] ) ) . ' )';
     451            $this->sql_clauses['where']['site__not_in'] = "{$wpdb->blogs}.blog_id NOT IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__not_in'] ) ) . ' )';
    407452        }
    408453
     
    527572        $join = '';
    528573
     574        if ( ! empty( $this->meta_query_clauses ) ) {
     575            $join .= $this->meta_query_clauses['join'];
     576
     577            // Strip leading 'AND'.
     578            $this->sql_clauses['where']['meta_query'] = preg_replace( '/^\s*AND\s*/', '', $this->meta_query_clauses['where'] );
     579
     580            if ( ! $this->query_vars['count'] ) {
     581                $groupby = "{$wpdb->blogs}.blog_id";
     582            }
     583        }
     584
    529585        $where = implode( ' AND ', $this->sql_clauses['where'] );
    530586
     
    676732                break;
    677733            case 'id':
    678                 $parsed = 'blog_id';
    679                 break;
     734                $parsed = "{$wpdb->blogs}.blog_id";
     735                break;
     736        }
     737
     738        if ( ! empty( $parsed ) || empty( $this->meta_query_clauses ) ) {
     739            return $parsed;
     740        }
     741
     742        $meta_clauses = $this->meta_query->get_clauses();
     743        if ( empty( $meta_clauses ) ) {
     744            return $parsed;
     745        }
     746
     747        $primary_meta_query = reset( $meta_clauses );
     748        if ( ! empty( $primary_meta_query['key'] ) && $primary_meta_query['key'] === $orderby ) {
     749            $orderby = 'meta_value';
     750        }
     751
     752        switch ( $orderby ) {
     753            case 'meta_value':
     754                if ( ! empty( $primary_meta_query['type'] ) ) {
     755                    $parsed = "CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})";
     756                } else {
     757                    $parsed = "{$primary_meta_query['alias']}.meta_value";
     758                }
     759                break;
     760            case 'meta_value_num':
     761                $parsed = "{$primary_meta_query['alias']}.meta_value+0";
     762                break;
     763            default:
     764                if ( isset( $meta_clauses[ $orderby ] ) ) {
     765                    $meta_clause = $meta_clauses[ $orderby ];
     766                    $parsed      = "CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})";
     767                }
    680768        }
    681769
  • trunk/tests/phpunit/tests/multisite/siteMeta.php

    r42836 r43010  
    257257        $this->assertSame( $num_queries + 1, $wpdb->num_queries);
    258258    }
     259
     260    /**
     261     * @ticket 40229
     262     */
     263    public function test_add_site_meta_should_bust_get_sites_cache() {
     264        if ( ! is_site_meta_supported() ) {
     265            $this->markTestSkipped( 'Tests only runs with the blogmeta database table installed' );
     266        }
     267
     268        add_site_meta( self::$site_id, 'foo', 'bar' );
     269
     270        // Prime cache.
     271        $found = get_sites( array(
     272            'fields' => 'ids',
     273            'meta_query' => array(
     274                array(
     275                    'key' => 'foo',
     276                    'value' => 'bar',
     277                ),
     278            ),
     279        ) );
     280
     281        $this->assertEqualSets( array( self::$site_id ), $found );
     282
     283        add_site_meta( self::$site_id2, 'foo', 'bar' );
     284
     285        $found = get_sites( array(
     286            'fields' => 'ids',
     287            'meta_query' => array(
     288                array(
     289                    'key' => 'foo',
     290                    'value' => 'bar',
     291                ),
     292            ),
     293        ) );
     294
     295        $this->assertEqualSets( array( self::$site_id, self::$site_id2 ), $found );
     296    }
     297
     298    /**
     299     * @ticket 40229
     300     */
     301    public function test_update_site_meta_should_bust_get_sites_cache() {
     302        if ( ! is_site_meta_supported() ) {
     303            $this->markTestSkipped( 'Tests only runs with the blogmeta database table installed' );
     304        }
     305
     306        add_site_meta( self::$site_id, 'foo', 'bar' );
     307        add_site_meta( self::$site_id2, 'foo', 'baz' );
     308
     309        // Prime cache.
     310        $found = get_sites( array(
     311            'fields' => 'ids',
     312            'meta_query' => array(
     313                array(
     314                    'key' => 'foo',
     315                    'value' => 'bar',
     316                ),
     317            ),
     318        ) );
     319
     320        $this->assertEqualSets( array( self::$site_id ), $found );
     321
     322        update_site_meta( self::$site_id2, 'foo', 'bar' );
     323
     324        $found = get_sites( array(
     325            'fields' => 'ids',
     326            'meta_query' => array(
     327                array(
     328                    'key' => 'foo',
     329                    'value' => 'bar',
     330                ),
     331            ),
     332        ) );
     333
     334        $this->assertEqualSets( array( self::$site_id, self::$site_id2 ), $found );
     335    }
     336
     337    /**
     338     * @ticket 40229
     339     */
     340    public function test_delete_site_meta_should_bust_get_sites_cache() {
     341        if ( ! is_site_meta_supported() ) {
     342            $this->markTestSkipped( 'Tests only runs with the blogmeta database table installed' );
     343        }
     344
     345        add_site_meta( self::$site_id, 'foo', 'bar' );
     346        add_site_meta( self::$site_id2, 'foo', 'bar' );
     347
     348        // Prime cache.
     349        $found = get_sites( array(
     350            'fields' => 'ids',
     351            'meta_query' => array(
     352                array(
     353                    'key' => 'foo',
     354                    'value' => 'bar',
     355                ),
     356            ),
     357        ) );
     358
     359        $this->assertEqualSets( array( self::$site_id, self::$site_id2 ), $found );
     360
     361        delete_site_meta( self::$site_id2, 'foo', 'bar' );
     362
     363        $found = get_sites( array(
     364            'fields' => 'ids',
     365            'meta_query' => array(
     366                array(
     367                    'key' => 'foo',
     368                    'value' => 'bar',
     369                ),
     370            ),
     371        ) );
     372
     373        $this->assertEqualSets( array( self::$site_id ), $found );
     374    }
    259375}
    260376
  • trunk/tests/phpunit/tests/multisite/siteQuery.php

    r42343 r43010  
    879879            $this->assertEquals( $number_of_queries + 1, $wpdb->num_queries );
    880880        }
     881
     882        /**
     883         * @ticket 40229
     884         * @dataProvider data_wp_site_query_meta_query
     885         */
     886        public function test_wp_site_query_meta_query( $query, $expected, $strict ) {
     887            if ( ! is_site_meta_supported() ) {
     888                $this->markTestSkipped( 'Tests only runs with the blogmeta database table installed' );
     889            }
     890
     891            add_site_meta( self::$site_ids['wordpress.org/'], 'foo', 'foo' );
     892            add_site_meta( self::$site_ids['wordpress.org/foo/'], 'foo', 'bar' );
     893            add_site_meta( self::$site_ids['wordpress.org/foo/bar/'], 'foo', 'baz' );
     894            add_site_meta( self::$site_ids['make.wordpress.org/'], 'bar', 'baz' );
     895            add_site_meta( self::$site_ids['wordpress.org/'], 'numberfoo', 1 );
     896            add_site_meta( self::$site_ids['wordpress.org/foo/'], 'numberfoo', 2 );
     897
     898            $query['fields'] = 'ids';
     899
     900            $q     = new WP_Site_Query();
     901            $found = $q->query( $query );
     902
     903            foreach ( $expected as $index => $domain_path ) {
     904                $expected[ $index ] = self::$site_ids[ $domain_path ];
     905            }
     906
     907            if ( $strict ) {
     908                $this->assertEquals( $expected, $found );
     909            } else {
     910                $this->assertEqualSets( $expected, $found );
     911            }
     912        }
     913
     914        public function data_wp_site_query_meta_query() {
     915            return array(
     916                array(
     917                    array(
     918                        'meta_key' => 'foo',
     919                    ),
     920                    array(
     921                        'wordpress.org/',
     922                        'wordpress.org/foo/',
     923                        'wordpress.org/foo/bar/',
     924                    ),
     925                    false,
     926                ),
     927                array(
     928                    array(
     929                        'meta_key'   => 'foo',
     930                        'meta_value' => 'bar',
     931                    ),
     932                    array(
     933                        'wordpress.org/foo/',
     934                    ),
     935                    false,
     936                ),
     937                array(
     938                    array(
     939                        'meta_key'     => 'foo',
     940                        'meta_value'   => array( 'bar', 'baz' ),
     941                        'meta_compare' => 'IN',
     942                    ),
     943                    array(
     944                        'wordpress.org/foo/',
     945                        'wordpress.org/foo/bar/',
     946                    ),
     947                    false,
     948                ),
     949                array(
     950                    array(
     951                        'meta_query' => array(
     952                            array(
     953                                'key'   => 'foo',
     954                                'value' => 'bar',
     955                            ),
     956                            array(
     957                                'key'   => 'numberfoo',
     958                                'value' => 2,
     959                                'type'  => 'NUMERIC',
     960                            ),
     961                        ),
     962                    ),
     963                    array(
     964                        'wordpress.org/foo/',
     965                    ),
     966                    false,
     967                ),
     968                array(
     969                    array(
     970                        'meta_key' => 'foo',
     971                        'orderby'  => 'meta_value',
     972                        'order'    => 'ASC',
     973                    ),
     974                    array(
     975                        'wordpress.org/foo/',
     976                        'wordpress.org/foo/bar/',
     977                        'wordpress.org/',
     978                    ),
     979                    true,
     980                ),
     981                array(
     982                    array(
     983                        'meta_key' => 'foo',
     984                        'orderby'  => 'foo',
     985                        'order'    => 'ASC',
     986                    ),
     987                    array(
     988                        'wordpress.org/foo/',
     989                        'wordpress.org/foo/bar/',
     990                        'wordpress.org/',
     991                    ),
     992                    true,
     993                ),
     994                array(
     995                    array(
     996                        'meta_key' => 'numberfoo',
     997                        'orderby'  => 'meta_value_num',
     998                        'order'    => 'DESC',
     999                    ),
     1000                    array(
     1001                        'wordpress.org/foo/',
     1002                        'wordpress.org/',
     1003                    ),
     1004                    true,
     1005                ),
     1006                array(
     1007                    array(
     1008                        'meta_query' => array(
     1009                            array(
     1010                                'key'     => 'foo',
     1011                                'value'   => array( 'foo', 'bar' ),
     1012                                'compare' => 'IN',
     1013                            ),
     1014                            array(
     1015                                'key' => 'numberfoo',
     1016                            ),
     1017                        ),
     1018                        'orderby'    => array( 'meta_value' => 'ASC' ),
     1019                    ),
     1020                    array(
     1021                        'wordpress.org/foo/',
     1022                        'wordpress.org/',
     1023                    ),
     1024                    true,
     1025                ),
     1026                array(
     1027                    array(
     1028                        'meta_query' => array(
     1029                            array(
     1030                                'key'     => 'foo',
     1031                                'value'   => array( 'foo', 'bar' ),
     1032                                'compare' => 'IN',
     1033                            ),
     1034                            array(
     1035                                'key' => 'numberfoo',
     1036                            ),
     1037                        ),
     1038                        'orderby'    => array( 'foo' => 'ASC' ),
     1039                    ),
     1040                    array(
     1041                        'wordpress.org/foo/',
     1042                        'wordpress.org/',
     1043                    ),
     1044                    true,
     1045                ),
     1046                array(
     1047                    array(
     1048                        'meta_query' => array(
     1049                            array(
     1050                                'key'     => 'foo',
     1051                                'value'   => array( 'foo', 'bar' ),
     1052                                'compare' => 'IN',
     1053                            ),
     1054                            'my_subquery' => array(
     1055                                'key' => 'numberfoo',
     1056                            ),
     1057                        ),
     1058                        'orderby'    => array( 'my_subquery' => 'DESC' ),
     1059                    ),
     1060                    array(
     1061                        'wordpress.org/foo/',
     1062                        'wordpress.org/',
     1063                    ),
     1064                    true,
     1065                ),
     1066            );
     1067        }
    8811068    }
    8821069
Note: See TracChangeset for help on using the changeset viewer.