[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> class-wp-network.php (source)

   1  <?php
   2  /**
   3   * Network API: WP_Network 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   *
  21   * @property int    $id
  22   * @property string $blog_id
  23   * @property int    $site_id
  24   *
  25   * @phpstan-property numeric-string $blog_id
  26   */
  27  #[AllowDynamicProperties]
  28  class WP_Network {
  29  
  30      /**
  31       * Network ID.
  32       *
  33       * @since 4.4.0
  34       * @since 4.6.0 Converted from public to private to explicitly enable more intuitive
  35       *              access via magic methods. As part of the access change, the type was
  36       *              also changed from `string` to `int`.
  37       * @var int
  38       */
  39      private $id;
  40  
  41      /**
  42       * Domain of the network.
  43       *
  44       * @since 4.4.0
  45       * @var string
  46       */
  47      public $domain = '';
  48  
  49      /**
  50       * Path of the network.
  51       *
  52       * @since 4.4.0
  53       * @var string
  54       */
  55      public $path = '';
  56  
  57      /**
  58       * The ID of the network's main site.
  59       *
  60       * Named "blog" vs. "site" for legacy reasons. A main site is mapped to
  61       * the network when the network is created.
  62       *
  63       * A numeric string, for compatibility reasons.
  64       *
  65       * @since 4.4.0
  66       * @var string
  67       * @phpstan-var numeric-string
  68       */
  69      private $blog_id = '0';
  70  
  71      /**
  72       * Domain used to set cookies for this network.
  73       *
  74       * @since 4.4.0
  75       * @var string
  76       */
  77      public $cookie_domain = '';
  78  
  79      /**
  80       * Name of this network.
  81       *
  82       * Named "site" vs. "network" for legacy reasons.
  83       *
  84       * @since 4.4.0
  85       * @var string
  86       */
  87      public $site_name = '';
  88  
  89      /**
  90       * Retrieves a network from the database by its ID.
  91       *
  92       * @since 4.4.0
  93       *
  94       * @global wpdb $wpdb WordPress database abstraction object.
  95       *
  96       * @param int $network_id The ID of the network to retrieve.
  97       * @return WP_Network|false The network's object if found. False if not.
  98       */
  99  	public static function get_instance( $network_id ) {
 100          global $wpdb;
 101  
 102          $network_id = (int) $network_id;
 103          if ( ! $network_id ) {
 104              return false;
 105          }
 106  
 107          $_network = wp_cache_get( $network_id, 'networks' );
 108  
 109          if ( false === $_network ) {
 110              $_network = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->site} WHERE id = %d LIMIT 1", $network_id ) );
 111  
 112              if ( empty( $_network ) || is_wp_error( $_network ) ) {
 113                  $_network = -1;
 114              }
 115  
 116              wp_cache_add( $network_id, $_network, 'networks' );
 117          }
 118  
 119          if ( is_numeric( $_network ) ) {
 120              return false;
 121          }
 122  
 123          return new WP_Network( $_network );
 124      }
 125  
 126      /**
 127       * Creates a new WP_Network object.
 128       *
 129       * Will populate object properties from the object provided and assign other
 130       * default properties based on that information.
 131       *
 132       * @since 4.4.0
 133       *
 134       * @param WP_Network|object $network A network object.
 135       */
 136  	public function __construct( $network ) {
 137          foreach ( get_object_vars( $network ) as $key => $value ) {
 138              $this->__set( $key, $value );
 139          }
 140  
 141          $this->_set_site_name();
 142          $this->_set_cookie_domain();
 143      }
 144  
 145      /**
 146       * Getter.
 147       *
 148       * Allows current multisite naming conventions when getting properties.
 149       *
 150       * @since 4.6.0
 151       *
 152       * @param string $key Property to get.
 153       * @return mixed Value of the property. Null if not available.
 154       */
 155  	public function __get( $key ) {
 156          switch ( $key ) {
 157              case 'id':
 158                  return (int) $this->id;
 159              case 'blog_id':
 160                  return (string) $this->get_main_site_id();
 161              case 'site_id':
 162                  return $this->get_main_site_id();
 163          }
 164  
 165          return null;
 166      }
 167  
 168      /**
 169       * Isset-er.
 170       *
 171       * Allows current multisite naming conventions when checking for properties.
 172       *
 173       * @since 4.6.0
 174       *
 175       * @param string $key Property to check if set.
 176       * @return bool Whether the property is set.
 177       */
 178  	public function __isset( $key ) {
 179          switch ( $key ) {
 180              case 'id':
 181              case 'blog_id':
 182              case 'site_id':
 183                  return true;
 184          }
 185  
 186          return false;
 187      }
 188  
 189      /**
 190       * Setter.
 191       *
 192       * Allows current multisite naming conventions while setting properties.
 193       *
 194       * @since 4.6.0
 195       *
 196       * @param string $key   Property to set.
 197       * @param mixed  $value Value to assign to the property.
 198       */
 199  	public function __set( $key, $value ) {
 200          switch ( $key ) {
 201              case 'id':
 202                  $this->id = (int) $value;
 203                  break;
 204              case 'blog_id':
 205              case 'site_id':
 206                  $this->blog_id = (string) $value;
 207                  break;
 208              default:
 209                  $this->$key = $value;
 210          }
 211      }
 212  
 213      /**
 214       * Returns the main site ID for the network.
 215       *
 216       * Internal method used by the magic getter for the 'blog_id' and 'site_id'
 217       * properties.
 218       *
 219       * @since 4.9.0
 220       *
 221       * @return int The ID of the main site.
 222       */
 223  	private function get_main_site_id() {
 224          /**
 225           * Filters the main site ID.
 226           *
 227           * Returning a positive integer will effectively short-circuit the function.
 228           *
 229           * @since 4.9.0
 230           *
 231           * @param int|null   $main_site_id If a positive integer is returned, it is interpreted as the main site ID.
 232           * @param WP_Network $network      The network object for which the main site was detected.
 233           */
 234          $main_site_id = (int) apply_filters( 'pre_get_main_site_id', null, $this );
 235  
 236          if ( 0 < $main_site_id ) {
 237              return $main_site_id;
 238          }
 239  
 240          if ( 0 < (int) $this->blog_id ) {
 241              return (int) $this->blog_id;
 242          }
 243  
 244          if ( ( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' )
 245              && DOMAIN_CURRENT_SITE === $this->domain && PATH_CURRENT_SITE === $this->path )
 246              || ( defined( 'SITE_ID_CURRENT_SITE' ) && (int) SITE_ID_CURRENT_SITE === $this->id )
 247          ) {
 248              if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) {
 249                  $this->blog_id = (string) BLOG_ID_CURRENT_SITE;
 250  
 251                  return (int) $this->blog_id;
 252              }
 253  
 254              if ( defined( 'BLOGID_CURRENT_SITE' ) ) { // Deprecated.
 255                  $this->blog_id = (string) BLOGID_CURRENT_SITE;
 256  
 257                  return (int) $this->blog_id;
 258              }
 259          }
 260  
 261          $site = get_site();
 262          if ( $site->domain === $this->domain && $site->path === $this->path ) {
 263              $main_site_id = (int) $site->id;
 264          } else {
 265  
 266              $main_site_id = get_network_option( $this->id, 'main_site' );
 267              if ( false === $main_site_id ) {
 268                  $_sites       = get_sites(
 269                      array(
 270                          'fields'     => 'ids',
 271                          'number'     => 1,
 272                          'domain'     => $this->domain,
 273                          'path'       => $this->path,
 274                          'network_id' => $this->id,
 275                      )
 276                  );
 277                  $main_site_id = ! empty( $_sites ) ? array_shift( $_sites ) : 0;
 278  
 279                  update_network_option( $this->id, 'main_site', $main_site_id );
 280              }
 281          }
 282  
 283          $this->blog_id = (string) $main_site_id;
 284  
 285          return (int) $this->blog_id;
 286      }
 287  
 288      /**
 289       * Sets the site name assigned to the network if one has not been populated.
 290       *
 291       * @since 4.4.0
 292       */
 293  	private function _set_site_name() {
 294          if ( ! empty( $this->site_name ) ) {
 295              return;
 296          }
 297  
 298          $default         = ucfirst( $this->domain );
 299          $this->site_name = get_network_option( $this->id, 'site_name', $default );
 300      }
 301  
 302      /**
 303       * Sets the cookie domain based on the network domain if one has
 304       * not been populated.
 305       *
 306       * @todo What if the domain of the network doesn't match the current site?
 307       *
 308       * @since 4.4.0
 309       */
 310  	private function _set_cookie_domain() {
 311          if ( ! empty( $this->cookie_domain ) ) {
 312              return;
 313          }
 314          $domain              = parse_url( $this->domain, PHP_URL_HOST );
 315          $this->cookie_domain = is_string( $domain ) ? $domain : $this->domain;
 316          if ( str_starts_with( $this->cookie_domain, 'www.' ) ) {
 317              $this->cookie_domain = substr( $this->cookie_domain, 4 );
 318          }
 319      }
 320  
 321      /**
 322       * Retrieves the closest matching network for a domain and path.
 323       *
 324       * This will not necessarily return an exact match for a domain and path. Instead, it
 325       * breaks the domain and path into pieces that are then used to match the closest
 326       * possibility from a query.
 327       *
 328       * The intent of this method is to match a network during bootstrap for a
 329       * requested site address.
 330       *
 331       * @since 4.4.0
 332       *
 333       * @param string   $domain   Domain to check.
 334       * @param string   $path     Path to check.
 335       * @param int|null $segments Path segments to use. Defaults to null, or the full path.
 336       * @return WP_Network|false Network object if successful. False when no network is found.
 337       */
 338  	public static function get_by_path( $domain = '', $path = '', $segments = null ) {
 339          $domains = array( $domain );
 340          $pieces  = explode( '.', $domain );
 341  
 342          /*
 343           * It's possible one domain to search is 'com', but it might as well
 344           * be 'localhost' or some other locally mapped domain.
 345           */
 346          while ( array_shift( $pieces ) ) {
 347              if ( ! empty( $pieces ) ) {
 348                  $domains[] = implode( '.', $pieces );
 349              }
 350          }
 351  
 352          /*
 353           * If we've gotten to this function during normal execution, there is
 354           * more than one network installed. At this point, who knows how many
 355           * we have. Attempt to optimize for the situation where networks are
 356           * only domains, thus meaning paths never need to be considered.
 357           *
 358           * This is a very basic optimization; anything further could have
 359           * drawbacks depending on the setup, so this is best done per-installation.
 360           */
 361          $using_paths = true;
 362          if ( wp_using_ext_object_cache() ) {
 363              $using_paths = get_networks(
 364                  array(
 365                      'number'       => 1,
 366                      'count'        => true,
 367                      'path__not_in' => '/',
 368                  )
 369              );
 370          }
 371  
 372          $paths = array();
 373          if ( $using_paths ) {
 374              $path_segments = array_filter( explode( '/', trim( $path, '/' ) ) );
 375  
 376              /**
 377               * Filters the number of path segments to consider when searching for a site.
 378               *
 379               * @since 3.9.0
 380               *
 381               * @param int|null $segments The number of path segments to consider. WordPress by default looks at
 382               *                           one path segment. The function default of null only makes sense when you
 383               *                           know the requested path should match a network.
 384               * @param string   $domain   The requested domain.
 385               * @param string   $path     The requested path, in full.
 386               */
 387              $segments = apply_filters( 'network_by_path_segments_count', $segments, $domain, $path );
 388  
 389              if ( ( null !== $segments ) && count( $path_segments ) > $segments ) {
 390                  $path_segments = array_slice( $path_segments, 0, $segments );
 391              }
 392  
 393              while ( count( $path_segments ) ) {
 394                  $paths[] = '/' . implode( '/', $path_segments ) . '/';
 395                  array_pop( $path_segments );
 396              }
 397  
 398              $paths[] = '/';
 399          }
 400  
 401          /**
 402           * Determines a network by its domain and path.
 403           *
 404           * This allows one to short-circuit the default logic, perhaps by
 405           * replacing it with a routine that is more optimal for your setup.
 406           *
 407           * Return null to avoid the short-circuit. Return false if no network
 408           * can be found at the requested domain and path. Otherwise, return
 409           * an object from wp_get_network().
 410           *
 411           * @since 3.9.0
 412           *
 413           * @param null|false|WP_Network $network  Network value to return by path. Default null
 414           *                                        to continue retrieving the network.
 415           * @param string                $domain   The requested domain.
 416           * @param string                $path     The requested path, in full.
 417           * @param int|null              $segments The suggested number of paths to consult.
 418           *                                        Default null, meaning the entire path was to be consulted.
 419           * @param string[]              $paths    Array of paths to search for, based on `$path` and `$segments`.
 420           */
 421          $pre = apply_filters( 'pre_get_network_by_path', null, $domain, $path, $segments, $paths );
 422          if ( null !== $pre ) {
 423              return $pre;
 424          }
 425  
 426          if ( ! $using_paths ) {
 427              $networks = get_networks(
 428                  array(
 429                      'number'     => 1,
 430                      'orderby'    => array(
 431                          'domain_length' => 'DESC',
 432                      ),
 433                      'domain__in' => $domains,
 434                  )
 435              );
 436  
 437              if ( ! empty( $networks ) ) {
 438                  return array_shift( $networks );
 439              }
 440  
 441              return false;
 442          }
 443  
 444          $networks = get_networks(
 445              array(
 446                  'orderby'    => array(
 447                      'domain_length' => 'DESC',
 448                      'path_length'   => 'DESC',
 449                  ),
 450                  'domain__in' => $domains,
 451                  'path__in'   => $paths,
 452              )
 453          );
 454  
 455          /*
 456           * Domains are sorted by length of domain, then by length of path.
 457           * The domain must match for the path to be considered. Otherwise,
 458           * a network with the path of / will suffice.
 459           */
 460          $found = false;
 461          foreach ( $networks as $network ) {
 462              if ( ( $network->domain === $domain ) || ( "www.{$network->domain}" === $domain ) ) {
 463                  if ( in_array( $network->path, $paths, true ) ) {
 464                      $found = true;
 465                      break;
 466                  }
 467              }
 468              if ( '/' === $network->path ) {
 469                  $found = true;
 470                  break;
 471              }
 472          }
 473  
 474          if ( true === $found ) {
 475              return $network;
 476          }
 477  
 478          return false;
 479      }
 480  }


Generated : Thu Jul 9 08:20:14 2026 Cross-referenced by PHPXref