WP_Site_Query::set_found_sites()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 17
Code Lines 5

Duplication

Lines 17
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 2
nop 0
dl 17
loc 17
rs 9.4285
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
class WP_Site_Query {
18
19
	/**
20
	 * SQL for database query.
21
	 *
22
	 * @since 4.6.0
23
	 * @access public
24
	 * @var string
25
	 */
26
	public $request;
27
28
	/**
29
	 * SQL query clauses.
30
	 *
31
	 * @since 4.6.0
32
	 * @access protected
33
	 * @var array
34
	 */
35
	protected $sql_clauses = array(
36
		'select'  => '',
37
		'from'    => '',
38
		'where'   => array(),
39
		'groupby' => '',
40
		'orderby' => '',
41
		'limits'  => '',
42
	);
43
44
	/**
45
	 * Date query container.
46
	 *
47
	 * @since 4.6.0
48
	 * @access public
49
	 * @var object WP_Date_Query
50
	 */
51
	public $date_query = false;
52
53
	/**
54
	 * Query vars set by the user.
55
	 *
56
	 * @since 4.6.0
57
	 * @access public
58
	 * @var array
59
	 */
60
	public $query_vars;
61
62
	/**
63
	 * Default values for query vars.
64
	 *
65
	 * @since 4.6.0
66
	 * @access public
67
	 * @var array
68
	 */
69
	public $query_var_defaults;
70
71
	/**
72
	 * List of sites located by the query.
73
	 *
74
	 * @since 4.6.0
75
	 * @access public
76
	 * @var array
77
	 */
78
	public $sites;
79
80
	/**
81
	 * The amount of found sites for the current query.
82
	 *
83
	 * @since 4.6.0
84
	 * @access public
85
	 * @var int
86
	 */
87
	public $found_sites = 0;
88
89
	/**
90
	 * The number of pages.
91
	 *
92
	 * @since 4.6.0
93
	 * @access public
94
	 * @var int
95
	 */
96
	public $max_num_pages = 0;
97
98
	/**
99
	 * Sets up the site query, based on the query vars passed.
100
	 *
101
	 * @since 4.6.0
102
	 * @since 4.8.0 Introduced the 'lang_id', 'lang__in', and 'lang__not_in' parameters.
103
	 * @access public
104
	 *
105
	 * @param string|array $query {
106
	 *     Optional. Array or query string of site query parameters. Default empty.
107
	 *
108
	 *     @type array        $site__in          Array of site IDs to include. Default empty.
109
	 *     @type array        $site__not_in      Array of site IDs to exclude. Default empty.
110
	 *     @type bool         $count             Whether to return a site count (true) or array of site objects.
111
	 *                                           Default false.
112
	 *     @type array        $date_query        Date query clauses to limit sites by. See WP_Date_Query.
113
	 *                                           Default null.
114
	 *     @type string       $fields            Site fields to return. Accepts 'ids' (returns an array of site IDs)
115
	 *                                           or empty (returns an array of complete site objects). Default empty.
116
	 *     @type int          $ID                A site ID to only return that site. Default empty.
117
	 *     @type int          $number            Maximum number of sites to retrieve. Default 100.
118
	 *     @type int          $offset            Number of sites to offset the query. Used to build LIMIT clause.
119
	 *                                           Default 0.
120
	 *     @type bool         $no_found_rows     Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true.
121
	 *     @type string|array $orderby           Site status or array of statuses. Accepts 'id', 'domain', 'path',
122
	 *                                           'network_id', 'last_updated', 'registered', 'domain_length',
123
	 *                                           'path_length', 'site__in' and 'network__in'. Also accepts false,
124
	 *                                           an empty array, or 'none' to disable `ORDER BY` clause.
125
	 *                                           Default 'id'.
126
	 *     @type string       $order             How to order retrieved sites. Accepts 'ASC', 'DESC'. Default 'ASC'.
127
	 *     @type int          $network_id        Limit results to those affiliated with a given network ID. If 0,
128
	 *                                           include all networks. Default 0.
129
	 *     @type array        $network__in       Array of network IDs to include affiliated sites for. Default empty.
130
	 *     @type array        $network__not_in   Array of network IDs to exclude affiliated sites for. Default empty.
131
	 *     @type string       $domain            Limit results to those affiliated with a given domain. Default empty.
132
	 *     @type array        $domain__in        Array of domains to include affiliated sites for. Default empty.
133
	 *     @type array        $domain__not_in    Array of domains to exclude affiliated sites for. Default empty.
134
	 *     @type string       $path              Limit results to those affiliated with a given path. Default empty.
135
	 *     @type array        $path__in          Array of paths to include affiliated sites for. Default empty.
136
	 *     @type array        $path__not_in      Array of paths to exclude affiliated sites for. Default empty.
137
	 *     @type int          $public            Limit results to public sites. Accepts '1' or '0'. Default empty.
138
	 *     @type int          $archived          Limit results to archived sites. Accepts '1' or '0'. Default empty.
139
	 *     @type int          $mature            Limit results to mature sites. Accepts '1' or '0'. Default empty.
140
	 *     @type int          $spam              Limit results to spam sites. Accepts '1' or '0'. Default empty.
141
	 *     @type int          $deleted           Limit results to deleted sites. Accepts '1' or '0'. Default empty.
142
	 *     @type int          $lang_id           Limit results to a language ID. Default empty.
143
	 *     @type array        $lang__in          Array of language IDs to include affiliated sites for. Default empty.
144
	 *     @type array        $lang__not_in      Array of language IDs to exclude affiliated sites for. Default empty.
145
	 *     @type string       $search            Search term(s) to retrieve matching sites for. Default empty.
146
	 *     @type array        $search_columns    Array of column names to be searched. Accepts 'domain' and 'path'.
147
	 *                                           Default empty array.
148
	 *     @type bool         $update_site_cache Whether to prime the cache for found sites. Default false.
149
	 * }
150
	 */
151
	public function __construct( $query = '' ) {
152
		$this->query_var_defaults = array(
153
			'fields'            => '',
154
			'ID'                => '',
155
			'site__in'          => '',
156
			'site__not_in'      => '',
157
			'number'            => 100,
158
			'offset'            => '',
159
			'no_found_rows'     => true,
160
			'orderby'           => 'id',
161
			'order'             => 'ASC',
162
			'network_id'        => 0,
163
			'network__in'       => '',
164
			'network__not_in'   => '',
165
			'domain'            => '',
166
			'domain__in'        => '',
167
			'domain__not_in'    => '',
168
			'path'              => '',
169
			'path__in'          => '',
170
			'path__not_in'      => '',
171
			'public'            => null,
172
			'archived'          => null,
173
			'mature'            => null,
174
			'spam'              => null,
175
			'deleted'           => null,
176
			'lang_id'           => null,
177
			'lang__in'          => '',
178
			'lang__not_in'      => '',
179
			'search'            => '',
180
			'search_columns'    => array(),
181
			'count'             => false,
182
			'date_query'        => null, // See WP_Date_Query
183
			'update_site_cache' => true,
184
		);
185
186
		if ( ! empty( $query ) ) {
187
			$this->query( $query );
188
		}
189
	}
190
191
	/**
192
	 * Parses arguments passed to the site query with default query parameters.
193
	 *
194
	 * @since 4.6.0
195
	 * @access public
196
	 *
197
	 * @see WP_Site_Query::__construct()
198
	 *
199
	 * @param string|array $query Array or string of WP_Site_Query arguments. See WP_Site_Query::__construct().
200
	 */
201 View Code Duplication
	public function parse_query( $query = '' ) {
202
		if ( empty( $query ) ) {
203
			$query = $this->query_vars;
204
		}
205
206
		$this->query_vars = wp_parse_args( $query, $this->query_var_defaults );
207
208
		/**
209
		 * Fires after the site query vars have been parsed.
210
		 *
211
		 * @since 4.6.0
212
		 *
213
		 * @param WP_Site_Query &$this The WP_Site_Query instance (passed by reference).
214
		 */
215
		do_action_ref_array( 'parse_site_query', array( &$this ) );
216
	}
217
218
	/**
219
	 * Sets up the WordPress query for retrieving sites.
220
	 *
221
	 * @since 4.6.0
222
	 * @access public
223
	 *
224
	 * @param string|array $query Array or URL query string of parameters.
225
	 * @return array|int List of sites, or number of sites when 'count' is passed as a query var.
226
	 */
227
	public function query( $query ) {
228
		$this->query_vars = wp_parse_args( $query );
229
230
		return $this->get_sites();
231
	}
232
233
	/**
234
	 * Retrieves a list of sites matching the query vars.
235
	 *
236
	 * @since 4.6.0
237
	 * @access public
238
	 *
239
	 * @return array|int List of sites, or number of sites when 'count' is passed as a query var.
240
	 */
241 View Code Duplication
	public function get_sites() {
242
		$this->parse_query();
243
244
		/**
245
		 * Fires before sites are retrieved.
246
		 *
247
		 * @since 4.6.0
248
		 *
249
		 * @param WP_Site_Query &$this Current instance of WP_Site_Query, passed by reference.
250
		 */
251
		do_action_ref_array( 'pre_get_sites', array( &$this ) );
252
253
		// $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
254
		$key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) );
