155 * @type string[] $domain__in Array of domains to include affiliated sites for. Default empty. |
156 * @type string[] $domain__in Array of domains to include affiliated sites for. Default empty. |
156 * @type string[] $domain__not_in Array of domains to exclude affiliated sites for. Default empty. |
157 * @type string[] $domain__not_in Array of domains to exclude affiliated sites for. Default empty. |
157 * @type string $path Limit results to those affiliated with a given path. Default empty. |
158 * @type string $path Limit results to those affiliated with a given path. Default empty. |
158 * @type string[] $path__in Array of paths to include affiliated sites for. Default empty. |
159 * @type string[] $path__in Array of paths to include affiliated sites for. Default empty. |
159 * @type string[] $path__not_in Array of paths to exclude affiliated sites for. Default empty. |
160 * @type string[] $path__not_in Array of paths to exclude affiliated sites for. Default empty. |
160 * @type int $public Limit results to public sites. Accepts '1' or '0'. Default empty. |
161 * @type int $public Limit results to public sites. Accepts 1 or 0. Default empty. |
161 * @type int $archived Limit results to archived sites. Accepts '1' or '0'. Default empty. |
162 * @type int $archived Limit results to archived sites. Accepts 1 or 0. Default empty. |
162 * @type int $mature Limit results to mature sites. Accepts '1' or '0'. Default empty. |
163 * @type int $mature Limit results to mature sites. Accepts 1 or 0. Default empty. |
163 * @type int $spam Limit results to spam sites. Accepts '1' or '0'. Default empty. |
164 * @type int $spam Limit results to spam sites. Accepts 1 or 0. Default empty. |
164 * @type int $deleted Limit results to deleted sites. Accepts '1' or '0'. Default empty. |
165 * @type int $deleted Limit results to deleted sites. Accepts 1 or 0. Default empty. |
165 * @type int $lang_id Limit results to a language ID. Default empty. |
166 * @type int $lang_id Limit results to a language ID. Default empty. |
166 * @type string[] $lang__in Array of language IDs to include affiliated sites for. Default empty. |
167 * @type string[] $lang__in Array of language IDs to include affiliated sites for. Default empty. |
167 * @type string[] $lang__not_in Array of language IDs to exclude affiliated sites for. Default empty. |
168 * @type string[] $lang__not_in Array of language IDs to exclude affiliated sites for. Default empty. |
168 * @type string $search Search term(s) to retrieve matching sites for. Default empty. |
169 * @type string $search Search term(s) to retrieve matching sites for. Default empty. |
169 * @type string[] $search_columns Array of column names to be searched. Accepts 'domain' and 'path'. |
170 * @type string[] $search_columns Array of column names to be searched. Accepts 'domain' and 'path'. |
171 * @type bool $update_site_cache Whether to prime the cache for found sites. Default true. |
172 * @type bool $update_site_cache Whether to prime the cache for found sites. Default true. |
172 * @type bool $update_site_meta_cache Whether to prime the metadata cache for found sites. Default true. |
173 * @type bool $update_site_meta_cache Whether to prime the metadata cache for found sites. Default true. |
173 * @type string|string[] $meta_key Meta key or keys to filter by. |
174 * @type string|string[] $meta_key Meta key or keys to filter by. |
174 * @type string|string[] $meta_value Meta value or values to filter by. |
175 * @type string|string[] $meta_value Meta value or values to filter by. |
175 * @type string $meta_compare MySQL operator used for comparing the meta value. |
176 * @type string $meta_compare MySQL operator used for comparing the meta value. |
176 * See WP_Meta_Query::__construct for accepted values and default value. |
177 * See WP_Meta_Query::__construct() for accepted values and default value. |
177 * @type string $meta_compare_key MySQL operator used for comparing the meta key. |
178 * @type string $meta_compare_key MySQL operator used for comparing the meta key. |
178 * See WP_Meta_Query::__construct for accepted values and default value. |
179 * See WP_Meta_Query::__construct() for accepted values and default value. |
179 * @type string $meta_type MySQL data type that the meta_value column will be CAST to for comparisons. |
180 * @type string $meta_type MySQL data type that the meta_value column will be CAST to for comparisons. |
180 * See WP_Meta_Query::__construct for accepted values and default value. |
181 * See WP_Meta_Query::__construct() for accepted values and default value. |
181 * @type string $meta_type_key MySQL data type that the meta_key column will be CAST to for comparisons. |
182 * @type string $meta_type_key MySQL data type that the meta_key column will be CAST to for comparisons. |
182 * See WP_Meta_Query::__construct for accepted values and default value. |
183 * See WP_Meta_Query::__construct() for accepted values and default value. |
183 * @type array $meta_query An associative array of WP_Meta_Query arguments. |
184 * @type array $meta_query An associative array of WP_Meta_Query arguments. |
184 * See WP_Meta_Query::__construct for accepted values. |
185 * See WP_Meta_Query::__construct() for accepted values. |
185 * } |
186 * } |
186 */ |
187 */ |
187 public function __construct( $query = '' ) { |
188 public function __construct( $query = '' ) { |
188 $this->query_var_defaults = array( |
189 $this->query_var_defaults = array( |
189 'fields' => '', |
190 'fields' => '', |
355 |
356 |
356 $key = md5( serialize( $_args ) ); |
357 $key = md5( serialize( $_args ) ); |
357 $last_changed = wp_cache_get_last_changed( 'sites' ); |
358 $last_changed = wp_cache_get_last_changed( 'sites' ); |
358 |
359 |
359 $cache_key = "get_sites:$key:$last_changed"; |
360 $cache_key = "get_sites:$key:$last_changed"; |
360 $cache_value = wp_cache_get( $cache_key, 'sites' ); |
361 $cache_value = wp_cache_get( $cache_key, 'site-queries' ); |
361 |
362 |
362 if ( false === $cache_value ) { |
363 if ( false === $cache_value ) { |
363 $site_ids = $this->get_site_ids(); |
364 $site_ids = $this->get_site_ids(); |
364 if ( $site_ids ) { |
365 if ( $site_ids ) { |
365 $this->set_found_sites(); |
366 $this->set_found_sites(); |
367 |
368 |
368 $cache_value = array( |
369 $cache_value = array( |
369 'site_ids' => $site_ids, |
370 'site_ids' => $site_ids, |
370 'found_sites' => $this->found_sites, |
371 'found_sites' => $this->found_sites, |
371 ); |
372 ); |
372 wp_cache_add( $cache_key, $cache_value, 'sites' ); |
373 wp_cache_add( $cache_key, $cache_value, 'site-queries' ); |
373 } else { |
374 } else { |
374 $site_ids = $cache_value['site_ids']; |
375 $site_ids = $cache_value['site_ids']; |
375 $this->found_sites = $cache_value['found_sites']; |
376 $this->found_sites = $cache_value['found_sites']; |
376 } |
377 } |
377 |
378 |
378 if ( $this->found_sites && $this->query_vars['number'] ) { |
379 if ( $this->found_sites && $this->query_vars['number'] ) { |
379 $this->max_num_pages = ceil( $this->found_sites / $this->query_vars['number'] ); |
380 $this->max_num_pages = (int) ceil( $this->found_sites / $this->query_vars['number'] ); |
380 } |
381 } |
381 |
382 |
382 // If querying for a count only, there's nothing more to do. |
383 // If querying for a count only, there's nothing more to do. |
383 if ( $this->query_vars['count'] ) { |
384 if ( $this->query_vars['count'] ) { |
384 // $site_ids is actually a count in this case. |
385 // $site_ids is actually a count in this case. |
385 return (int) $site_ids; |
386 return (int) $site_ids; |
386 } |
387 } |
387 |
388 |
388 $site_ids = array_map( 'intval', $site_ids ); |
389 $site_ids = array_map( 'intval', $site_ids ); |
389 |
390 |
|
391 if ( $this->query_vars['update_site_meta_cache'] ) { |
|
392 wp_lazyload_site_meta( $site_ids ); |
|
393 } |
|
394 |
390 if ( 'ids' === $this->query_vars['fields'] ) { |
395 if ( 'ids' === $this->query_vars['fields'] ) { |
391 $this->sites = $site_ids; |
396 $this->sites = $site_ids; |
392 |
397 |
393 return $this->sites; |
398 return $this->sites; |
394 } |
399 } |
395 |
400 |
396 // Prime site network caches. |
401 // Prime site network caches. |
397 if ( $this->query_vars['update_site_cache'] ) { |
402 if ( $this->query_vars['update_site_cache'] ) { |
398 _prime_site_caches( $site_ids, $this->query_vars['update_site_meta_cache'] ); |
403 _prime_site_caches( $site_ids, false ); |
399 } |
404 } |
400 |
405 |
401 // Fetch full site objects from the primed cache. |
406 // Fetch full site objects from the primed cache. |
402 $_sites = array(); |
407 $_sites = array(); |
403 foreach ( $site_ids as $site_id ) { |
408 foreach ( $site_ids as $site_id ) { |
624 $this->sql_clauses['where']['search'] = $this->get_search_sql( $this->query_vars['search'], $search_columns ); |
629 $this->sql_clauses['where']['search'] = $this->get_search_sql( $this->query_vars['search'], $search_columns ); |
625 } |
630 } |
626 |
631 |
627 $date_query = $this->query_vars['date_query']; |
632 $date_query = $this->query_vars['date_query']; |
628 if ( ! empty( $date_query ) && is_array( $date_query ) ) { |
633 if ( ! empty( $date_query ) && is_array( $date_query ) ) { |
629 $this->date_query = new WP_Date_Query( $date_query, 'registered' ); |
634 $this->date_query = new WP_Date_Query( $date_query, 'registered' ); |
|
635 |
|
636 // Strip leading 'AND'. |
630 $this->sql_clauses['where']['date_query'] = preg_replace( '/^\s*AND\s*/', '', $this->date_query->get_sql() ); |
637 $this->sql_clauses['where']['date_query'] = preg_replace( '/^\s*AND\s*/', '', $this->date_query->get_sql() ); |
631 } |
638 } |
632 |
639 |
633 $join = ''; |
640 $join = ''; |
634 $groupby = ''; |
641 $groupby = ''; |
644 } |
651 } |
645 } |
652 } |
646 |
653 |
647 $where = implode( ' AND ', $this->sql_clauses['where'] ); |
654 $where = implode( ' AND ', $this->sql_clauses['where'] ); |
648 |
655 |
649 $clauses = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' ); |
656 $pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' ); |
650 |
657 |
651 /** |
658 /** |
652 * Filters the site query clauses. |
659 * Filters the site query clauses. |
653 * |
660 * |
654 * @since 4.6.0 |
661 * @since 4.6.0 |
655 * |
662 * |
656 * @param string[] $clauses An associative array of site query clauses. |
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 * } |
657 * @param WP_Site_Query $query Current instance of WP_Site_Query (passed by reference). |
673 * @param WP_Site_Query $query Current instance of WP_Site_Query (passed by reference). |
658 */ |
674 */ |
659 $clauses = apply_filters_ref_array( 'sites_clauses', array( compact( $clauses ), &$this ) ); |
675 $clauses = apply_filters_ref_array( 'sites_clauses', array( compact( $pieces ), &$this ) ); |
660 |
676 |
661 $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : ''; |
677 $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : ''; |
662 $join = isset( $clauses['join'] ) ? $clauses['join'] : ''; |
678 $join = isset( $clauses['join'] ) ? $clauses['join'] : ''; |
663 $where = isset( $clauses['where'] ) ? $clauses['where'] : ''; |
679 $where = isset( $clauses['where'] ) ? $clauses['where'] : ''; |
664 $orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : ''; |
680 $orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : ''; |
686 $this->sql_clauses['from'] = "FROM $wpdb->blogs $join"; |
702 $this->sql_clauses['from'] = "FROM $wpdb->blogs $join"; |
687 $this->sql_clauses['groupby'] = $groupby; |
703 $this->sql_clauses['groupby'] = $groupby; |
688 $this->sql_clauses['orderby'] = $orderby; |
704 $this->sql_clauses['orderby'] = $orderby; |
689 $this->sql_clauses['limits'] = $limits; |
705 $this->sql_clauses['limits'] = $limits; |
690 |
706 |
691 $this->request = " |
707 // Beginning of the string is on a new line to prevent leading whitespace. See https://core.trac.wordpress.org/ticket/56841. |
692 {$this->sql_clauses['select']} |
708 $this->request = |
693 {$this->sql_clauses['from']} |
709 "{$this->sql_clauses['select']} |
694 {$where} |
710 {$this->sql_clauses['from']} |
695 {$this->sql_clauses['groupby']} |
711 {$where} |
696 {$this->sql_clauses['orderby']} |
712 {$this->sql_clauses['groupby']} |
697 {$this->sql_clauses['limits']} |
713 {$this->sql_clauses['orderby']} |
698 "; |
714 {$this->sql_clauses['limits']}"; |
699 |
715 |
700 if ( $this->query_vars['count'] ) { |
716 if ( $this->query_vars['count'] ) { |
701 return (int) $wpdb->get_var( $this->request ); |
717 return (int) $wpdb->get_var( $this->request ); |
702 } |
718 } |
703 |
719 |
744 * @return string Search SQL. |
760 * @return string Search SQL. |
745 */ |
761 */ |
746 protected function get_search_sql( $search, $columns ) { |
762 protected function get_search_sql( $search, $columns ) { |
747 global $wpdb; |
763 global $wpdb; |
748 |
764 |
749 if ( false !== strpos( $search, '*' ) ) { |
765 if ( str_contains( $search, '*' ) ) { |
750 $like = '%' . implode( '%', array_map( array( $wpdb, 'esc_like' ), explode( '*', $search ) ) ) . '%'; |
766 $like = '%' . implode( '%', array_map( array( $wpdb, 'esc_like' ), explode( '*', $search ) ) ) . '%'; |
751 } else { |
767 } else { |
752 $like = '%' . $wpdb->esc_like( $search ) . '%'; |
768 $like = '%' . $wpdb->esc_like( $search ) . '%'; |
753 } |
769 } |
754 |
770 |