home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / class-wp-site-query.php < prev    next >
Encoding:
PHP Script  |  2017-10-18  |  22.6 KB  |  702 lines

  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.      * @var string
  24.      */
  25.     public $request;
  26.  
  27.     /**
  28.      * SQL query clauses.
  29.      *
  30.      * @since 4.6.0
  31.      * @var array
  32.      */
  33.     protected $sql_clauses = array(
  34.         'select'  => '',
  35.         'from'    => '',
  36.         'where'   => array(),
  37.         'groupby' => '',
  38.         'orderby' => '',
  39.         'limits'  => '',
  40.     );
  41.  
  42.     /**
  43.      * Date query container.
  44.      *
  45.      * @since 4.6.0
  46.      * @var object WP_Date_Query
  47.      */
  48.     public $date_query = false;
  49.  
  50.     /**
  51.      * Query vars set by the user.
  52.      *
  53.      * @since 4.6.0
  54.      * @var array
  55.      */
  56.     public $query_vars;
  57.  
  58.     /**
  59.      * Default values for query vars.
  60.      *
  61.      * @since 4.6.0
  62.      * @var array
  63.      */
  64.     public $query_var_defaults;
  65.  
  66.     /**
  67.      * List of sites located by the query.
  68.      *
  69.      * @since 4.6.0
  70.      * @var array
  71.      */
  72.     public $sites;
  73.  
  74.     /**
  75.      * The amount of found sites for the current query.
  76.      *
  77.      * @since 4.6.0
  78.      * @var int
  79.      */
  80.     public $found_sites = 0;
  81.  
  82.     /**
  83.      * The number of pages.
  84.      *
  85.      * @since 4.6.0
  86.      * @var int
  87.      */
  88.     public $max_num_pages = 0;
  89.  
  90.     /**
  91.      * Sets up the site query, based on the query vars passed.
  92.      *
  93.      * @since 4.6.0
  94.      * @since 4.8.0 Introduced the 'lang_id', 'lang__in', and 'lang__not_in' parameters.
  95.      *
  96.      * @param string|array $query {
  97.      *     Optional. Array or query string of site query parameters. Default empty.
  98.      *
  99.      *     @type array        $site__in          Array of site IDs to include. Default empty.
  100.      *     @type array        $site__not_in      Array of site IDs to exclude. Default empty.
  101.      *     @type bool         $count             Whether to return a site count (true) or array of site objects.
  102.      *                                           Default false.
  103.      *     @type array        $date_query        Date query clauses to limit sites by. See WP_Date_Query.
  104.      *                                           Default null.
  105.      *     @type string       $fields            Site fields to return. Accepts 'ids' (returns an array of site IDs)
  106.      *                                           or empty (returns an array of complete site objects). Default empty.
  107.      *     @type int          $ID                A site ID to only return that site. Default empty.
  108.      *     @type int          $number            Maximum number of sites to retrieve. Default 100.
  109.      *     @type int          $offset            Number of sites to offset the query. Used to build LIMIT clause.
  110.      *                                           Default 0.
  111.      *     @type bool         $no_found_rows     Whether to disable the `SQL_CALC_FOUND_ROWS` query. Default true.
  112.      *     @type string|array $orderby           Site status or array of statuses. Accepts 'id', 'domain', 'path',
  113.      *                                           'network_id', 'last_updated', 'registered', 'domain_length',
  114.      *                                           'path_length', 'site__in' and 'network__in'. Also accepts false,
  115.      *                                           an empty array, or 'none' to disable `ORDER BY` clause.
  116.      *                                           Default 'id'.
  117.      *     @type string       $order             How to order retrieved sites. Accepts 'ASC', 'DESC'. Default 'ASC'.
  118.      *     @type int          $network_id        Limit results to those affiliated with a given network ID. If 0,
  119.      *                                           include all networks. Default 0.
  120.      *     @type array        $network__in       Array of network IDs to include affiliated sites for. Default empty.
  121.      *     @type array        $network__not_in   Array of network IDs to exclude affiliated sites for. Default empty.
  122.      *     @type string       $domain            Limit results to those affiliated with a given domain. Default empty.
  123.      *     @type array        $domain__in        Array of domains to include affiliated sites for. Default empty.
  124.      *     @type array        $domain__not_in    Array of domains to exclude affiliated sites for. Default empty.
  125.      *     @type string       $path              Limit results to those affiliated with a given path. Default empty.
  126.      *     @type array        $path__in          Array of paths to include affiliated sites for. Default empty.
  127.      *     @type array        $path__not_in      Array of paths to exclude affiliated sites for. Default empty.
  128.      *     @type int          $public            Limit results to public sites. Accepts '1' or '0'. Default empty.
  129.      *     @type int          $archived          Limit results to archived sites. Accepts '1' or '0'. Default empty.
  130.      *     @type int          $mature            Limit results to mature sites. Accepts '1' or '0'. Default empty.
  131.      *     @type int          $spam              Limit results to spam sites. Accepts '1' or '0'. Default empty.
  132.      *     @type int          $deleted           Limit results to deleted sites. Accepts '1' or '0'. Default empty.
  133.      *     @type int          $lang_id           Limit results to a language ID. Default empty.
  134.      *     @type array        $lang__in          Array of language IDs to include affiliated sites for. Default empty.
  135.      *     @type array        $lang__not_in      Array of language IDs to exclude affiliated sites for. Default empty.
  136.      *     @type string       $search            Search term(s) to retrieve matching sites for. Default empty.
  137.      *     @type array        $search_columns    Array of column names to be searched. Accepts 'domain' and 'path'.
  138.      *                                           Default empty array.
  139.      *     @type bool         $update_site_cache Whether to prime the cache for found sites. Default true.
  140.      * }
  141.      */
  142.     public function __construct( $query = '' ) {
  143.         $this->query_var_defaults = array(
  144.             'fields'            => '',
  145.             'ID'                => '',
  146.             'site__in'          => '',
  147.             'site__not_in'      => '',
  148.             'number'            => 100,
  149.             'offset'            => '',
  150.             'no_found_rows'     => true,
  151.             'orderby'           => 'id',
  152.             'order'             => 'ASC',
  153.             'network_id'        => 0,
  154.             'network__in'       => '',
  155.             'network__not_in'   => '',
  156.             'domain'            => '',
  157.             'domain__in'        => '',
  158.             'domain__not_in'    => '',
  159.             'path'              => '',
  160.             'path__in'          => '',
  161.             'path__not_in'      => '',
  162.             'public'            => null,
  163.             'archived'          => null,
  164.             'mature'            => null,
  165.             'spam'              => null,
  166.             'deleted'           => null,
  167.             'lang_id'           => null,
  168.             'lang__in'          => '',
  169.             'lang__not_in'      => '',
  170.             'search'            => '',
  171.             'search_columns'    => array(),
  172.             'count'             => false,
  173.             'date_query'        => null, // See WP_Date_Query
  174.             'update_site_cache' => true,
  175.         );
  176.  
  177.         if ( ! empty( $query ) ) {
  178.             $this->query( $query );
  179.         }
  180.     }
  181.  
  182.     /**
  183.      * Parses arguments passed to the site query with default query parameters.
  184.      *
  185.      * @since 4.6.0
  186.      *
  187.      * @see WP_Site_Query::__construct()
  188.      *
  189.      * @param string|array $query Array or string of WP_Site_Query arguments. See WP_Site_Query::__construct().
  190.      */
  191.     public function parse_query( $query = '' ) {
  192.         if ( empty( $query ) ) {
  193.             $query = $this->query_vars;
  194.         }
  195.  
  196.         $this->query_vars = wp_parse_args( $query, $this->query_var_defaults );
  197.  
  198.         /**
  199.          * Fires after the site query vars have been parsed.
  200.          *
  201.          * @since 4.6.0
  202.          *
  203.          * @param WP_Site_Query $this The WP_Site_Query instance (passed by reference).
  204.          */
  205.         do_action_ref_array( 'parse_site_query', array( &$this ) );
  206.     }
  207.  
  208.     /**
  209.      * Sets up the WordPress query for retrieving sites.
  210.      *
  211.      * @since 4.6.0
  212.      *
  213.      * @param string|array $query Array or URL query string of parameters.
  214.      * @return array|int List of WP_Site objects, a list of site ids when 'fields' is set to 'ids',
  215.      *                   or the number of sites when 'count' is passed as a query var.
  216.      */
  217.     public function query( $query ) {
  218.         $this->query_vars = wp_parse_args( $query );
  219.  
  220.         return $this->get_sites();
  221.     }
  222.  
  223.     /**
  224.      * Retrieves a list of sites matching the query vars.
  225.      *
  226.      * @since 4.6.0
  227.      *
  228.      * @return array|int List of WP_Site objects, a list of site ids when 'fields' is set to 'ids',
  229.      *                   or the number of sites when 'count' is passed as a query var.
  230.      */
  231.     public function get_sites() {
  232.         $this->parse_query();
  233.  
  234.         /**
  235.          * Fires before sites are retrieved.
  236.          *
  237.          * @since 4.6.0
  238.          *
  239.          * @param WP_Site_Query $this Current instance of WP_Site_Query (passed by reference).
  240.          */
  241.         do_action_ref_array( 'pre_get_sites', array( &$this ) );
  242.  
  243.         // $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
  244.         $_args = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) );
  245.  
  246.         // Ignore the $fields argument as the queried result will be the same regardless.
  247.         unset( $_args['fields'] );
  248.  
  249.         $key = md5( serialize( $_args ) );
  250.         $last_changed = wp_cache_get_last_changed( 'sites' );
  251.  
  252.         $cache_key = "get_sites:$key:$last_changed";
  253.         $cache_value = wp_cache_get( $cache_key, 'sites' );
  254.  
  255.         if ( false === $cache_value ) {
  256.             $site_ids = $this->get_site_ids();
  257.             if ( $site_ids ) {
  258.                 $this->set_found_sites();
  259.             }
  260.  
  261.             $cache_value = array(
  262.                 'site_ids' => $site_ids,
  263.                 'found_sites' => $this->found_sites,
  264.             );
  265.             wp_cache_add( $cache_key, $cache_value, 'sites' );
  266.         } else {
  267.             $site_ids = $cache_value['site_ids'];
  268.             $this->found_sites = $cache_value['found_sites'];
  269.         }
  270.  
  271.         if ( $this->found_sites && $this->query_vars['number'] ) {
  272.             $this->max_num_pages = ceil( $this->found_sites / $this->query_vars['number'] );
  273.         }
  274.  
  275.         // If querying for a count only, there's nothing more to do.
  276.         if ( $this->query_vars['count'] ) {
  277.             // $site_ids is actually a count in this case.
  278.             return intval( $site_ids );
  279.         }
  280.  
  281.         $site_ids = array_map( 'intval', $site_ids );
  282.  
  283.         if ( 'ids' == $this->query_vars['fields'] ) {
  284.             $this->sites = $site_ids;
  285.  
  286.             return $this->sites;
  287.         }
  288.  
  289.         // Prime site network caches.
  290.         if ( $this->query_vars['update_site_cache'] ) {
  291.             _prime_site_caches( $site_ids );
  292.         }
  293.  
  294.         // Fetch full site objects from the primed cache.
  295.         $_sites = array();
  296.         foreach ( $site_ids as $site_id ) {
  297.             if ( $_site = get_site( $site_id ) ) {
  298.                 $_sites[] = $_site;
  299.             }
  300.         }
  301.  
  302.         /**
  303.          * Filters the site query results.
  304.          *
  305.          * @since 4.6.0
  306.          *
  307.          * @param array         $_sites An array of WP_Site objects.
  308.          * @param WP_Site_Query $this   Current instance of WP_Site_Query (passed by reference).
  309.          */
  310.         $_sites = apply_filters_ref_array( 'the_sites', array( $_sites, &$this ) );
  311.  
  312.         // Convert to WP_Site instances.
  313.         $this->sites = array_map( 'get_site', $_sites );
  314.  
  315.         return $this->sites;
  316.     }
  317.  
  318.     /**
  319.      * Used internally to get a list of site IDs matching the query vars.
  320.      *
  321.      * @since 4.6.0
  322.      *
  323.      * @global wpdb $wpdb WordPress database abstraction object.
  324.      *
  325.      * @return int|array A single count of site IDs if a count query. An array of site IDs if a full query.
  326.      */
  327.     protected function get_site_ids() {
  328.         global $wpdb;
  329.  
  330.         $order = $this->parse_order( $this->query_vars['order'] );
  331.  
  332.         // Disable ORDER BY with 'none', an empty array, or boolean false.
  333.         if ( in_array( $this->query_vars['orderby'], array( 'none', array(), false ), true ) ) {
  334.             $orderby = '';
  335.         } elseif ( ! empty( $this->query_vars['orderby'] ) ) {
  336.             $ordersby = is_array( $this->query_vars['orderby'] ) ?
  337.                 $this->query_vars['orderby'] :
  338.                 preg_split( '/[,\s]/', $this->query_vars['orderby'] );
  339.  
  340.             $orderby_array = array();
  341.             foreach ( $ordersby as $_key => $_value ) {
  342.                 if ( ! $_value ) {
  343.                     continue;
  344.                 }
  345.  
  346.                 if ( is_int( $_key ) ) {
  347.                     $_orderby = $_value;
  348.                     $_order = $order;
  349.                 } else {
  350.                     $_orderby = $_key;
  351.                     $_order = $_value;
  352.                 }
  353.  
  354.                 $parsed = $this->parse_orderby( $_orderby );
  355.  
  356.                 if ( ! $parsed ) {
  357.                     continue;
  358.                 }
  359.  
  360.                 if ( 'site__in' === $_orderby || 'network__in' === $_orderby ) {
  361.                     $orderby_array[] = $parsed;
  362.                     continue;
  363.                 }
  364.  
  365.                 $orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
  366.             }
  367.  
  368.             $orderby = implode( ', ', $orderby_array );
  369.         } else {
  370.             $orderby = "blog_id $order";
  371.         }
  372.  
  373.         $number = absint( $this->query_vars['number'] );
  374.         $offset = absint( $this->query_vars['offset'] );
  375.  
  376.         if ( ! empty( $number ) ) {
  377.             if ( $offset ) {
  378.                 $limits = 'LIMIT ' . $offset . ',' . $number;
  379.             } else {
  380.                 $limits = 'LIMIT ' . $number;
  381.             }
  382.         }
  383.  
  384.         if ( $this->query_vars['count'] ) {
  385.             $fields = 'COUNT(*)';
  386.         } else {
  387.             $fields = 'blog_id';
  388.         }
  389.  
  390.         // Parse site IDs for an IN clause.
  391.         $site_id = absint( $this->query_vars['ID'] );
  392.         if ( ! empty( $site_id ) ) {
  393.             $this->sql_clauses['where']['ID'] = $wpdb->prepare( 'blog_id = %d', $site_id );
  394.         }
  395.  
  396.         // Parse site IDs for an IN clause.
  397.         if ( ! empty( $this->query_vars['site__in'] ) ) {
  398.             $this->sql_clauses['where']['site__in'] = "blog_id IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__in'] ) ) . ' )';
  399.         }
  400.  
  401.         // Parse site IDs for a NOT IN clause.
  402.         if ( ! empty( $this->query_vars['site__not_in'] ) ) {
  403.             $this->sql_clauses['where']['site__not_in'] = "blog_id NOT IN ( " . implode( ',', wp_parse_id_list( $this->query_vars['site__not_in'] ) ) . ' )';
  404.         }
  405.  
  406.         $network_id = absint( $this->query_vars['network_id'] );
  407.  
  408.         if ( ! empty( $network_id ) ) {
  409.             $this->sql_clauses['where']['network_id'] = $wpdb->prepare( 'site_id = %d', $network_id );
  410.         }
  411.  
  412.         // Parse site network IDs for an IN clause.
  413.         if ( ! empty( $this->query_vars['network__in'] ) ) {
  414.             $this->sql_clauses['where']['network__in'] = 'site_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['network__in'] ) ) . ' )';
  415.         }
  416.  
  417.         // Parse site network IDs for a NOT IN clause.
  418.         if ( ! empty( $this->query_vars['network__not_in'] ) ) {
  419.             $this->sql_clauses['where']['network__not_in'] = 'site_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['network__not_in'] ) ) . ' )';
  420.         }
  421.  
  422.         if ( ! empty( $this->query_vars['domain'] ) ) {
  423.             $this->sql_clauses['where']['domain'] = $wpdb->prepare( 'domain = %s', $this->query_vars['domain'] );
  424.         }
  425.  
  426.         // Parse site domain for an IN clause.
  427.         if ( is_array( $this->query_vars['domain__in'] ) ) {
  428.             $this->sql_clauses['where']['domain__in'] = "domain IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['domain__in'] ) ) . "' )";
  429.         }
  430.  
  431.         // Parse site domain for a NOT IN clause.
  432.         if ( is_array( $this->query_vars['domain__not_in'] ) ) {
  433.             $this->sql_clauses['where']['domain__not_in'] = "domain NOT IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['domain__not_in'] ) ) . "' )";
  434.         }
  435.  
  436.         if ( ! empty( $this->query_vars['path'] ) ) {
  437.             $this->sql_clauses['where']['path'] = $wpdb->prepare( 'path = %s', $this->query_vars['path'] );
  438.         }
  439.  
  440.         // Parse site path for an IN clause.
  441.         if ( is_array( $this->query_vars['path__in'] ) ) {
  442.             $this->sql_clauses['where']['path__in'] = "path IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['path__in'] ) ) . "' )";
  443.         }
  444.  
  445.         // Parse site path for a NOT IN clause.
  446.         if ( is_array( $this->query_vars['path__not_in'] ) ) {
  447.             $this->sql_clauses['where']['path__not_in'] = "path NOT IN ( '" . implode( "', '", $wpdb->_escape( $this->query_vars['path__not_in'] ) ) . "' )";
  448.         }
  449.  
  450.         if ( is_numeric( $this->query_vars['archived'] ) ) {
  451.             $archived = absint( $this->query_vars['archived'] );
  452.             $this->sql_clauses['where']['archived'] = $wpdb->prepare( "archived = %s ", absint( $archived ) );
  453.         }
  454.  
  455.         if ( is_numeric( $this->query_vars['mature'] ) ) {
  456.             $mature = absint( $this->query_vars['mature'] );
  457.             $this->sql_clauses['where']['mature'] = $wpdb->prepare( "mature = %d ", $mature );
  458.         }
  459.  
  460.         if ( is_numeric( $this->query_vars['spam'] ) ) {
  461.             $spam = absint( $this->query_vars['spam'] );
  462.             $this->sql_clauses['where']['spam'] = $wpdb->prepare( "spam = %d ", $spam );
  463.         }
  464.  
  465.         if ( is_numeric( $this->query_vars['deleted'] ) ) {
  466.             $deleted = absint( $this->query_vars['deleted'] );
  467.             $this->sql_clauses['where']['deleted'] = $wpdb->prepare( "deleted = %d ", $deleted );
  468.         }
  469.  
  470.         if ( is_numeric( $this->query_vars['public'] ) ) {
  471.             $public = absint( $this->query_vars['public'] );
  472.             $this->sql_clauses['where']['public'] = $wpdb->prepare( "public = %d ", $public );
  473.         }
  474.  
  475.         if ( is_numeric( $this->query_vars['lang_id'] ) ) {
  476.             $lang_id = absint( $this->query_vars['lang_id'] );
  477.             $this->sql_clauses['where']['lang_id'] = $wpdb->prepare( "lang_id = %d ", $lang_id );
  478.         }
  479.  
  480.         // Parse site language IDs for an IN clause.
  481.         if ( ! empty( $this->query_vars['lang__in'] ) ) {
  482.             $this->sql_clauses['where']['lang__in'] = 'lang_id IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['lang__in'] ) ) . ' )';
  483.         }
  484.  
  485.         // Parse site language IDs for a NOT IN clause.
  486.         if ( ! empty( $this->query_vars['lang__not_in'] ) ) {
  487.             $this->sql_clauses['where']['lang__not_in'] = 'lang_id NOT IN ( ' . implode( ',', wp_parse_id_list( $this->query_vars['lang__not_in'] ) ) . ' )';
  488.         }
  489.  
  490.         // Falsey search strings are ignored.
  491.         if ( strlen( $this->query_vars['search'] ) ) {
  492.             $search_columns = array();
  493.  
  494.             if ( $this->query_vars['search_columns'] ) {
  495.                 $search_columns = array_intersect( $this->query_vars['search_columns'], array( 'domain', 'path' ) );
  496.             }
  497.  
  498.             if ( ! $search_columns ) {
  499.                 $search_columns = array( 'domain', 'path' );
  500.             }
  501.  
  502.             /**
  503.              * Filters the columns to search in a WP_Site_Query search.
  504.              *
  505.              * The default columns include 'domain' and 'path.
  506.              *
  507.              * @since 4.6.0
  508.              *
  509.              * @param array         $search_columns Array of column names to be searched.
  510.              * @param string        $search         Text being searched.
  511.              * @param WP_Site_Query $this           The current WP_Site_Query instance.
  512.              */
  513.             $search_columns = apply_filters( 'site_search_columns', $search_columns, $this->query_vars['search'], $this );
  514.  
  515.             $this->sql_clauses['where']['search'] = $this->get_search_sql( $this->query_vars['search'], $search_columns );
  516.         }
  517.  
  518.         $date_query = $this->query_vars['date_query'];
  519.         if ( ! empty( $date_query ) && is_array( $date_query ) ) {
  520.             $this->date_query = new WP_Date_Query( $date_query, 'registered' );
  521.             $this->sql_clauses['where']['date_query'] = preg_replace( '/^\s*AND\s*/', '', $this->date_query->get_sql() );
  522.         }
  523.  
  524.         $join = '';
  525.  
  526.         $where = implode( ' AND ', $this->sql_clauses['where'] );
  527.  
  528.         $pieces = array( 'fields', 'join', 'where', 'orderby', 'limits', 'groupby' );
  529.  
  530.         /**
  531.          * Filters the site query clauses.
  532.          *
  533.          * @since 4.6.0
  534.          *
  535.          * @param array         $pieces A compacted array of site query clauses.
  536.          * @param WP_Site_Query $this   Current instance of WP_Site_Query (passed by reference).
  537.          */
  538.         $clauses = apply_filters_ref_array( 'sites_clauses', array( compact( $pieces ), &$this ) );
  539.  
  540.         $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : '';
  541.         $join = isset( $clauses['join'] ) ? $clauses['join'] : '';
  542.         $where = isset( $clauses['where'] ) ? $clauses['where'] : '';
  543.         $orderby = isset( $clauses['orderby'] ) ? $clauses['orderby'] : '';
  544.         $limits = isset( $clauses['limits'] ) ? $clauses['limits'] : '';
  545.         $groupby = isset( $clauses['groupby'] ) ? $clauses['groupby'] : '';
  546.  
  547.         if ( $where ) {
  548.             $where = 'WHERE ' . $where;
  549.         }
  550.  
  551.         if ( $groupby ) {
  552.             $groupby = 'GROUP BY ' . $groupby;
  553.         }
  554.  
  555.         if ( $orderby ) {
  556.             $orderby = "ORDER BY $orderby";
  557.         }
  558.  
  559.         $found_rows = '';
  560.         if ( ! $this->query_vars['no_found_rows'] ) {
  561.             $found_rows = 'SQL_CALC_FOUND_ROWS';
  562.         }
  563.  
  564.         $this->sql_clauses['select']  = "SELECT $found_rows $fields";
  565.         $this->sql_clauses['from']    = "FROM $wpdb->blogs $join";
  566.         $this->sql_clauses['groupby'] = $groupby;
  567.         $this->sql_clauses['orderby'] = $orderby;
  568.         $this->sql_clauses['limits']  = $limits;
  569.  
  570.         $this->request = "{$this->sql_clauses['select']} {$this->sql_clauses['from']} {$where} {$this->sql_clauses['groupby']} {$this->sql_clauses['orderby']} {$this->sql_clauses['limits']}";
  571.  
  572.         if ( $this->query_vars['count'] ) {
  573.             return intval( $wpdb->get_var( $this->request ) );
  574.         }
  575.  
  576.         $site_ids = $wpdb->get_col( $this->request );
  577.  
  578.         return array_map( 'intval', $site_ids );
  579.     }
  580.  
  581.     /**
  582.      * Populates found_sites and max_num_pages properties for the current query
  583.      * if the limit clause was used.
  584.      *
  585.      * @since 4.6.0
  586.      *
  587.      * @global wpdb $wpdb WordPress database abstraction object.
  588.      */
  589.     private function set_found_sites() {
  590.         global $wpdb;
  591.  
  592.         if ( $this->query_vars['number'] && ! $this->query_vars['no_found_rows'] ) {
  593.             /**
  594.              * Filters the query used to retrieve found site count.
  595.              *
  596.              * @since 4.6.0
  597.              *
  598.              * @param string        $found_sites_query SQL query. Default 'SELECT FOUND_ROWS()'.
  599.              * @param WP_Site_Query $site_query        The `WP_Site_Query` instance.
  600.              */
  601.             $found_sites_query = apply_filters( 'found_sites_query', 'SELECT FOUND_ROWS()', $this );
  602.  
  603.             $this->found_sites = (int) $wpdb->get_var( $found_sites_query );
  604.         }
  605.     }
  606.  
  607.     /**
  608.      * Used internally to generate an SQL string for searching across multiple columns.
  609.      *
  610.      * @since 4.6.0
  611.      *
  612.      * @global wpdb  $wpdb WordPress database abstraction object.
  613.      *
  614.      * @param string $string  Search string.
  615.      * @param array  $columns Columns to search.
  616.      * @return string Search SQL.
  617.      */
  618.     protected function get_search_sql( $string, $columns ) {
  619.         global $wpdb;
  620.  
  621.         if ( false !== strpos( $string, '*' ) ) {
  622.             $like = '%' . implode( '%', array_map( array( $wpdb, 'esc_like' ), explode( '*', $string ) ) ) . '%';
  623.         } else {
  624.             $like = '%' . $wpdb->esc_like( $string ) . '%';
  625.         }
  626.  
  627.         $searches = array();
  628.         foreach ( $columns as $column ) {
  629.             $searches[] = $wpdb->prepare( "$column LIKE %s", $like );
  630.         }
  631.  
  632.         return '(' . implode( ' OR ', $searches ) . ')';
  633.     }
  634.  
  635.     /**
  636.      * Parses and sanitizes 'orderby' keys passed to the site query.
  637.      *
  638.      * @since 4.6.0
  639.      *
  640.      * @global wpdb $wpdb WordPress database abstraction object.
  641.      *
  642.      * @param string $orderby Alias for the field to order by.
  643.      * @return string|false Value to used in the ORDER clause. False otherwise.
  644.      */
  645.     protected function parse_orderby( $orderby ) {
  646.         global $wpdb;
  647.  
  648.         $parsed = false;
  649.  
  650.         switch ( $orderby ) {
  651.             case 'site__in':
  652.                 $site__in = implode( ',', array_map( 'absint', $this->query_vars['site__in'] ) );
  653.                 $parsed = "FIELD( {$wpdb->blogs}.blog_id, $site__in )";
  654.                 break;
  655.             case 'network__in':
  656.                 $network__in = implode( ',', array_map( 'absint', $this->query_vars['network__in'] ) );
  657.                 $parsed = "FIELD( {$wpdb->blogs}.site_id, $network__in )";
  658.                 break;
  659.             case 'domain':
  660.             case 'last_updated':
  661.             case 'path':
  662.             case 'registered':
  663.                 $parsed = $orderby;
  664.                 break;
  665.             case 'network_id':
  666.                 $parsed = 'site_id';
  667.                 break;
  668.             case 'domain_length':
  669.                 $parsed = 'CHAR_LENGTH(domain)';
  670.                 break;
  671.             case 'path_length':
  672.                 $parsed = 'CHAR_LENGTH(path)';
  673.                 break;
  674.             case 'id':
  675.                 $parsed = 'blog_id';
  676.                 break;
  677.         }
  678.  
  679.         return $parsed;
  680.     }
  681.  
  682.     /**
  683.      * Parses an 'order' query variable and cast it to 'ASC' or 'DESC' as necessary.
  684.      *
  685.      * @since 4.6.0
  686.      *
  687.      * @param string $order The 'order' query variable.
  688.      * @return string The sanitized 'order' query variable.
  689.      */
  690.     protected function parse_order( $order ) {
  691.         if ( ! is_string( $order ) || empty( $order ) ) {
  692.             return 'ASC';
  693.         }
  694.  
  695.         if ( 'ASC' === strtoupper( $order ) ) {
  696.             return 'ASC';
  697.         } else {
  698.             return 'DESC';
  699.         }
  700.     }
  701. }
  702.