255
		$last_changed = wp_cache_get_last_changed( 'sites' );
256
257
		$cache_key = "get_sites:$key:$last_changed";
258
		$cache_value = wp_cache_get( $cache_key, 'sites' );
259
260
		if ( false === $cache_value ) {
261
			$site_ids = $this->get_site_ids();
262
			if ( $site_ids ) {
263
				$this->set_found_sites();
264
			}
265
266
			$cache_value = array(
267
				'site_ids' => $site_ids,
268
				'found_sites' => $this->found_sites,
269
			);
270
			wp_cache_add( $cache_key, $cache_value, 'sites' );
271
		} else {
272
			$site_ids = $cache_value['site_ids'];
273
			$this->found_sites = $cache_value['found_sites'];
274
		}
275
276
		if ( $this->found_sites && $this->query_vars['number'] ) {
277
			$this->max_num_pages = ceil( $this->found_sites / $this->query_vars['number'] );
0 ignored issues
show
Documentation Bug introduced by
The property $max_num_pages was declared of type integer, but ceil($this->found_sites ...->query_vars['number']) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
278
		}
279
280
		// If querying for a count only, there's nothing more to do.
281
		if ( $this->query_vars['count'] ) {
282
			// $site_ids is actually a count in this case.
283
			return intval( $site_ids );
284
		}
