WordPress.org

Make WordPress Core

Ticket #31985: 31985.8.diff

File 31985.8.diff, 18.2 KB (added by jeremyfelt, 6 years ago)
  • src/wp-includes/class-wp-network.php

     
     1<?php
     2/**
     3 * Network API: WP_Network object class
     4 *
     5 * @package WordPress
     6 * @subpackage Multisite
     7 * @since 4.4.0
     8 */
     9
     10/**
     11 * Core class used for interacting with a multisite network.
     12 *
     13 * This class is used during load to populate the `$current_site` global and
     14 * setup the current network.
     15 *
     16 * This class is most useful in WordPress multi-network installations where the
     17 * ability to interact with any network of sites is required.
     18 *
     19 * @since 4.4.0
     20 */
     21class WP_Network {
     22
     23        /**
     24         * Network ID.
     25         *
     26         * @since 4.4.0
     27         * @access public
     28         * @var int
     29         */
     30        public $id;
     31
     32        /**
     33         * Domain of the network.
     34         *
     35         * @since 4.4.0
     36         * @access public
     37         * @var string
     38         */
     39        public $domain = '';
     40
     41        /**
     42         * Path of the network.
     43         *
     44         * @since 4.4.0
     45         * @access public
     46         * @var string
     47         */
     48        public $path = '';
     49
     50        /**
     51         * The ID of the network's main site.
     52         *
     53         * Named "blog" vs. "site" for legacy reasons. A main site is mapped to
     54         * the network when the network is created.
     55         *
     56         * @since 4.4.0
     57         * @access public
     58         * @var int
     59         */
     60        public $blog_id = 0;
     61
     62        /**
     63         * Domain used to set cookies for this network.
     64         *
     65         * @since 4.4.0
     66         * @access public
     67         * @var int
     68         */
     69        public $cookie_domain = '';
     70
     71        /**
     72         * Name of this network.
     73         *
     74         * Named "site" vs. "network" for legacy reasons.
     75         *
     76         * @since 4.4.0
     77         * @access public
     78         * @var string
     79         */
     80        public $site_name = '';
     81
     82        /**
     83         * Retrieve a network from the database by its ID.
     84         *
     85         * @since 4.4.0
     86         * @access public
     87         *
     88         * @global wpdb $wpdb WordPress database abstraction object.
     89         *
     90         * @param int $network_id The ID of the network to retrieve.
     91         * @return WP_Network|bool The network's object if found. False if not.
     92         */
     93        public static function get_instance( $network_id ) {
     94                global $wpdb;
     95
     96                $network_id = (int) $network_id;
     97                if ( $network_id ) {
     98                        return false;
     99                }
     100
     101                $_network = wp_cache_get( $network_id, 'networks' );
     102
     103                if ( ! $_network ) {
     104                        $_network = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->site} WHERE id = %d LIMIT 1", $network_id ) );
     105
     106                        if ( empty( $_network ) || is_wp_error( $_network ) ) {
     107                                return false;
     108                        }
     109
     110                        wp_cache_add( $network_id, $_network, 'networks' );
     111                }
     112
     113                return new WP_Network( $_network );
     114        }
     115
     116        /**
     117         * Create a new WP_Network object.
     118         *
     119         * Will populate object properties from the object provided and assign other
     120         * default properties based on that information.
     121         *
     122         * @since 4.4.0
     123         * @access public
     124         *
     125         * @param WP_Network|object $network A network object.
     126         */
     127        public function __construct( $network ) {
     128                foreach( get_object_vars( $network ) as $key => $value ) {
     129                        $this->$key = $value;
     130                }
     131
     132                $this->set_cookie_domain();
     133        }
     134
     135        /**
     136         * Set the cookie domain based on the network domain if one has
     137         * not been populated.
     138         *
     139         * @todo What if the domain of the network doesn't match the current site?
     140         *
     141         * @since 4.4.0
     142         * @access private
     143         */
     144        private function set_cookie_domain() {
     145                if ( ! empty( $this->cookie_domain ) ) {
     146                        return;
     147                }
     148
     149                $this->cookie_domain = $this->domain;
     150                if ( 'www.' === substr( $this->cookie_domain, 0, 4 ) ) {
     151                        $this->cookie_domain = substr( $this->cookie_domain, 4 );
     152                }
     153        }
     154
     155        /**
     156         * Retrieve a network by its domain and path.
     157         *
     158         * @since 4.4.0
     159         * @access public
     160         * @static
     161         *
     162         * @param string   $domain   Domain to check.
     163         * @param string   $path     Path to check.
     164         * @param int|null $segments Path segments to use. Defaults to null, or the full path.
     165         * @return WP_Network|bool Network object if successful. False when no network is found.
     166         */
     167        public static function get_by_path( $domain = '', $path = '', $segments = null ) {
     168                global $wpdb;
     169
     170                $domains = array( $domain );
     171                $pieces  = explode( '.', $domain );
     172
     173                /*
     174                 * It's possible one domain to search is 'com', but it might as well
     175                 * be 'localhost' or some other locally mapped domain.
     176                 */
     177                while ( array_shift( $pieces ) ) {
     178                        if ( ! empty( $pieces ) ) {
     179                                $domains[] = implode( '.', $pieces );
     180                        }
     181                }
     182
     183                /*
     184                 * If we've gotten to this function during normal execution, there is
     185                 * more than one network installed. At this point, who knows how many
     186                 * we have. Attempt to optimize for the situation where networks are
     187                 * only domains, thus meaning paths never need to be considered.
     188                 *
     189                 * This is a very basic optimization; anything further could have
     190                 * drawbacks depending on the setup, so this is best done per-install.
     191                 */
     192                $using_paths = true;
     193                if ( wp_using_ext_object_cache() ) {
     194                        $using_paths = wp_cache_get( 'networks_have_paths', 'site-options' );
     195                        if ( false === $using_paths ) {
     196                                $using_paths = $wpdb->get_var( "SELECT id FROM {$wpdb->site} WHERE path <> '/' LIMIT 1" );
     197                                wp_cache_add( 'networks_have_paths', (int) $using_paths, 'site-options'  );
     198                        }
     199                }
     200
     201                $paths = array();
     202                if ( true === $using_paths ) {
     203                        $path_segments = array_filter( explode( '/', trim( $path, '/' ) ) );
     204
     205                        /**
     206                         * Filter the number of path segments to consider when searching for a site.
     207                         *
     208                         * @since 3.9.0
     209                         *
     210                         * @param int|null $segments The number of path segments to consider. WordPress by default looks at
     211                         *                           one path segment. The function default of null only makes sense when you
     212                         *                           know the requested path should match a network.
     213                         * @param string   $domain   The requested domain.
     214                         * @param string   $path     The requested path, in full.
     215                         */
     216                        $segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path );
     217
     218                        if ( ( null !== $segments ) && count( $path_segments ) > $segments ) {
     219                                $path_segments = array_slice( $path_segments, 0, $segments );
     220                        }
     221
     222                        while ( count( $path_segments ) ) {
     223                                $paths[] = '/' . implode( '/', $path_segments ) . '/';
     224                                array_pop( $path_segments );
     225                        }
     226
     227                        $paths[] = '/';
     228                }
     229
     230                /**
     231                 * Determine a network by its domain and path.
     232                 *
     233                 * This allows one to short-circuit the default logic, perhaps by
     234                 * replacing it with a routine that is more optimal for your setup.
     235                 *
     236                 * Return null to avoid the short-circuit. Return false if no network
     237                 * can be found at the requested domain and path. Otherwise, return
     238                 * an object from wp_get_network().
     239                 *
     240                 * @since 3.9.0
     241                 *
     242                 * @param null|bool|object $network  Network value to return by path.
     243                 * @param string           $domain   The requested domain.
     244                 * @param string           $path     The requested path, in full.
     245                 * @param int|null         $segments The suggested number of paths to consult.
     246                 *                                   Default null, meaning the entire path was to be consulted.
     247                 * @param array            $paths    The paths to search for, based on $path and $segments.
     248                 */
     249                $pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths );
     250                if ( null !== $pre ) {
     251                        return $pre;
     252                }
     253
     254                // @todo Consider additional optimization routes, perhaps as an opt-in for plugins.
     255                // We already have paths covered. What about how far domains should be drilled down (including www)?
     256
     257                $search_domains = "'" . implode( "', '", $wpdb->_escape( $domains ) ) . "'";
     258
     259                if ( false === $using_paths ) {
     260                        $network = $wpdb->get_row( "
     261                                SELECT * FROM {$wpdb->site}
     262                                WHERE domain IN ({$search_domains})
     263                                ORDER BY CHAR_LENGTH(domain)
     264                                DESC LIMIT 1
     265                        " );
     266
     267                        if ( ! empty( $network ) && ! is_wp_error( $network ) ) {
     268                                return new WP_Network( $network );
     269                        }
     270
     271                        return false;
     272
     273                } else {
     274                        $search_paths = "'" . implode( "', '", $wpdb->_escape( $paths ) ) . "'";
     275                        $networks = $wpdb->get_results( "
     276                                SELECT * FROM {$wpdb->site}
     277                                WHERE domain IN ({$search_domains})
     278                                AND path IN ({$search_paths})
     279                                ORDER BY CHAR_LENGTH(domain) DESC, CHAR_LENGTH(path) DESC
     280                        " );
     281                }
     282
     283                /*
     284                 * Domains are sorted by length of domain, then by length of path.
     285                 * The domain must match for the path to be considered. Otherwise,
     286                 * a network with the path of / will suffice.
     287                 */
     288                $found = false;
     289                foreach ( $networks as $network ) {
     290                        if ( ( $network->domain === $domain ) || ( "www.{$network->domain}" === $domain ) ) {
     291                                if ( in_array( $network->path, $paths, true ) ) {
     292                                        $found = true;
     293                                        break;
     294                                }
     295                        }
     296                        if ( $network->path === '/' ) {
     297                                $found = true;
     298                                break;
     299                        }
     300                }
     301
     302                if ( true === $found ) {
     303                        return new WP_Network( $network );
     304                }
     305
     306                return false;
     307        }
     308}
  • src/wp-includes/ms-load.php

     
    113113 * Retrieve a network object by its domain and path.
    114114 *
    115115 * @since 3.9.0
    116  *
    117  * @global wpdb $wpdb
     116 * @since 4.4.0 Converted to a wrapper for WP_Network::get_by_path()
    118117 *
    119118 * @param string   $domain   Domain to check.
    120119 * @param string   $path     Path to check.
    121120 * @param int|null $segments Path segments to use. Defaults to null, or the full path.
    122  * @return object|false Network object if successful. False when no network is found.
     121 * @return WP_Network|false Network object if successful. False when no network is found.
    123122 */
    124123function get_network_by_path( $domain, $path, $segments = null ) {
    125         global $wpdb;
    126 
    127         $domains = array( $domain );
    128         $pieces = explode( '.', $domain );
    129 
    130         /*
    131          * It's possible one domain to search is 'com', but it might as well
    132          * be 'localhost' or some other locally mapped domain.
    133          */
    134         while ( array_shift( $pieces ) ) {
    135                 if ( $pieces ) {
    136                         $domains[] = implode( '.', $pieces );
    137                 }
    138         }
    139 
    140         /*
    141          * If we've gotten to this function during normal execution, there is
    142          * more than one network installed. At this point, who knows how many
    143          * we have. Attempt to optimize for the situation where networks are
    144          * only domains, thus meaning paths never need to be considered.
    145          *
    146          * This is a very basic optimization; anything further could have drawbacks
    147          * depending on the setup, so this is best done per-install.
    148          */
    149         $using_paths = true;
    150         if ( wp_using_ext_object_cache() ) {
    151                 $using_paths = wp_cache_get( 'networks_have_paths', 'site-options' );
    152                 if ( false === $using_paths ) {
    153                         $using_paths = (bool) $wpdb->get_var( "SELECT id FROM $wpdb->site WHERE path <> '/' LIMIT 1" );
    154                         wp_cache_add( 'networks_have_paths', (int) $using_paths, 'site-options'  );
    155                 }
    156         }
    157 
    158         $paths = array();
    159         if ( $using_paths ) {
    160                 $path_segments = array_filter( explode( '/', trim( $path, "/" ) ) );
    161 
    162                 /**
    163                  * Filter the number of path segments to consider when searching for a site.
    164                  *
    165                  * @since 3.9.0
    166                  *
    167                  * @param int|null $segments The number of path segments to consider. WordPress by default looks at
    168                  *                           one path segment. The function default of null only makes sense when you
    169                  *                           know the requested path should match a network.
    170                  * @param string   $domain   The requested domain.
    171                  * @param string   $path     The requested path, in full.
    172                  */
    173                 $segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path );
    174 
    175                 if ( null !== $segments && count($path_segments ) > $segments ) {
    176                         $path_segments = array_slice( $path_segments, 0, $segments );
    177                 }
    178 
    179                 while ( count( $path_segments ) ) {
    180                         $paths[] = '/' . implode( '/', $path_segments ) . '/';
    181                         array_pop( $path_segments );
    182                 }
    183 
    184                 $paths[] = '/';
    185         }
    186 
    187         /**
    188          * Determine a network by its domain and path.
    189          *
    190          * This allows one to short-circuit the default logic, perhaps by
    191          * replacing it with a routine that is more optimal for your setup.
    192          *
    193          * Return null to avoid the short-circuit. Return false if no network
    194          * can be found at the requested domain and path. Otherwise, return
    195          * an object from wp_get_network().
    196          *
    197          * @since 3.9.0
    198          *
    199          * @param null|bool|object $network  Network value to return by path.
    200          * @param string           $domain   The requested domain.
    201          * @param string           $path     The requested path, in full.
    202          * @param int|null         $segments The suggested number of paths to consult.
    203          *                                   Default null, meaning the entire path was to be consulted.
    204          * @param array            $paths    The paths to search for, based on $path and $segments.
    205          */
    206         $pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths );
    207         if ( null !== $pre ) {
    208                 return $pre;
    209         }
    210 
    211         // @todo Consider additional optimization routes, perhaps as an opt-in for plugins.
    212         // We already have paths covered. What about how far domains should be drilled down (including www)?
    213 
    214         $search_domains = "'" . implode( "', '", $wpdb->_escape( $domains ) ) . "'";
    215 
    216         if ( ! $using_paths ) {
    217                 $network = $wpdb->get_row( "SELECT id, domain, path FROM $wpdb->site
    218                         WHERE domain IN ($search_domains) ORDER BY CHAR_LENGTH(domain) DESC LIMIT 1" );
    219                 if ( $network ) {
    220                         return wp_get_network( $network );
    221                 }
    222                 return false;
    223 
    224         } else {
    225                 $search_paths = "'" . implode( "', '", $wpdb->_escape( $paths ) ) . "'";
    226                 $networks = $wpdb->get_results( "SELECT id, domain, path FROM $wpdb->site
    227                         WHERE domain IN ($search_domains) AND path IN ($search_paths)
    228                         ORDER BY CHAR_LENGTH(domain) DESC, CHAR_LENGTH(path) DESC" );
    229         }
    230 
    231         /*
    232          * Domains are sorted by length of domain, then by length of path.
    233          * The domain must match for the path to be considered. Otherwise,
    234          * a network with the path of / will suffice.
    235          */
    236         $found = false;
    237         foreach ( $networks as $network ) {
    238                 if ( $network->domain === $domain || "www.$network->domain" === $domain ) {
    239                         if ( in_array( $network->path, $paths, true ) ) {
    240                                 $found = true;
    241                                 break;
    242                         }
    243                 }
    244                 if ( $network->path === '/' ) {
    245                         $found = true;
    246                         break;
    247                 }
    248         }
    249 
    250         if ( $found ) {
    251                 return wp_get_network( $network );
    252         }
    253 
    254         return false;
     124        return WP_Network::get_by_path( $domain, $path, $segments );
    255125}
    256126
    257127/**
    258128 * Retrieve an object containing information about the requested network.
    259129 *
    260130 * @since 3.9.0
    261  *
    262  * @global wpdb $wpdb
     131 * @since 4.4.0 Converted to leverage WP_Network
    263132 *
    264133 * @param object|int $network The network's database row or ID.
    265  * @return object|false Object containing network information if found, false if not.
     134 * @return WP_Network|false Object containing network information if found, false if not.
    266135 */
    267136function wp_get_network( $network ) {
    268         global $wpdb;
    269 
    270137        if ( ! is_object( $network ) ) {
    271                 $network = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->site WHERE id = %d", $network ) );
    272                 if ( ! $network ) {
    273                         return false;
    274                 }
     138                $network = WP_Network::get_instance( $network );
     139        } else {
     140                $network = new WP_Network( $network );
    275141        }
    276142
    277143        return $network;
  • src/wp-includes/ms-settings.php

     
    1010 * @since 3.0.0
    1111 */
    1212
    13 /** Include Multisite initialization functions */
     13/** WP_Network class */
     14require_once( ABSPATH . WPINC . '/class-wp-network.php' );
     15
     16/** Multisite loader */
    1417require_once( ABSPATH . WPINC . '/ms-load.php' );
     18
     19/** Default Multisite constants */
    1520require_once( ABSPATH . WPINC . '/ms-default-constants.php' );
    1621
    1722if ( defined( 'SUNRISE' ) ) {
     
    7580                        // Are there even two networks installed?
    7681                        $one_network = $wpdb->get_row( "SELECT * FROM $wpdb->site LIMIT 2" ); // [sic]
    7782                        if ( 1 === $wpdb->num_rows ) {
    78                                 $current_site = wp_get_network( $one_network );
     83                                $current_site = new WP_Network( $one_network );
    7984                                wp_cache_add( 'current_network', $current_site, 'site-options' );
    8085                        } elseif ( 0 === $wpdb->num_rows ) {
    8186                                ms_not_installed( $domain, $path );
    8287                        }
    8388                }
    8489                if ( empty( $current_site ) ) {
    85                         $current_site = get_network_by_path( $domain, $path, 1 );
     90                        $current_site = WP_Network::get_by_path( $domain, $path, 1 );
    8691                }
    8792
    8893                if ( empty( $current_site ) ) {
     
    110115                // Find the site by the domain and at most the first path segment.
    111116                $current_blog = get_site_by_path( $domain, $path, 1 );
    112117                if ( $current_blog ) {
    113                         $current_site = wp_get_network( $current_blog->site_id ? $current_blog->site_id : 1 );
     118                        $current_site = WP_Network::get_instance( $current_blog->site_id ? $current_blog->site_id : 1 );
    114119                } else {
    115120                        // If you don't have a site with the same domain/path as a network, you're pretty screwed, but:
    116                         $current_site = get_network_by_path( $domain, $path, 1 );
     121                        $current_site = WP_Network::get_by_path( $domain, $path, 1 );
    117122                }
    118123        }
    119124
    120125        // The network declared by the site trumps any constants.
    121126        if ( $current_blog && $current_blog->site_id != $current_site->id ) {
    122                 $current_site = wp_get_network( $current_blog->site_id );
     127                $current_site = WP_Network::get_instance( $current_blog->site_id );
    123128        }
    124129
    125130        // No network has been found, bail.
     
    179184                exit;
    180185        }
    181186
    182         // @todo What if the domain of the network doesn't match the current site?
    183         $current_site->cookie_domain = $current_site->domain;
    184         if ( 'www.' === substr( $current_site->cookie_domain, 0, 4 ) ) {
    185                 $current_site->cookie_domain = substr( $current_site->cookie_domain, 4 );
    186         }
    187 
    188187        // Figure out the current network's main site.
    189         if ( ! isset( $current_site->blog_id ) ) {
     188        if ( empty( $current_site->blog_id ) ) {
    190189                if ( $current_blog->domain === $current_site->domain && $current_blog->path === $current_site->path ) {
    191190                        $current_site->blog_id = $current_blog->blog_id;
    192191                } elseif ( ! $current_site->blog_id = wp_cache_get( 'network:' . $current_site->id . ':main_site', 'site-options' ) ) {
     
    218217// need to init cache again after blog_id is set
    219218wp_start_object_cache();
    220219
    221 if ( ! isset( $current_site->site_name ) ) {
     220if ( ! $current_site instanceof WP_Network ) {
     221        $current_site = new WP_Network( $current_site );
     222}
     223
     224if ( empty( $current_site->site_name ) ) {
    222225        $current_site->site_name = get_site_option( 'site_name' );
    223226        if ( ! $current_site->site_name ) {
    224227                $current_site->site_name = ucfirst( $current_site->domain );