Ticket #40229: 40229.diff
File 40229.diff, 15.3 KB (added by , 7 years ago) |
---|
-
src/wp-includes/class-wp-site-query.php
40 40 ); 41 41 42 42 /** 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 /** 43 59 * Date query container. 44 60 * 45 61 * @since 4.6.0 … … 92 108 * 93 109 * @since 4.6.0 94 110 * @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. 96 113 * 97 114 * @param string|array $query { 98 115 * Optional. Array or query string of site query parameters. Default empty. … … 139 156 * Default empty array. 140 157 * @type bool $update_site_cache Whether to prime the cache for found sites. Default true. 141 158 * @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. 142 168 * } 143 169 */ 144 170 public function __construct( $query = '' ) { … … 175 201 'date_query' => null, // See WP_Date_Query 176 202 'update_site_cache' => true, 177 203 'update_site_meta_cache' => true, 204 'meta_query' => '', 205 'meta_key' => '', 206 'meta_value' => '', 207 'meta_type' => '', 208 'meta_compare' => '', 178 209 ); 179 210 180 211 if ( ! empty( $query ) ) { … … 228 259 * 229 260 * @since 4.6.0 230 261 * 262 * @global wpdb $wpdb WordPress database abstraction object. 263 * 231 264 * @return array|int List of WP_Site objects, a list of site ids when 'fields' is set to 'ids', 232 265 * or the number of sites when 'count' is passed as a query var. 233 266 */ 234 267 public function get_sites() { 268 global $wpdb; 269 235 270 $this->parse_query(); 236 271 272 // Parse meta query. 273 $this->meta_query = new WP_Meta_Query(); 274 $this->meta_query->parse_query_vars( $this->query_vars ); 275 237 276 /** 238 277 * Fires before sites are retrieved. 239 278 * … … 243 282 */ 244 283 do_action_ref_array( 'pre_get_sites', array( &$this ) ); 245 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 } 290 246 291 // $args can include anything. Only use the args defined in the query_var_defaults to compute the key. 247 292 $_args = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ); 248 293 … … 370 415 371 416 $orderby = implode( ', ', $orderby_array ); 372 417 } else { 373 $orderby = " blog_id $order";418 $orderby = "{$wpdb->blogs}.blog_id $order"; 374 419 } 375 420 376 421 $number = absint( $this->query_vars['number'] ); … … 387 432 if ( $this->query_vars['count'] ) { 388 433 $fields = 'COUNT(*)'; 389 434 } else { 390 $fields = 'blog_id';435 $fields = "{$wpdb->blogs}.blog_id"; 391 436 } 392 437 393 438 // Parse site IDs for an IN clause. 394 439 $site_id = absint( $this->query_vars['ID'] ); 395 440 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 ); 397 442 } 398 443 399 444 // Parse site IDs for an IN clause. 400 445 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'] ) ) . ' )'; 402 447 } 403 448 404 449 // Parse site IDs for a NOT IN clause. 405 450 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'] ) ) . ' )'; 407 452 } 408 453 409 454 $network_id = absint( $this->query_vars['network_id'] ); … … 526 571 527 572 $join = ''; 528 573 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 529 585 $where = implode( ' AND ', $this->sql_clauses['where'] ); 530 586 531 587 $pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' ); … … 675 731 $parsed = 'CHAR_LENGTH(path)'; 676 732 break; 677 733 case 'id': 678 $parsed = 'blog_id';734 $parsed = "{$wpdb->blogs}.blog_id"; 679 735 break; 680 736 } 681 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 } 768 } 769 682 770 return $parsed; 683 771 } 684 772 -
src/wp-settings.php
98 98 require( ABSPATH . WPINC . '/formatting.php' ); 99 99 require( ABSPATH . WPINC . '/meta.php' ); 100 100 require( ABSPATH . WPINC . '/functions.php' ); 101 require( ABSPATH . WPINC . '/class-wp-meta-query.php' ); 101 102 require( ABSPATH . WPINC . '/class-wp-matchesmapregex.php' ); 102 103 require( ABSPATH . WPINC . '/class-wp.php' ); 103 104 require( ABSPATH . WPINC . '/class-wp-error.php' ); … … 159 160 require( ABSPATH . WPINC . '/class-wp-user-query.php' ); 160 161 require( ABSPATH . WPINC . '/class-wp-session-tokens.php' ); 161 162 require( ABSPATH . WPINC . '/class-wp-user-meta-session-tokens.php' ); 162 require( ABSPATH . WPINC . '/class-wp-meta-query.php' );163 163 require( ABSPATH . WPINC . '/class-wp-metadata-lazyloader.php' ); 164 164 require( ABSPATH . WPINC . '/general-template.php' ); 165 165 require( ABSPATH . WPINC . '/link-template.php' ); -
tests/phpunit/tests/multisite/siteMeta.php
256 256 get_site_meta( self::$site_id, 'foo', true ); 257 257 $this->assertSame( $num_queries + 1, $wpdb->num_queries); 258 258 } 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 } 259 375 } 260 376 261 377 endif; -
tests/phpunit/tests/multisite/siteQuery.php
878 878 ); 879 879 $this->assertEquals( $number_of_queries + 1, $wpdb->num_queries ); 880 880 } 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 } 881 1068 } 882 1069 883 1070 endif;