285
286
		$site_ids = array_map( 'intval', $site_ids );
287
288
		if ( 'ids' == $this->query_vars['fields'] ) {
289
			$this->sites = $site_ids;
290
291
			return $this->sites;
292
		}
293
294
		// Prime site network caches.
295
		if ( $this->query_vars['update_site_cache'] ) {
296
			_prime_site_caches( $site_ids );
297
		}
298
299
		// Fetch full site objects from the primed cache.
300
		$_sites = array();
301
		foreach ( $site_ids as $site_id ) {
302
			if ( $_site = get_site( $site_id ) ) {
303
				$_sites[] = $_site;
304
			}
305
		}
306
307
		/**
308
		 * Filters the site query results.
309
		 *
310
		 * @since 4.6.0
311
		 *
312
		 * @param array         $results An array of sites.
313
		 * @param WP_Site_Query &$this   Current instance of WP_Site_Query, passed by reference.
314
		 */
315
		$_sites = apply_filters_ref_array( 'the_sites', array( $_sites, &$this ) );
316
317
		// Convert to WP_Site instances.
318
		$this->sites = array_map( 'get_site', $_sites );
319
320
		return $this->sites;
321
	}
322
323
	/**
324
	 * Used internally to get a list of site IDs matching the query vars.
325
	 *
326
	 * @since 4.6.0
327
	 * @access protected
328
	 *
329
	 * @global wpdb $wpdb WordPress database abstraction object.
330
	 *
331
	 * @return int|array A single count of site IDs if a count query. An array of site IDs if a full query.
332
	 */
333
	protected function get_site_ids() {
334
		global $wpdb;
335
336
		$order = $this->parse_order( $this->query_vars['order'] );
337
338
		// Disable ORDER BY with 'none', an empty array, or boolean false.
339 View Code Duplication
		if ( in_array( $this->query_vars['orderby'], array( 'none', array(), false ), true ) ) {
340
			$orderby = '';
341
		} elseif ( ! empty( $this->query_vars['orderby'] ) ) {
342
			$ordersby = is_array( $this->query_vars['orderby'] ) ?
343
				$this->query_vars['orderby'] :
344
				preg_split( '/[,\s]/', $this->query_vars['orderby'] );
345
346
			$orderby_array = array();
347
			foreach ( $ordersby as $_key => $_value ) {
348
				if ( ! $_value ) {
349
					continue;
350
				}
351
352
				if ( is_int( $_key ) ) {
353
					$_orderby = $_value;
354
					$_order = $order;
355
				} else {
356
					$_orderby = $_key;
357
					$_order = $_value;
358
				}
359
360
				$parsed = $this->parse_orderby( $_orderby );
361
362
				if ( ! $parsed ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parsed of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
363
					continue;
364
				}
365
366
				if ( 'site__in' === $_orderby || 'network__in' === $_orderby ) {
367
					$orderby_array[] = $parsed;
368
					continue;
369
				}
370
371
				$orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
372
			}
373
374
			$orderby = implode( ', ', $orderby_array );
375
		} else {
376
			$orderby = "blog_id $order";
377
		}
378
379
		$number = absint( $this->query_vars['number'] );
380
		$offset = absint( $this->query_vars['offset'] );
381
382 View Code Duplication
		if ( ! empty( $number ) ) {
383
			if ( $offset ) {
384
				$limits = 'LIMIT ' . $offset . ',' . $number;
385
			} else {
386
				$limits = 'LIMIT ' . $number;
387
			}
388
		}
389
390
		if ( $this->query_vars['count'] ) {
391
			$fields = 'COUNT(*)';
392
		} else {
393
			$fields = 'blog_id';
394
		}
395
396
		// Parse site IDs for an IN clause.
397
		$site_id = absint( $this->query_vars['ID'] );
398
		if ( ! empty( $site_id ) ) {
399
			$this->sql_clauses['where']['ID'] = $wpdb->prepare( 'blog_id = %d', $site_id );
400
		}
401
402
		// Parse site IDs for an IN clause.
403
		if ( ! empty( $this->query_vars['site__in'] ) ) {
404
			$this->sql_clauses['where']['site__in'] = "blog_id IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__in'] ) ) . ' )';
405
		}
406
407
		// Parse site IDs for a NOT IN clause.
408
		if ( ! empty( $this->query_vars['site__not_in'] ) ) {
409
			$this->sql_clauses['where']['site__not_in'] = "blog_id NOT IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__not_in'] ) ) . ' )';
410
		}
411
412
		$network_id = absint( $this->query_vars['network_id'] );
413
414
		if ( ! empty( $network_id ) ) {
415
			$this->sql_clauses['where']['network_id'] = $wpdb->prepare( 'site_id = %d', $network_id );
416
		}
417
418
		// Parse site network IDs for an IN clause.
419
		if ( ! empty( $this->query_vars['network__in'] ) ) {
420
			$this->sql_clauses['where']['network__in'] = 'site_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['network__in'] ) ) . ' )';
421
		}
422
423
		// Parse site network IDs for a NOT IN clause.
424
		if ( ! empty( $this->query_vars['network__not_in'] ) ) {
425
			$this->sql_clauses['where']['network__not_in'] = 'site_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['network__not_in'] ) ) . ' )';
426
		}
427
428 View Code Duplication
		if ( ! empty( $this->query_vars['domain'] ) ) {
429
			$this->sql_clauses['where']['domain'] = $wpdb->prepare( 'domain = %s', $this->query_vars['domain'] );
430
		}
431
432
		// Parse site domain for an IN clause.
433
		if ( is_array( $this->query_vars['domain__in'] ) ) {
434
			$this->sql_clauses['where']['domain__in'] = "domain IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['domain__in'] ) ) . "' )";
435
		}
436
437
		// Parse site domain for a NOT IN clause.
438
		if ( is_array( $this->query_vars['domain__not_in'] ) ) {
439
			$this->sql_clauses['where']['domain__not_in'] = "domain NOT IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['domain__not_in'] ) ) . "' )";
440
		}
441
442 View Code Duplication
		if ( ! empty( $this->query_vars['path'] ) ) {
443
			$this->sql_clauses['where']['path'] = $wpdb->prepare( 'path = %s', $this->query_vars['path'] );
444
		}
445
446
		// Parse site path for an IN clause.
447
		if ( is_array( $this->query_vars['path__in'] ) ) {
448
			$this->sql_clauses['where']['path__in'] = "path IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['path__in'] ) ) . "' )";
449
		}
450
451
		// Parse site path for a NOT IN clause.
452
		if ( is_array( $this->query_vars['path__not_in'] ) ) {
453
			$this->sql_clauses['where']['path__not_in'] = "path NOT IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['path__not_in'] ) ) . "' )";
454
		}
455
456 View Code Duplication
		if ( is_numeric( $this->query_vars['archived'] ) ) {
457
			$archived = absint( $this->query_vars['archived'] );
458
			$this->sql_clauses['where']['archived'] = $wpdb->prepare( "archived = %d ", $archived );
459
		}
460
461 View Code Duplication
		if ( is_numeric( $this->query_vars['mature'] ) ) {
462
			$mature = absint( $this->query_vars['mature'] );
463
			$this->sql_clauses['where']['mature'] = $wpdb->prepare( "mature = %d ", $mature );
464
		}
465
466 View Code Duplication
		if ( is_numeric( $this->query_vars['spam'] ) ) {
467
			$spam = absint( $this->query_vars['spam'] );
468
			$this->sql_clauses['where']['spam'] = $wpdb->prepare( "spam = %d ", $spam );
469
		}
470
471 View Code Duplication
		if ( is_numeric( $this->query_vars['deleted'] ) ) {
472
			$deleted = absint( $this->query_vars['deleted'] );
473
			$this->sql_clauses['where']['deleted'] = $wpdb->prepare( "deleted = %d ", $deleted );
474
		}
475
476 View Code Duplication
		if ( is_numeric( $this->query_vars['public'] ) ) {
477
			$public = absint( $this->query_vars['public'] );
478
			$this->sql_clauses['where']['public'] = $wpdb->prepare( "public = %d ", $public );
479
		}
480
481 View Code Duplication
		if ( is_numeric( $this->query_vars['lang_id'] ) ) {
482
			$lang_id = absint( $this->query_vars['lang_id'] );
483
			$this->sql_clauses['where']['lang_id'] = $wpdb->prepare( "lang_id = %d ", $lang_id );
484
		}
485
486
		// Parse site language IDs for an IN clause.
487
		if ( ! empty( $this->query_vars['lang__in'] ) ) {
488
			$this->sql_clauses['where']['lang__in'] = 'lang_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['lang__in'] ) ) . ' )';
489
		}
490
491
		// Parse site language IDs for a NOT IN clause.
492
		if ( ! empty( $this->query_vars['lang__not_in'] ) ) {
493
			$this->sql_clauses['where']['lang__not_in'] = 'lang_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['lang__not_in'] ) ) . ' )';
494
		}
495
496
		// Falsey search strings are ignored.
497
		if ( strlen( $this->query_vars['search'] ) ) {
498
			$search_columns = array();
499
500
			if ( $this->query_vars['search_columns'] ) {
501
				$search_columns = array_intersect( $this->query_vars['search_columns'], array( 'domain', 'path' ) );
502
			}
503
504
			if ( ! $search_columns ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $search_columns of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
505
				$search_columns = array( 'domain', 'path' );
506
			}
507
508
			/**
509
			 * Filters the columns to search in a WP_Site_Query search.
510
			 *
511
			 * The default columns include 'domain' and 'path.
512
			 *
513
			 * @since 4.6.0
514
			 *
515
			 * @param array         $search_columns Array of column names to be searched.
516
			 * @param string        $search         Text being searched.
517
			 * @param WP_Site_Query $this           The current WP_Site_Query instance.
518
			 */
519
			$search_columns = apply_filters( 'site_search_columns', $search_columns, $this->query_vars['search'], $this );
520
521
			$this->sql_clauses['where']['search'] = $this->get_search_sql( $this->query_vars['search'], $search_columns );
522
		}
523
524
		$date_query = $this->query_vars['date_query'];
525
		if ( ! empty( $date_query ) && is_array( $date_query ) ) {
526
			$this->date_query = new WP_Date_Query( $date_query, 'registered' );
527
			$this->sql_clauses['where']['date_query'] = preg_replace( '/^\s*AND\s*/', '', $this->date_query->get_sql() );
528
		}
529
530
		$join = '';
531
532
		$where = implode( ' AND ', $this->sql_clauses['where'] );
533
534
		$pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' );
535
536
		/**
537
		 * Filters the site query clauses.
538
		 *
539
		 * @since 4.6.0
540
		 *
541
		 * @param array $pieces A compacted array of site query clauses.
542
		 * @param WP_Site_Query &$this Current instance of WP_Site_Query, passed by reference.
543
		 */
544
		$clauses = apply_filters_ref_array( 'sites_clauses', array( compact( $pieces ), &$this ) );
545
546
		$fields = isset( $clauses['fields'] ) ? $clauses['fields'] : '';
547
		$join = isset( $clauses['join'] ) ? $clauses['join'] : '';
548
		$where = isset( $clauses['where'] ) ? $clauses['where'] : '';
549
		$orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : '';
550
		$limits = isset( $clauses['limits'] ) ? $clauses['limits'] : '';
551
		$groupby = isset( $clauses['groupby'] ) ? $clauses['groupby'] : '';
552
553
		if ( $where ) {
554
			$where = 'WHERE ' . $where;
555
		}
556
557
		if ( $groupby ) {
558
			$groupby = 'GROUP BY ' . $groupby;
559
		}
560
561
		if ( $orderby ) {
562
			$orderby = "ORDER BY $orderby";
563
		}
564
565
		$found_rows = '';
566
		if ( ! $this->query_vars['no_found_rows'] ) {
567
			$found_rows = 'SQL_CALC_FOUND_ROWS';
568
		}
569
570
		$this->sql_clauses['select']  = "SELECT $found_rows $fields";
571
		$this->sql_clauses['from']    = "FROM $wpdb->blogs $join";
572
		$this->sql_clauses['groupby'] = $groupby;
573
		$this->sql_clauses['orderby'] = $orderby;
574
		$this->sql_clauses['limits']  = $limits;
575
576
		$this->request = "{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['groupby']} {$this->sql_clauses['orderby']} {$this->sql_clauses['limits']}";
577
578
		if ( $this->query_vars['count'] ) {
579
			return intval( $wpdb->get_var( $this->request ) );
580
		}
581
582
		$site_ids = $wpdb->get_col( $this->request );
583
584
		return array_map( 'intval', $site_ids );
585
	}
586
587
	/**
588
	 * Populates found_sites and max_num_pages properties for the current query
589
	 * if the limit clause was used.
590
	 *
591
	 * @since 4.6.0
592
	 * @access private
593
	 *
594
	 * @global wpdb $wpdb WordPress database abstraction object.
595
	 */
596 View Code Duplication
	private function set_found_sites() {
597
		global $wpdb;
598
599
		if ( $this->query_vars['number'] && ! $this->query_vars['no_found_rows'] ) {
600
			/**
601
			 * Filters the query used to retrieve found site count.
602
			 *
603
			 * @since 4.6.0
604
			 *
605
			 * @param string        $found_sites_query SQL query. Default 'SELECT FOUND_ROWS()'.
606
			 * @param WP_Site_Query $site_query        The `WP_Site_Query` instance.
607
			 */
608
			$found_sites_query = apply_filters( 'found_sites_query', 'SELECT FOUND_ROWS()', $this );
609
610
			$this->found_sites = (int) $wpdb->get_var( $found_sites_query );
611
		}
612
	}
613
614
	/**
615
	 * Used internally to generate an SQL string for searching across multiple columns.
616
	 *
617
	 * @since 4.6.0
618
	 * @access protected
619
	 *
620
	 * @global wpdb  $wpdb WordPress database abstraction object.
621
	 *
622
	 * @param string $string  Search string.
623
	 * @param array  $columns Columns to search.
624
	 * @return string Search SQL.
625
	 */
626
	protected function get_search_sql( $string, $columns ) {
627
		global $wpdb;
628
629
		if ( false !== strpos( $string, '*' ) ) {
630
			$like = '%' . implode( '%', array_map( array( $wpdb, 'esc_like' ), explode( '*', $string ) ) ) . '%';
631
		} else {
632
			$like = '%' . $wpdb->esc_like( $string ) . '%';
633
		}
634
635
		$searches = array();
636
		foreach ( $columns as $column ) {
637
			$searches[] = $wpdb->prepare( "$column LIKE %s", $like );
638
		}
639
640
		return '(' . implode( ' OR ', $searches ) . ')';
641
	}
642
643
	/**
644
	 * Parses and sanitizes 'orderby' keys passed to the site query.
645
	 *
646
	 * @since 4.6.0
647
	 * @access protected
648
	 *
649
	 * @global wpdb $wpdb WordPress database abstraction object.
650
	 *
651
	 * @param string $orderby Alias for the field to order by.
652
	 * @return string|false Value to used in the ORDER clause. False otherwise.
653
	 */
654
	protected function parse_orderby( $orderby ) {
655
		global $wpdb;
656
657
		$parsed = false;
658
659
		switch ( $orderby ) {
660 View Code Duplication
			case 'site__in':
661
				$site__in = implode( ',', array_map( 'absint', $this->query_vars['site__in'] ) );
662
				$parsed = "FIELD( {$wpdb->blogs}.blog_id, $site__in )";
663
				break;
664 View Code Duplication
			case 'network__in':
665
				$network__in = implode( ',', array_map( 'absint', $this->query_vars['network__in'] ) );
666
				$parsed = "FIELD( {$wpdb->blogs}.site_id, $network__in )";
667
				break;
668
			case 'domain':
669
			case 'last_updated':
670
			case 'path':
671
			case 'registered':
672
				$parsed = $orderby;
673
				break;
674
			case 'network_id':
675
				$parsed = 'site_id';
676
				break;
677
			case 'domain_length':
678
				$parsed = 'CHAR_LENGTH(domain)';
679
				break;
680
			case 'path_length':
681
				$parsed = 'CHAR_LENGTH(path)';
682
				break;
683
			case 'id':
684
				$parsed = 'blog_id';
685
				break;
686
		}
687
688
		return $parsed;
689
	}
690
691
	/**
692
	 * Parses an 'order' query variable and cast it to 'ASC' or 'DESC' as necessary.
693
	 *
694
	 * @since 4.6.0
695
	 * @access protected
696
	 *
697
	 * @param string $order The 'order' query variable.
698
	 * @return string The sanitized 'order' query variable.
699
	 */
700 View Code Duplication
	protected function parse_order( $order ) {
701
		if ( ! is_string( $order ) || empty( $order ) ) {
702
			return 'ASC';
703
		}
704
705
		if ( 'ASC' === strtoupper( $order ) ) {
706
			return 'ASC';
707
		} else {
708
			return 'DESC';
709
		}
710
	}
711
}
712