[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Site API: WP_Site_Query class 4 * 5 * @package WordPress 6 * @subpackage Sites 7 * @since 4.6.0 8 */ 9 10 /** 11 * Core class used for querying sites. 12 * 13 * @since 4.6.0 14 * 15 * @see WP_Site_Query::__construct() for accepted arguments. 16 */ 17 #[AllowDynamicProperties] 18 class WP_Site_Query { 19 20 /** 21 * SQL for database query. 22 * 23 * @since 4.6.0 24 * @var string 25 */ 26 public $request; 27 28 /** 29 * SQL query clauses. 30 * 31 * @since 4.6.0 32 * @var array 33 */ 34 protected $sql_clauses = array( 35 'select' => '', 36 'from' => '', 37 'where' => array(), 38 'groupby' => '', 39 'orderby' => '', 40 'limits' => '', 41 ); 42 43 /** 44 * Metadata query container. 45 * 46 * @since 5.1.0 47 * @var WP_Meta_Query 48 */ 49 public $meta_query = false; 50 51 /** 52 * Metadata query clauses. 53 * 54 * @since 5.1.0 55 * @var array 56 */ 57 protected $meta_query_clauses; 58 59 /** 60 * Date query container. 61 * 62 * @since 4.6.0 63 * @var WP_Date_Query A date query instance. 64 */ 65 public $date_query = false; 66 67 /** 68 * Query vars set by the user. 69 * 70 * @since 4.6.0 71 * @var array 72 */ 73 public $query_vars; 74 75 /** 76 * Default values for query vars. 77 * 78 * @since 4.6.0 79 * @var array 80 */ 81 public $query_var_defaults; 82 83 /** 84 * List of sites located by the query. 85 * 86 * @since 4.6.0 87 * @var array 88 */ 89 public $sites; 90 91 /** 92 * The amount of found sites for the current query. 93 * 94 * @since 4.6.0 95 * @var int 96 */ 97 public $found_sites = 0; 98 99 /** 100 * The number of pages. 101 * 102 * @since 4.6.0 103 * @var int 104 */ 105 public $max_num_pages = 0; 106 107 /** 108 * Sets up the site query, based on the query vars passed. 109 * 110 * @since 4.6.0 111 * @since 4.8.0 Introduced the 'lang_id', 'lang__in', and 'lang__not_in' parameters. 112 * @since 5.1.0 Introduced the 'update_site_meta_cache', 'meta_query', 'meta_key', 113 * 'meta_compare_key', 'meta_value', 'meta_type', and 'meta_compare' parameters. 114 * @since 5.3.0 Introduced the 'meta_type_key' parameter. 115 * 116 * @param string|array $query { 117 * Optional. Array or query string of site query parameters. Default empty. 118 * 119 * @type int[] $site__in Array of site IDs to include. Default empty. 120 * @type int[] $site__not_in Array of site IDs to exclude. Default empty. 121 * @type bool $count Whether to return a site count (true) or array of site objects. 122 * Default false. 123 * @type array $date_query Date query clauses to limit sites by. See WP_Date_Query. 124 * Default null. 125 * @type string $fields Site fields to return. Accepts 'ids' (returns an array of site IDs) 126 * or empty (returns an array of complete site objects). Default empty. 127 * @type int $ID A site ID to only return that site. Default empty. 128 * @type int $number Maximum number of sites to retrieve. Default 100. 129 * @type int $offset Number of sites to offset the query. Used to build LIMIT clause. 130 * Default 0. 131 * @type bool $no_found_rows Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true. 132 * @type string|array $orderby Site status or array of statuses. Accepts: 133 * - 'id' 134 * - 'domain' 135 * - 'path' 136 * - 'network_id' 137 * - 'last_updated' 138 * - 'registered' 139 * - 'domain_length' 140 * - 'path_length' 141 * - 'site__in' 142 * - 'network__in' 143 * - 'deleted' 144 * - 'mature' 145 * - 'spam' 146 * - 'archived' 147 * - 'public' 148 * - false, an empty array, or 'none' to disable `ORDER BY` clause. 149 * Default 'id'. 150 * @type string $order How to order retrieved sites. Accepts 'ASC', 'DESC'. Default 'ASC'. 151 * @type int $network_id Limit results to those affiliated with a given network ID. If 0, 152 * include all networks. Default 0. 153 * @type int[] $network__in Array of network IDs to include affiliated sites for. Default empty. 154 * @type int[] $network__not_in Array of network IDs to exclude affiliated sites for. Default empty. 155 * @type string $domain Limit results to those affiliated with a given domain. Default empty. 156 * @type string[] $domain__in Array of domains to include affiliated sites for. Default empty. 157 * @type string[] $domain__not_in Array of domains to exclude affiliated sites for. Default empty. 158 * @type string $path Limit results to those affiliated with a given path. Default empty. 159 * @type string[] $path__in Array of paths to include affiliated sites for. Default empty. 160 * @type string[] $path__not_in Array of paths to exclude affiliated sites for. Default empty. 161 * @type int $public Limit results to public sites. Accepts 1 or 0. Default empty. 162 * @type int $archived Limit results to archived sites. Accepts 1 or 0. Default empty. 163 * @type int $mature Limit results to mature sites. Accepts 1 or 0. Default empty. 164 * @type int $spam Limit results to spam sites. Accepts 1 or 0. Default empty. 165 * @type int $deleted Limit results to deleted sites. Accepts 1 or 0. Default empty. 166 * @type int $lang_id Limit results to a language ID. Default empty. 167 * @type string[] $lang__in Array of language IDs to include affiliated sites for. Default empty. 168 * @type string[] $lang__not_in Array of language IDs to exclude affiliated sites for. Default empty. 169 * @type string $search Search term(s) to retrieve matching sites for. Default empty. 170 * @type string[] $search_columns Array of column names to be searched. Accepts 'domain' and 'path'. 171 * Default empty array. 172 * @type bool $update_site_cache Whether to prime the cache for found sites. Default true. 173 * @type bool $update_site_meta_cache Whether to prime the metadata cache for found sites. Default true. 174 * @type string|string[] $meta_key Meta key or keys to filter by. 175 * @type string|string[] $meta_value Meta value or values to filter by. 176 * @type string $meta_compare MySQL operator used for comparing the meta value. 177 * See WP_Meta_Query::__construct() for accepted values and default value. 178 * @type string $meta_compare_key MySQL operator used for comparing the meta key. 179 * See WP_Meta_Query::__construct() for accepted values and default value. 180 * @type string $meta_type MySQL data type that the meta_value column will be CAST to for comparisons. 181 * See WP_Meta_Query::__construct() for accepted values and default value. 182 * @type string $meta_type_key MySQL data type that the meta_key column will be CAST to for comparisons. 183 * See WP_Meta_Query::__construct() for accepted values and default value. 184 * @type array $meta_query An associative array of WP_Meta_Query arguments. 185 * See WP_Meta_Query::__construct() for accepted values. 186 * } 187 */ 188 public function __construct( $query = '' ) { 189 $this->query_var_defaults = array( 190 'fields' => '', 191 'ID' => '', 192 'site__in' => '', 193 'site__not_in' => '', 194 'number' => 100, 195 'offset' => '', 196 'no_found_rows' => true, 197 'orderby' => 'id', 198 'order' => 'ASC', 199 'network_id' => 0, 200 'network__in' => '', 201 'network__not_in' => '', 202 'domain' => '', 203 'domain__in' => '', 204 'domain__not_in' => '', 205 'path' => '', 206 'path__in' => '', 207 'path__not_in' => '', 208 'public' => null, 209 'archived' => null, 210 'mature' => null, 211 'spam' => null, 212 'deleted' => null, 213 'lang_id' => null, 214 'lang__in' => '', 215 'lang__not_in' => '', 216 'search' => '', 217 'search_columns' => array(), 218 'count' => false, 219 'date_query' => null, // See WP_Date_Query. 220 'update_site_cache' => true, 221 'update_site_meta_cache' => true, 222 'meta_query' => '', 223 'meta_key' => '', 224 'meta_value' => '', 225 'meta_type' => '', 226 'meta_compare' => '', 227 ); 228 229 if ( ! empty( $query ) ) { 230 $this->query( $query ); 231 } 232 } 233 234 /** 235 * Parses arguments passed to the site query with default query parameters. 236 * 237 * @since 4.6.0 238 * 239 * @see WP_Site_Query::__construct() 240 * 241 * @param string|array $query Array or string of WP_Site_Query arguments. See WP_Site_Query::__construct(). 242 */ 243 public function parse_query( $query = '' ) { 244 if ( empty( $query ) ) { 245 $query = $this->query_vars; 246 } 247 248 $this->query_vars = wp_parse_args( $query, $this->query_var_defaults ); 249 250 /** 251 * Fires after the site query vars have been parsed. 252 * 253 * @since 4.6.0 254 * 255 * @param WP_Site_Query $query The WP_Site_Query instance (passed by reference). 256 */ 257 do_action_ref_array( 'parse_site_query', array( &$this ) ); 258 } 259 260 /** 261 * Sets up the WordPress query for retrieving sites. 262 * 263 * @since 4.6.0 264 * 265 * @param string|array $query Array or URL query string of parameters. 266 * @return WP_Site[]|int[]|int List of WP_Site objects, a list of site IDs when 'fields' is set to 'ids', 267 * or the number of sites when 'count' is passed as a query var. 268 */ 269 public function query( $query ) { 270 $this->query_vars = wp_parse_args( $query ); 271 272 return $this->get_sites(); 273 } 274 275 /** 276 * Retrieves a list of sites matching the query vars. 277 * 278 * @since 4.6.0 279 * 280 * @global wpdb $wpdb WordPress database abstraction object. 281 * 282 * @return WP_Site[]|int[]|int List of WP_Site objects, a list of site IDs when 'fields' is set to 'ids', 283 * or the number of sites when 'count' is passed as a query var. 284 */ 285 public function get_sites() { 286 global $wpdb; 287 288 $this->parse_query(); 289 290 // Parse meta query. 291 $this->meta_query = new WP_Meta_Query(); 292 $this->meta_query->parse_query_vars( $this->query_vars ); 293 294 /** 295 * Fires before sites are retrieved. 296 * 297 * @since 4.6.0 298 * 299 * @param WP_Site_Query $query Current instance of WP_Site_Query (passed by reference). 300 */ 301 do_action_ref_array( 'pre_get_sites', array( &$this ) ); 302 303 // Reparse query vars, in case they were modified in a 'pre_get_sites' callback. 304 $this->meta_query->parse_query_vars( $this->query_vars ); 305 if ( ! empty( $this->meta_query->queries ) ) { 306 $this->meta_query_clauses = $this->meta_query->get_sql( 'blog', $wpdb->blogs, 'blog_id', $this ); 307 } 308 309 $site_data = null; 310 311 /** 312 * Filters the site data before the get_sites query takes place. 313 * 314 * Return a non-null value to bypass WordPress' default site queries. 315 * 316 * The expected return type from this filter depends on the value passed 317 * in the request query vars: 318 * - When `$this->query_vars['count']` is set, the filter should return 319 * the site count as an integer. 320 * - When `'ids' === $this->query_vars['fields']`, the filter should return 321 * an array of site IDs. 322 * - Otherwise the filter should return an array of WP_Site objects. 323 * 324 * Note that if the filter returns an array of site data, it will be assigned 325 * to the `sites` property of the current WP_Site_Query instance. 326 * 327 * Filtering functions that require pagination information are encouraged to set 328 * the `found_sites` and `max_num_pages` properties of the WP_Site_Query object, 329 * passed to the filter by reference. If WP_Site_Query does not perform a database 330 * query, it will not have enough information to generate these values itself. 331 * 332 * @since 5.2.0 333 * @since 5.6.0 The returned array of site data is assigned to the `sites` property 334 * of the current WP_Site_Query instance. 335 * 336 * @param WP_Site[]|int[]|int|null $site_data Return an array of site data to short-circuit WP's site query, 337 * the site count as an integer if `$this->query_vars['count']` is set, 338 * or null to run the normal queries. 339 * @param WP_Site_Query $query The WP_Site_Query instance, passed by reference. 340 */ 341 $site_data = apply_filters_ref_array( 'sites_pre_query', array( $site_data, &$this ) ); 342 343 if ( null !== $site_data ) { 344 if ( is_array( $site_data ) && ! $this->query_vars['count'] ) { 345 $this->sites = $site_data; 346 } 347 348 return $site_data; 349 } 350 351 // $args can include anything. Only use the args defined in the query_var_defaults to compute the key. 352 $_args = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ); 353 354 // Ignore the $fields, $update_site_cache, $update_site_meta_cache argument as the queried result will be the same regardless. 355 unset( $_args['fields'], $_args['update_site_cache'], $_args['update_site_meta_cache'] ); 356 357 $key = md5( serialize( $_args ) ); 358 $last_changed = wp_cache_get_last_changed( 'sites' ); 359 360 $cache_key = "get_sites:$key:$last_changed"; 361 $cache_value = wp_cache_get( $cache_key, 'site-queries' ); 362 363 if ( false === $cache_value ) { 364 $site_ids = $this->get_site_ids(); 365 if ( $site_ids ) { 366 $this->set_found_sites(); 367 } 368 369 $cache_value = array( 370 'site_ids' => $site_ids, 371 'found_sites' => $this->found_sites, 372 ); 373 wp_cache_add( $cache_key, $cache_value, 'site-queries' ); 374 } else { 375 $site_ids = $cache_value['site_ids']; 376 $this->found_sites = $cache_value['found_sites']; 377 } 378 379 if ( $this->found_sites && $this->query_vars['number'] ) { 380 $this->max_num_pages = (int) ceil( $this->found_sites / $this->query_vars['number'] ); 381 } 382 383 // If querying for a count only, there's nothing more to do. 384 if ( $this->query_vars['count'] ) { 385 // $site_ids is actually a count in this case. 386 return (int) $site_ids; 387 } 388 389 $site_ids = array_map( 'intval', $site_ids ); 390 391 if ( $this->query_vars['update_site_meta_cache'] ) { 392 wp_lazyload_site_meta( $site_ids ); 393 } 394 395 if ( 'ids' === $this->query_vars['fields'] ) { 396 $this->sites = $site_ids; 397 398 return $this->sites; 399 } 400 401 // Prime site network caches. 402 if ( $this->query_vars['update_site_cache'] ) { 403 _prime_site_caches( $site_ids, false ); 404 } 405 406 // Fetch full site objects from the primed cache. 407 $_sites = array(); 408 foreach ( $site_ids as $site_id ) { 409 $_site = get_site( $site_id ); 410 if ( $_site ) { 411 $_sites[] = $_site; 412 } 413 } 414 415 /** 416 * Filters the site query results. 417 * 418 * @since 4.6.0 419 * 420 * @param WP_Site[] $_sites An array of WP_Site objects. 421 * @param WP_Site_Query $query Current instance of WP_Site_Query (passed by reference). 422 */ 423 $_sites = apply_filters_ref_array( 'the_sites', array( $_sites, &$this ) ); 424 425 // Convert to WP_Site instances. 426 $this->sites = array_map( 'get_site', $_sites ); 427 428 return $this->sites; 429 } 430 431 /** 432 * Used internally to get a list of site IDs matching the query vars. 433 * 434 * @since 4.6.0 435 * 436 * @global wpdb $wpdb WordPress database abstraction object. 437 * 438 * @return int|array A single count of site IDs if a count query. An array of site IDs if a full query. 439 */ 440 protected function get_site_ids() { 441 global $wpdb; 442 443 $order = $this->parse_order( $this->query_vars['order'] ); 444 445 // Disable ORDER BY with 'none', an empty array, or boolean false. 446 if ( in_array( $this->query_vars['orderby'], array( 'none', array(), false ), true ) ) { 447 $orderby = ''; 448 } elseif ( ! empty( $this->query_vars['orderby'] ) ) { 449 $ordersby = is_array( $this->query_vars['orderby'] ) ? 450 $this->query_vars['orderby'] : 451 preg_split( '/[,\s]/', $this->query_vars['orderby'] ); 452 453 $orderby_array = array(); 454 foreach ( $ordersby as $_key => $_value ) { 455 if ( ! $_value ) { 456 continue; 457 } 458 459 if ( is_int( $_key ) ) { 460 $_orderby = $_value; 461 $_order = $order; 462 } else { 463 $_orderby = $_key; 464 $_order = $_value; 465 } 466 467 $parsed = $this->parse_orderby( $_orderby ); 468 469 if ( ! $parsed ) { 470 continue; 471 } 472 473 if ( 'site__in' === $_orderby || 'network__in' === $_orderby ) { 474 $orderby_array[] = $parsed; 475 continue; 476 } 477 478 $orderby_array[] = $parsed . ' ' . $this->parse_order( $_order ); 479 } 480 481 $orderby = implode( ', ', $orderby_array ); 482 } else { 483 $orderby = "{$wpdb->blogs}.blog_id $order"; 484 } 485 486 $number = absint( $this->query_vars['number'] ); 487 $offset = absint( $this->query_vars['offset'] ); 488 $limits = ''; 489 490 if ( ! empty( $number ) ) { 491 if ( $offset ) { 492 $limits = 'LIMIT ' . $offset . ',' . $number; 493 } else { 494 $limits = 'LIMIT ' . $number; 495 } 496 } 497 498 if ( $this->query_vars['count'] ) { 499 $fields = 'COUNT(*)'; 500 } else { 501 $fields = "{$wpdb->blogs}.blog_id"; 502 } 503 504 // Parse site IDs for an IN clause. 505 $site_id = absint( $this->query_vars['ID'] ); 506 if ( ! empty( $site_id ) ) { 507 $this->sql_clauses['where']['ID'] = $wpdb->prepare( "{$wpdb->blogs}.blog_id = %d", $site_id ); 508 } 509 510 // Parse site IDs for an IN clause. 511 if ( ! empty( $this->query_vars['site__in'] ) ) { 512 $this->sql_clauses['where']['site__in'] = "{$wpdb->blogs}.blog_id IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__in'] ) ) . ' )'; 513 } 514 515 // Parse site IDs for a NOT IN clause. 516 if ( ! empty( $this->query_vars['site__not_in'] ) ) { 517 $this->sql_clauses['where']['site__not_in'] = "{$wpdb->blogs}.blog_id NOT IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__not_in'] ) ) . ' )'; 518 } 519 520 $network_id = absint( $this->query_vars['network_id'] ); 521 522 if ( ! empty( $network_id ) ) { 523 $this->sql_clauses['where']['network_id'] = $wpdb->prepare( 'site_id = %d', $network_id ); 524 } 525 526 // Parse site network IDs for an IN clause. 527 if ( ! empty( $this->query_vars['network__in'] ) ) { 528 $this->sql_clauses['where']['network__in'] = 'site_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['network__in'] ) ) . ' )'; 529 } 530 531 // Parse site network IDs for a NOT IN clause. 532 if ( ! empty( $this->query_vars['network__not_in'] ) ) { 533 $this->sql_clauses['where']['network__not_in'] = 'site_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['network__not_in'] ) ) . ' )'; 534 } 535 536 if ( ! empty( $this->query_vars['domain'] ) ) { 537 $this->sql_clauses['where']['domain'] = $wpdb->prepare( 'domain = %s', $this->query_vars['domain'] ); 538 } 539 540 // Parse site domain for an IN clause. 541 if ( is_array( $this->query_vars['domain__in'] ) ) { 542 $this->sql_clauses['where']['domain__in'] = "domain IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['domain__in'] ) ) . "' )"; 543 } 544 545 // Parse site domain for a NOT IN clause. 546 if ( is_array( $this->query_vars['domain__not_in'] ) ) { 547 $this->sql_clauses['where']['domain__not_in'] = "domain NOT IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['domain__not_in'] ) ) . "' )"; 548 } 549 550 if ( ! empty( $this->query_vars['path'] ) ) { 551 $this->sql_clauses['where']['path'] = $wpdb->prepare( 'path = %s', $this->query_vars['path'] ); 552 } 553 554 // Parse site path for an IN clause. 555 if ( is_array( $this->query_vars['path__in'] ) ) { 556 $this->sql_clauses['where']['path__in'] = "path IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['path__in'] ) ) . "' )"; 557 } 558 559 // Parse site path for a NOT IN clause. 560 if ( is_array( $this->query_vars['path__not_in'] ) ) { 561 $this->sql_clauses['where']['path__not_in'] = "path NOT IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['path__not_in'] ) ) . "' )"; 562 } 563 564 if ( is_numeric( $this->query_vars['archived'] ) ) { 565 $archived = absint( $this->query_vars['archived'] ); 566 $this->sql_clauses['where']['archived'] = $wpdb->prepare( 'archived = %s ', absint( $archived ) ); 567 } 568 569 if ( is_numeric( $this->query_vars['mature'] ) ) { 570 $mature = absint( $this->query_vars['mature'] ); 571 $this->sql_clauses['where']['mature'] = $wpdb->prepare( 'mature = %d ', $mature ); 572 } 573 574 if ( is_numeric( $this->query_vars['spam'] ) ) { 575 $spam = absint( $this->query_vars['spam'] ); 576 $this->sql_clauses['where']['spam'] = $wpdb->prepare( 'spam = %d ', $spam ); 577 } 578 579 if ( is_numeric( $this->query_vars['deleted'] ) ) { 580 $deleted = absint( $this->query_vars['deleted'] ); 581 $this->sql_clauses['where']['deleted'] = $wpdb->prepare( 'deleted = %d ', $deleted ); 582 } 583 584 if ( is_numeric( $this->query_vars['public'] ) ) { 585 $public = absint( $this->query_vars['public'] ); 586 $this->sql_clauses['where']['public'] = $wpdb->prepare( 'public = %d ', $public ); 587 } 588 589 if ( is_numeric( $this->query_vars['lang_id'] ) ) { 590 $lang_id = absint( $this->query_vars['lang_id'] ); 591 $this->sql_clauses['where']['lang_id'] = $wpdb->prepare( 'lang_id = %d ', $lang_id ); 592 } 593 594 // Parse site language IDs for an IN clause. 595 if ( ! empty( $this->query_vars['lang__in'] ) ) { 596 $this->sql_clauses['where']['lang__in'] = 'lang_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['lang__in'] ) ) . ' )'; 597 } 598 599 // Parse site language IDs for a NOT IN clause. 600 if ( ! empty( $this->query_vars['lang__not_in'] ) ) { 601 $this->sql_clauses['where']['lang__not_in'] = 'lang_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['lang__not_in'] ) ) . ' )'; 602 } 603 604 // Falsey search strings are ignored. 605 if ( strlen( $this->query_vars['search'] ) ) { 606 $search_columns = array(); 607 608 if ( $this->query_vars['search_columns'] ) { 609 $search_columns = array_intersect( $this->query_vars['search_columns'], array( 'domain', 'path' ) ); 610 } 611 612 if ( ! $search_columns ) { 613 $search_columns = array( 'domain', 'path' ); 614 } 615 616 /** 617 * Filters the columns to search in a WP_Site_Query search. 618 * 619 * The default columns include 'domain' and 'path. 620 * 621 * @since 4.6.0 622 * 623 * @param string[] $search_columns Array of column names to be searched. 624 * @param string $search Text being searched. 625 * @param WP_Site_Query $query The current WP_Site_Query instance. 626 */ 627 $search_columns = apply_filters( 'site_search_columns', $search_columns, $this->query_vars['search'], $this ); 628 629 $this->sql_clauses['where']['search'] = $this->get_search_sql( $this->query_vars['search'], $search_columns ); 630 } 631 632 $date_query = $this->query_vars['date_query']; 633 if ( ! empty( $date_query ) && is_array( $date_query ) ) { 634 $this->date_query = new WP_Date_Query( $date_query, 'registered' ); 635 636 // Strip leading 'AND'. 637 $this->sql_clauses['where']['date_query'] = preg_replace( '/^\s*AND\s*/', '', $this->date_query->get_sql() ); 638 } 639 640 $join = ''; 641 $groupby = ''; 642 643 if ( ! empty( $this->meta_query_clauses ) ) { 644 $join .= $this->meta_query_clauses['join']; 645 646 // Strip leading 'AND'. 647 $this->sql_clauses['where']['meta_query'] = preg_replace( '/^\s*AND\s*/', '', $this->meta_query_clauses['where'] ); 648 649 if ( ! $this->query_vars['count'] ) { 650 $groupby = "{$wpdb->blogs}.blog_id"; 651 } 652 } 653 654 $where = implode( ' AND ', $this->sql_clauses['where'] ); 655 656 $pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' ); 657 658 /** 659 * Filters the site query clauses. 660 * 661 * @since 4.6.0 662 * 663 * @param string[] $clauses { 664 * Associative array of the clauses for the query. 665 * 666 * @type string $fields The SELECT clause of the query. 667 * @type string $join The JOIN clause of the query. 668 * @type string $where The WHERE clause of the query. 669 * @type string $orderby The ORDER BY clause of the query. 670 * @type string $limits The LIMIT clause of the query. 671 * @type string $groupby The GROUP BY clause of the query. 672 * } 673 * @param WP_Site_Query $query Current instance of WP_Site_Query (passed by reference). 674 */ 675 $clauses = apply_filters_ref_array( 'sites_clauses', array( compact( $pieces ), &$this ) ); 676 677 $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : ''; 678 $join = isset( $clauses['join'] ) ? $clauses['join'] : ''; 679 $where = isset( $clauses['where'] ) ? $clauses['where'] : ''; 680 $orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : ''; 681 $limits = isset( $clauses['limits'] ) ? $clauses['limits'] : ''; 682 $groupby = isset( $clauses['groupby'] ) ? $clauses['groupby'] : ''; 683 684 if ( $where ) { 685 $where = 'WHERE ' . $where; 686 } 687 688 if ( $groupby ) { 689 $groupby = 'GROUP BY ' . $groupby; 690 } 691 692 if ( $orderby ) { 693 $orderby = "ORDER BY $orderby"; 694 } 695 696 $found_rows = ''; 697 if ( ! $this->query_vars['no_found_rows'] ) { 698 $found_rows = 'SQL_CALC_FOUND_ROWS'; 699 } 700 701 $this->sql_clauses['select'] = "SELECT $found_rows $fields"; 702 $this->sql_clauses['from'] = "FROM $wpdb->blogs $join"; 703 $this->sql_clauses['groupby'] = $groupby; 704 $this->sql_clauses['orderby'] = $orderby; 705 $this->sql_clauses['limits'] = $limits; 706 707 // Beginning of the string is on a new line to prevent leading whitespace. See https://core.trac.wordpress.org/ticket/56841. 708 $this->request = 709 "{$this->sql_clauses['select']} 710 {$this->sql_clauses['from']} 711 {$where} 712 {$this->sql_clauses['groupby']} 713 {$this->sql_clauses['orderby']} 714 {$this->sql_clauses['limits']}"; 715 716 if ( $this->query_vars['count'] ) { 717 return (int) $wpdb->get_var( $this->request ); 718 } 719 720 $site_ids = $wpdb->get_col( $this->request ); 721 722 return array_map( 'intval', $site_ids ); 723 } 724 725 /** 726 * Populates found_sites and max_num_pages properties for the current query 727 * if the limit clause was used. 728 * 729 * @since 4.6.0 730 * 731 * @global wpdb $wpdb WordPress database abstraction object. 732 */ 733 private function set_found_sites() { 734 global $wpdb; 735 736 if ( $this->query_vars['number'] && ! $this->query_vars['no_found_rows'] ) { 737 /** 738 * Filters the query used to retrieve found site count. 739 * 740 * @since 4.6.0 741 * 742 * @param string $found_sites_query SQL query. Default 'SELECT FOUND_ROWS()'. 743 * @param WP_Site_Query $site_query The `WP_Site_Query` instance. 744 */ 745 $found_sites_query = apply_filters( 'found_sites_query', 'SELECT FOUND_ROWS()', $this ); 746 747 $this->found_sites = (int) $wpdb->get_var( $found_sites_query ); 748 } 749 } 750 751 /** 752 * Used internally to generate an SQL string for searching across multiple columns. 753 * 754 * @since 4.6.0 755 * 756 * @global wpdb $wpdb WordPress database abstraction object. 757 * 758 * @param string $search Search string. 759 * @param string[] $columns Array of columns to search. 760 * @return string Search SQL. 761 */ 762 protected function get_search_sql( $search, $columns ) { 763 global $wpdb; 764 765 if ( str_contains( $search, '*' ) ) { 766 $like = '%' . implode( '%', array_map( array( $wpdb, 'esc_like' ), explode( '*', $search ) ) ) . '%'; 767 } else { 768 $like = '%' . $wpdb->esc_like( $search ) . '%'; 769 } 770 771 $searches = array(); 772 foreach ( $columns as $column ) { 773 $searches[] = $wpdb->prepare( "$column LIKE %s", $like ); 774 } 775 776 return '(' . implode( ' OR ', $searches ) . ')'; 777 } 778 779 /** 780 * Parses and sanitizes 'orderby' keys passed to the site query. 781 * 782 * @since 4.6.0 783 * 784 * @global wpdb $wpdb WordPress database abstraction object. 785 * 786 * @param string $orderby Alias for the field to order by. 787 * @return string|false Value to used in the ORDER clause. False otherwise. 788 */ 789 protected function parse_orderby( $orderby ) { 790 global $wpdb; 791 792 $parsed = false; 793 794 switch ( $orderby ) { 795 case 'site__in': 796 $site__in = implode( ',', array_map( 'absint', $this->query_vars['site__in'] ) ); 797 $parsed = "FIELD( {$wpdb->blogs}.blog_id, $site__in )"; 798 break; 799 case 'network__in': 800 $network__in = implode( ',', array_map( 'absint', $this->query_vars['network__in'] ) ); 801 $parsed = "FIELD( {$wpdb->blogs}.site_id, $network__in )"; 802 break; 803 case 'domain': 804 case 'last_updated': 805 case 'path': 806 case 'registered': 807 case 'deleted': 808 case 'spam': 809 case 'mature': 810 case 'archived': 811 case 'public': 812 $parsed = $orderby; 813 break; 814 case 'network_id': 815 $parsed = 'site_id'; 816 break; 817 case 'domain_length': 818 $parsed = 'CHAR_LENGTH(domain)'; 819 break; 820 case 'path_length': 821 $parsed = 'CHAR_LENGTH(path)'; 822 break; 823 case 'id': 824 $parsed = "{$wpdb->blogs}.blog_id"; 825 break; 826 } 827 828 if ( ! empty( $parsed ) || empty( $this->meta_query_clauses ) ) { 829 return $parsed; 830 } 831 832 $meta_clauses = $this->meta_query->get_clauses(); 833 if ( empty( $meta_clauses ) ) { 834 return $parsed; 835 } 836 837 $primary_meta_query = reset( $meta_clauses ); 838 if ( ! empty( $primary_meta_query['key'] ) && $primary_meta_query['key'] === $orderby ) { 839 $orderby = 'meta_value'; 840 } 841 842 switch ( $orderby ) { 843 case 'meta_value': 844 if ( ! empty( $primary_meta_query['type'] ) ) { 845 $parsed = "CAST({$primary_meta_query['alias']}.meta_value AS {$primary_meta_query['cast']})"; 846 } else { 847 $parsed = "{$primary_meta_query['alias']}.meta_value"; 848 } 849 break; 850 case 'meta_value_num': 851 $parsed = "{$primary_meta_query['alias']}.meta_value+0"; 852 break; 853 default: 854 if ( isset( $meta_clauses[ $orderby ] ) ) { 855 $meta_clause = $meta_clauses[ $orderby ]; 856 $parsed = "CAST({$meta_clause['alias']}.meta_value AS {$meta_clause['cast']})"; 857 } 858 } 859 860 return $parsed; 861 } 862 863 /** 864 * Parses an 'order' query variable and cast it to 'ASC' or 'DESC' as necessary. 865 * 866 * @since 4.6.0 867 * 868 * @param string $order The 'order' query variable. 869 * @return string The sanitized 'order' query variable. 870 */ 871 protected function parse_order( $order ) { 872 if ( ! is_string( $order ) || empty( $order ) ) { 873 return 'ASC'; 874 } 875 876 if ( 'ASC' === strtoupper( $order ) ) { 877 return 'ASC'; 878 } else { 879 return 'DESC'; 880 } 881 } 882 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |