Multisite



Multisite

0 0


Multisite-Talk

A flexible, changing talk on WordPress Multisite

On Github jeremyfelt / Multisite-Talk

Multisite

@jeremyfelt

History

  • History as context.
  • b2 - Michel Valdrighi, 2001.
  • WordPress - early 2003
  • b2-smarty, then b2++ - Donncha Ó Caoimh
  • WordPress first release, Donncha joins dev team with goal of merge
  • WordPress Multi User
  • Automattic, WP.com work starts - WordPress MU repository
  • Community builds, WP.com drives primary use case.
  • 2009, Matt announces merge
  • 2010, January - [12602] introduces ms-settings.php
  • 2010, WordPress 3.0 - straight no chaser.

WordPress 3.0 "Thelonious"

June 17, 2010

Use it to power one site, or 10 million.Straight, no chaser.

Structure

Context

Extension

* Provide the structure of multisite by showing what happens behind the scenes when a multisite request is made. * Empower with a sense of awareness by walking through sunrise possibilities. * Give you some immediate tips on enhancing your current multisite setup through available plugins.
  • wp_options
  • wp_posts
  • wp_postmeta
  • wp_comments
  • wp_commentmeta
  • wp_terms
  • wp_term_taxonomy
  • wp_term_relationships
  • wp_users
  • wp_usermeta
  • wp_options
  • wp_posts
  • wp_postmeta
  • wp_comments
  • wp_commentmeta
  • wp_terms
  • wp_term_taxonomy
  • wp_term_relationships
  • wp_users
  • wp_usermeta
  • wp_blogs
  • wp_blog_versions
  • wp_registration_log
  • wp_signups
  • wp_site
  • wp_sitemeta
  • wp_options
  • wp_posts
  • wp_postmeta
  • wp_comments
  • wp_commentmeta
  • wp_terms
  • wp_term_taxonomy
  • wp_term_relationships
  • wp_users
  • wp_usermeta
  • wp_blogs
  • wp_blog_versions
  • wp_registration_log
  • wp_signups
  • wp_site
  • wp_sitemeta
  • wp_2_options
  • wp_2_posts
  • wp_2_postmeta
  • wp_2_comments
  • wp_2_commentmeta
  • wp_2_terms
  • wp_2_term_taxonomy
  • wp_2_term_relationships
  • wp_3_options
  • wp_3_posts
  • wp_3_postmeta
  • wp_3_comments
  • wp_3_commentmeta
  • wp_3_terms
  • wp_3_term_taxonomy
  • wp_3_term_relationships
  • wp_4_options
  • wp_4_posts
  • wp_4_postmeta
  • wp_4_comments
  • wp_4_commentmeta
  • wp_4_terms
  • wp_4_term_taxonomy
  • wp_4_term_relationships
  • wp_options
  • wp_posts
  • wp_postmeta
  • wp_comments
  • wp_commentmeta
  • wp_terms
  • wp_term_taxonomy
  • wp_term_relationships
  • wp_users
  • wp_usermeta
  • wp_blogs
  • wp_blog_versions
  • wp_registration_log
  • wp_signups
  • wp_site
  • wp_sitemeta
  • wp_2_options
  • wp_2_posts
  • wp_2_postmeta
  • wp_2_comments
  • wp_2_commentmeta
  • wp_2_terms
  • wp_2_term_taxonomy
  • wp_2_term_relationships
  • wp_3_options
  • wp_3_posts
  • wp_3_postmeta
  • wp_3_comments
  • wp_3_commentmeta
  • wp_3_terms
  • wp_3_term_taxonomy
  • wp_3_term_relationships
  • wp_4_options
  • wp_4_posts
  • wp_4_postmeta
  • wp_4_comments
  • wp_4_commentmeta
  • wp_4_terms
  • wp_4_term_taxonomy
  • wp_4_term_relationships
  • wp_5_options
  • wp_5_posts
  • wp_5_postmeta
  • wp_5_comments
  • wp_5_commentmeta
  • wp_5_terms
  • wp_5_term_taxonomy
  • wp_5_term_relationships
  • wp_6_options
  • wp_6_posts
  • wp_6_postmeta
  • wp_6_comments
  • wp_6_commentmeta
  • wp_6_terms
  • wp_6_term_taxonomy
  • wp_6_term_relationships
  • wp_7_options
  • wp_7_posts
  • wp_7_postmeta
  • wp_7_comments
  • wp_7_commentmeta
  • wp_7_terms
  • wp_7_term_taxonomy
  • wp_7_term_relationships
  • wp_options
  • wp_posts
  • wp_postmeta
  • wp_comments
  • wp_commentmeta
  • wp_terms
  • wp_term_taxonomy
  • wp_term_relationships
  • wp_users
  • wp_usermeta
  • wp_blogs
  • wp_blog_versions
  • wp_registration_log
  • wp_signups
  • wp_site
  • wp_sitemeta
  • wp_2_options
  • wp_2_posts
  • wp_2_postmeta
  • wp_2_comments
  • wp_2_commentmeta
  • wp_2_terms
  • wp_2_term_taxonomy
  • wp_2_term_relationships
  • wp_3_options
  • wp_3_posts
  • wp_3_postmeta
  • wp_3_comments
  • wp_3_commentmeta
  • wp_3_terms
  • wp_3_term_taxonomy
  • wp_3_term_relationships
  • wp_4_options
  • wp_4_posts
  • wp_4_postmeta
  • wp_4_comments
  • wp_4_commentmeta
  • wp_4_terms
  • wp_4_term_taxonomy
  • wp_4_term_relationships
  • wp_5_options
  • wp_5_posts
  • wp_5_postmeta
  • wp_5_comments
  • wp_5_commentmeta
  • wp_5_terms
  • wp_5_term_taxonomy
  • wp_5_term_relationships
  • wp_6_options
  • wp_6_posts
  • wp_6_postmeta
  • wp_6_comments
  • wp_6_commentmeta
  • wp_6_terms
  • wp_6_term_taxonomy
  • wp_6_term_relationships
  • wp_7_options
  • wp_7_posts
  • wp_7_postmeta
  • wp_7_comments
  • wp_7_commentmeta
  • wp_7_terms
  • wp_7_term_taxonomy
  • wp_7_term_relationships
  • wp_8_options
  • wp_8_posts
  • wp_8_postmeta
  • wp_8_comments
  • wp_8_commentmeta
  • wp_8_terms
  • wp_8_term_taxonomy
  • wp_8_term_relationships
  • wp_9_options
  • wp_9_posts
  • wp_9_postmeta
  • wp_9_comments
  • wp_9_commentmeta
  • wp_9_terms
  • wp_9_term_taxonomy
  • wp_9_term_relationships
  • wp_10_options
  • wp_10_posts
  • wp_10_postmeta
  • wp_10_comments
  • wp_10_commentmeta
  • wp_10_terms
  • wp_10_term_taxonomy
  • wp_10_term_relationships
  • wp_11_options
  • wp_11_posts
  • wp_11_postmeta
  • wp_11_comments
  • wp_11_commentmeta
  • wp_11_terms
  • wp_11_term_taxonomy
  • wp_11_term_relationships
  • wp_12_options
  • wp_12_posts
  • wp_12_postmeta
  • wp_12_comments
  • wp_12_commentmeta
  • wp_12_terms
  • wp_12_term_taxonomy
  • wp_12_term_relationships
  • wp_13_options
  • wp_13_posts
  • wp_13_postmeta
  • wp_13_comments
  • wp_13_commentmeta
  • wp_13_terms
  • wp_13_term_taxonomy
  • wp_13_term_relationships
  • wp_14_options
  • wp_14_posts
  • wp_14_postmeta
  • wp_14_comments
  • wp_14_commentmeta
  • wp_14_terms
  • wp_14_term_taxonomy
  • wp_14_term_relationships
  • wp_options
  • wp_posts
  • wp_postmeta
  • wp_comments
  • wp_commentmeta
  • wp_terms
  • wp_term_taxonomy
  • wp_term_relationships
  • wp_users
  • wp_usermeta
  • wp_blogs
  • wp_blog_versions
  • wp_registration_log
  • wp_signups
  • wp_site
  • wp_sitemeta
  • wp_2_options
  • wp_2_posts
  • wp_2_postmeta
  • wp_2_comments
  • wp_2_commentmeta
  • wp_2_terms
  • wp_2_term_taxonomy
  • wp_2_term_relationships
  • wp_3_options
  • wp_3_posts
  • wp_3_postmeta
  • wp_3_comments
  • wp_3_commentmeta
  • wp_3_terms
  • wp_3_term_taxonomy
  • wp_3_term_relationships
  • wp_4_options
  • wp_4_posts
  • wp_4_postmeta
  • wp_4_comments
  • wp_4_commentmeta
  • wp_4_terms
  • wp_4_term_taxonomy
  • wp_4_term_relationships
  • wp_5_options
  • wp_5_posts
  • wp_5_postmeta
  • wp_5_comments
  • wp_5_commentmeta
  • wp_5_terms
  • wp_5_term_taxonomy
  • wp_5_term_relationships
  • wp_6_options
  • wp_6_posts
  • wp_6_postmeta
  • wp_6_comments
  • wp_6_commentmeta
  • wp_6_terms
  • wp_6_term_taxonomy
  • wp_6_term_relationships
  • wp_7_options
  • wp_7_posts
  • wp_7_postmeta
  • wp_7_comments
  • wp_7_commentmeta
  • wp_7_terms
  • wp_7_term_taxonomy
  • wp_7_term_relationships
  • wp_8_options
  • wp_8_posts
  • wp_8_postmeta
  • wp_8_comments
  • wp_8_commentmeta
  • wp_8_terms
  • wp_8_term_taxonomy
  • wp_8_term_relationships
  • wp_9_options
  • wp_9_posts
  • wp_9_postmeta
  • wp_9_comments
  • wp_9_commentmeta
  • wp_9_terms
  • wp_9_term_taxonomy
  • wp_9_term_relationships
  • wp_10_options
  • wp_10_posts
  • wp_10_postmeta
  • wp_10_comments
  • wp_10_commentmeta
  • wp_10_terms
  • wp_10_term_taxonomy
  • wp_10_term_relationships
  • wp_11_options
  • wp_11_posts
  • wp_11_postmeta
  • wp_11_comments
  • wp_11_commentmeta
  • wp_11_terms
  • wp_11_term_taxonomy
  • wp_11_term_relationships
  • wp_12_options
  • wp_12_posts
  • wp_12_postmeta
  • wp_12_comments
  • wp_12_commentmeta
  • wp_12_terms
  • wp_12_term_taxonomy
  • wp_12_term_relationships
  • wp_13_options
  • wp_13_posts
  • wp_13_postmeta
  • wp_13_comments
  • wp_13_commentmeta
  • wp_13_terms
  • wp_13_term_taxonomy
  • wp_13_term_relationships
  • wp_14_options
  • wp_14_posts
  • wp_14_postmeta
  • wp_14_comments
  • wp_14_commentmeta
  • wp_14_terms
  • wp_14_term_taxonomy
  • wp_14_term_relationships
  • wp_15_options
  • wp_15_posts
  • wp_15_postmeta
  • wp_15_comments
  • wp_15_commentmeta
  • wp_15_terms
  • wp_15_term_taxonomy
  • wp_15_term_relationships
  • wp_16_options
  • wp_16_posts
  • wp_16_postmeta
  • wp_16_comments
  • wp_16_commentmeta
  • wp_16_terms
  • wp_16_term_taxonomy
  • wp_16_term_relationships
  • wp_17_options
  • wp_17_posts
  • wp_17_postmeta
  • wp_17_comments
  • wp_17_commentmeta
  • wp_17_terms
  • wp_17_term_taxonomy
  • wp_17_term_relationships
  • wp_18_options
  • wp_18_posts
  • wp_18_postmeta
  • wp_18_comments
  • wp_18_commentmeta
  • wp_18_terms
  • wp_18_term_taxonomy
  • wp_18_term_relationships
  • wp_19_options
  • wp_19_posts
  • wp_19_postmeta
  • wp_19_comments
  • wp_19_commentmeta
  • wp_19_terms
  • wp_19_term_taxonomy
  • wp_19_term_relationships
  • wp_20_options
  • wp_20_posts
  • wp_20_postmeta
  • wp_20_comments
  • wp_20_commentmeta
  • wp_20_terms
  • wp_20_term_taxonomy
  • wp_20_term_relationships
  • wp_21_options
  • wp_21_posts
  • wp_21_postmeta
  • wp_21_comments
  • wp_21_commentmeta
  • wp_21_terms
  • wp_21_term_taxonomy
  • wp_21_term_relationships
  • wp_22_options
  • wp_22_posts
  • wp_22_postmeta
  • wp_22_comments
  • wp_22_commentmeta
  • wp_22_terms
  • wp_22_term_taxonomy
  • wp_22_term_relationships
  • wp_23_options
  • wp_23_posts
  • wp_23_postmeta
  • wp_23_comments
  • wp_23_commentmeta
  • wp_23_terms
  • wp_23_term_taxonomy
  • wp_23_term_relationships
Multisite is basically using the global blogs and sites tables to figure out what other set of tables to use for the request. After that, almost everything it does is exactly the same as single site for most page loads. Remember this as it's key to understanding many things in multisite and we'll touch on it again later.

Network: $current_site

$current_site->id;        // The ID of the network in the wp_site table.
$current_site->domain;
$current_site->path;      // Uses leading and trailing slashes - '/path/'
$current_site->blog_id;   // The blog_id of the network's main site.
mysql> SELECT * FROM wp_site;
+----+---------------------------+------+
| id | domain                    | path |
+----+---------------------------+------+
|  1 | jeremyfelt.com            | /    |
+----+---------------------------+------+
1 row in set (0.00 sec)

Site: $current_blog

$current_blog->blog_id; // The ID of the site in the wp_blogs table.
$current_blog->site_id; // The ID of the site's network in the wp_site table.
$current_blog->domain;
$current_blog->path;    // Uses leading and trailing slashes - '/path/'
$current_blog->....     // More data directly from the wp_blogs record.
mysql> SELECT blog_id, site_id, domain, path FROM wp_blogs;
+---------+---------+----------------+----------+
| blog_id | site_id | domain         | path     |
+---------+---------+----------------+----------+
|       1 |       1 | jeremyfelt.com | /        |
|       2 |       1 | jeremyfelt.com | /photos/ |
+---------+---------+----------------+----------+
2 rows in set (0.00 sec)

get_site_by_path()

/**
 * Retrieve a site object by its domain and path.
 *
 * @param string   $domain   Domain to check.
 * @param string   $path     Path to check.
 * @param int|null $segments Path segments to use.
 */
function get_site_by_path( $domain, $path, $segments = null ) {

  // Use $wpdb to find matching site data from wp_blogs
  $site = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs 
    WHERE domain = %s AND path = %s", $domains[0], $paths[0] ) );

}

get_network_by_path()

/**
 * Retrieve a network object by its domain and path.
 *
 * @param string   $domain   Domain to check.
 * @param string   $path     Path to check.
 * @param int|null $segments Path segments to use.
 */
function get_network_by_path( $domain, $path, $segments = null ) {

  // Use $wpdb to find matching network data from wp_site
  $networks = $wpdb->get_results( "SELECT id, domain, path FROM $wpdb->site
    WHERE domain IN ($search_domains) AND path IN ($search_paths)
    ORDER BY CHAR_LENGTH(domain) DESC, CHAR_LENGTH(path) DESC" );

}

wp-includes/ms-settings.php

$domain = strtolower( stripslashes( $_SERVER['HTTP_HOST'] ) );

if ( substr( $domain, -3 ) == ':80' ) {
	$domain = substr( $domain, 0, -3 );
	$_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -3 );
} elseif ( substr( $domain, -4 ) == ':443' ) {
	$domain = substr( $domain, 0, -4 );
	$_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -4 );
}

$path = stripslashes( $_SERVER['REQUEST_URI'] );

if ( is_admin() ) {
	$path = preg_replace( '#(.*)/wp-admin/.*#', '$1/', $path );
}
list( $path ) = explode( '?', $path );

wp-includes/ms-settings.php

if ( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' ) ) {

  $current_site = new stdClass;
  $current_site->id = defined( 'SITE_ID_CURRENT_SITE' ) ? SITE_ID_CURRENT_SITE : 1;
  $current_site->domain = DOMAIN_CURRENT_SITE;
  $current_site->path = PATH_CURRENT_SITE;

  if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) {
    $current_site->blog_id = BLOG_ID_CURRENT_SITE;
  }

wp-config.php

define( 'DOMAIN_CURRENT_SITE', 'jeremyfelt.com' );
define( 'PATH_CURRENT_SITE',   '/'              );
define( 'SITE_ID_CURRENT_SITE', 1               );
define( 'BLOG_ID_CURRENT_SITE', 1               );
This configuration cares nothing for whether this is a subdirectory or subdomain installation of multisite.

Subdirectory Configuration

All sites on a network have the same domain and different paths

Populate $current_site first

If more than one network exists, use get_network_by_path()

Populate $current_blog using get_site_by_path()

mysql> SELECT blog_id, site_id, domain, path FROM wp_blogs;
+---------+---------+----------------+----------+
| blog_id | site_id | domain         | path     |
+---------+---------+----------------+----------+
|       1 |       1 | jeremyfelt.com | /        |
|       2 |       1 | jeremyfelt.com | /photos/ |
+---------+---------+----------------+----------+
2 rows in set (0.00 sec)

Subdomain Configuration

Sites on a network have different subdomains

Sites can also have different paths

Populate $current_blog first using get_site_by_path()

Populate $current_site using the site_id attached to the $current_blog object

mysql> SELECT blog_id, site_id, domain, path FROM wp_blogs;
+---------+---------+-----------------------+----------+
| blog_id | site_id | domain                | path     |
+---------+---------+-----------------------+----------+
|       1 |       1 | jeremyfelt.com        | /        |
|       2 |       1 | photos.jeremyfelt.com | /        |
|       3 |       2 | alsoadomain.com       | /howdy/  |
+---------+---------+-----------------------+----------+
3 rows in set (0.00 sec)
  • wp_options
  • wp_posts
  • wp_postmeta
  • wp_comments
  • wp_commentmeta
  • wp_terms
  • wp_term_taxonomy
  • wp_term_relationships
  • wp_users
  • wp_usermeta
  • wp_blogs
  • wp_blog_versions
  • wp_registration_log
  • wp_signups
  • wp_site
  • wp_sitemeta
  • wp_2_options
  • wp_2_posts
  • wp_2_postmeta
  • wp_2_comments
  • wp_2_commentmeta
  • wp_2_terms
  • wp_2_term_taxonomy
  • wp_2_term_relationships
  • wp_3_options
  • wp_3_posts
  • wp_3_postmeta
  • wp_3_comments
  • wp_3_commentmeta
  • wp_3_terms
  • wp_3_term_taxonomy
  • wp_3_term_relationships
  • wp_4_options
  • wp_4_posts
  • wp_4_postmeta
  • wp_4_comments
  • wp_4_commentmeta
  • wp_4_terms
  • wp_4_term_taxonomy
  • wp_4_term_relationships
  • wp_5_options
  • wp_5_posts
  • wp_5_postmeta
  • wp_5_comments
  • wp_5_commentmeta
  • wp_5_terms
  • wp_5_term_taxonomy
  • wp_5_term_relationships
  • wp_6_options
  • wp_6_posts
  • wp_6_postmeta
  • wp_6_comments
  • wp_6_commentmeta
  • wp_6_terms
  • wp_6_term_taxonomy
  • wp_6_term_relationships
  • wp_7_options
  • wp_7_posts
  • wp_7_postmeta
  • wp_7_comments
  • wp_7_commentmeta
  • wp_7_terms
  • wp_7_term_taxonomy
  • wp_7_term_relationships
  • wp_8_options
  • wp_8_posts
  • wp_8_postmeta
  • wp_8_comments
  • wp_8_commentmeta
  • wp_8_terms
  • wp_8_term_taxonomy
  • wp_8_term_relationships
  • wp_9_options
  • wp_9_posts
  • wp_9_postmeta
  • wp_9_comments
  • wp_9_commentmeta
  • wp_9_terms
  • wp_9_term_taxonomy
  • wp_9_term_relationships
  • wp_10_options
  • wp_10_posts
  • wp_10_postmeta
  • wp_10_comments
  • wp_10_commentmeta
  • wp_10_terms
  • wp_10_term_taxonomy
  • wp_10_term_relationships
  • wp_11_options
  • wp_11_posts
  • wp_11_postmeta
  • wp_11_comments
  • wp_11_commentmeta
  • wp_11_terms
  • wp_11_term_taxonomy
  • wp_11_term_relationships
  • wp_12_options
  • wp_12_posts
  • wp_12_postmeta
  • wp_12_comments
  • wp_12_commentmeta
  • wp_12_terms
  • wp_12_term_taxonomy
  • wp_12_term_relationships
  • wp_13_options
  • wp_13_posts
  • wp_13_postmeta
  • wp_13_comments
  • wp_13_commentmeta
  • wp_13_terms
  • wp_13_term_taxonomy
  • wp_13_term_relationships
  • wp_14_options
  • wp_14_posts
  • wp_14_postmeta
  • wp_14_comments
  • wp_14_commentmeta
  • wp_14_terms
  • wp_14_term_taxonomy
  • wp_14_term_relationships
  • wp_15_options
  • wp_15_posts
  • wp_15_postmeta
  • wp_15_comments
  • wp_15_commentmeta
  • wp_15_terms
  • wp_15_term_taxonomy
  • wp_15_term_relationships
  • wp_16_options
  • wp_16_posts
  • wp_16_postmeta
  • wp_16_comments
  • wp_16_commentmeta
  • wp_16_terms
  • wp_16_term_taxonomy
  • wp_16_term_relationships
  • wp_17_options
  • wp_17_posts
  • wp_17_postmeta
  • wp_17_comments
  • wp_17_commentmeta
  • wp_17_terms
  • wp_17_term_taxonomy
  • wp_17_term_relationships
  • wp_18_options
  • wp_18_posts
  • wp_18_postmeta
  • wp_18_comments
  • wp_18_commentmeta
  • wp_18_terms
  • wp_18_term_taxonomy
  • wp_18_term_relationships
  • wp_19_options
  • wp_19_posts
  • wp_19_postmeta
  • wp_19_comments
  • wp_19_commentmeta
  • wp_19_terms
  • wp_19_term_taxonomy
  • wp_19_term_relationships
  • wp_20_options
  • wp_20_posts
  • wp_20_postmeta
  • wp_20_comments
  • wp_20_commentmeta
  • wp_20_terms
  • wp_20_term_taxonomy
  • wp_20_term_relationships
  • wp_21_options
  • wp_21_posts
  • wp_21_postmeta
  • wp_21_comments
  • wp_21_commentmeta
  • wp_21_terms
  • wp_21_term_taxonomy
  • wp_21_term_relationships
  • wp_22_options
  • wp_22_posts
  • wp_22_postmeta
  • wp_22_comments
  • wp_22_commentmeta
  • wp_22_terms
  • wp_22_term_taxonomy
  • wp_22_term_relationships
  • wp_23_options
  • wp_23_posts
  • wp_23_postmeta
  • wp_23_comments
  • wp_23_commentmeta
  • wp_23_terms
  • wp_23_term_taxonomy
  • wp_23_term_relationships
Multisite is basically using the global blogs and sites tables to figure out what other set of tables to use for the request. After that, almost everything it does is exactly the same as single site for most page loads. Remember this as it's key to understanding many things in multisite and we'll touch on it again later.

wp_usermeta

mysql> SELECT * FROM wp_usermeta WHERE meta_key LIKE '%_capabilities';
+----------+---------+-------------------+---------------------------------+
| umeta_id | user_id | meta_key          | meta_value                      |
+----------+---------+-------------------+---------------------------------+
|       10 |       1 | wp_capabilities   | a:1:{s:13:"administrator";b:1;} |
|       32 |       2 | wp_capabilities   | a:1:{s:13:"administrator";b:1;} |
|       47 |       1 | wp_2_capabilities | a:1:{s:13:"administrator";b:1;} |
|       54 |       2 | wp_2_capabilities | a:1:{s:11:"contributor";b:1;}   |
|       58 |       3 | wp_2_capabilities | a:1:{s:6:"editor";b:1;}         |
|       60 |       3 | wp_capabilities   | a:1:{s:6:"author";b:1;}         |
+----------+---------+-------------------+---------------------------------+
6 rows in set (0.00 sec)

wp-includes/ms-settings.php

/** Include Multisite initialization functions */
require_once( ABSPATH . WPINC . '/ms-load.php' );
require_once( ABSPATH . WPINC . '/ms-default-constants.php' );

if ( defined( 'SUNRISE' ) ) {
	// Load custom logic to find a network and site.
	include_once( WP_CONTENT_DIR . '/sunrise.php' );
}

ms_subdomain_constants();

if ( !isset( $current_site ) || !isset( $current_blog ) ) {
	// Default core logic to find a network and site.
}

$wpdb->set_prefix( $table_prefix, false );
$wpdb->set_blog_id( $current_blog->blog_id, $current_blog->site_id );
$table_prefix = $wpdb->get_blog_prefix();
sunrise allows you to hook in before anything else is done in WordPress and determine what this page load will become. This is where you can do very custom, purposeful things that could normally be handled further down in the stack (nginx config) or up in the stack (WordPress plugin.)

wp-content/sunrise.php

//Capture the domain and path from the current request
$req_domain    = $_SERVER['HTTP_HOST'];
$req_uri       = trim( $_SERVER['REQUEST_URI'], '/' );

// We currently support one subdirectory deep, and therefore
// only look at the first path level.
$req_uri_parts = explode( '/', $req_uri );
$req_path = $req_uri_parts[0] . '/';

wp_cache_add_global_groups( 'wsuwp:network' );
wp_cache_add_global_groups( 'wsuwp:site' );

// If we're dealing with a root domain, we want to leave it
// at a path of '/'
if ( '/' !== $req_path ) {
	$req_path = '/' . $req_path;
}

if ( ! $current_blog = wp_cache_get( $req_domain . $req_path, 'wsuwp:site' ) ) {
Caching the request makes all future lookups easy. We clear the cache for a domain/path combination whenever a new site is created, and conflicts are less possible the other way around - when a page is created.

wp-content/sunrise.php

// Start with the assumption that SSL is available for this domain.
$current_blog->ssl_enabled = true;
// We're looking for a base option name of foo.bar.com_ssl_disabled
$ssl_domain_check = $requested_domain . '_ssl_disabled';
$non_ssl_domain = $wpdb->get_row( $wpdb->prepare( "SELECT option_id FROM [...]" ) );

if ( is_object( $non_ssl_domain ) ) {
	$current_blog->ssl_enabled = false;
}

wp_cache_add( $req_domain . $req_path, $current_blog, 'wsuwp:site', 60 * 60 * 12 );
if ( isset( $current_blog->ssl_enabled ) && true === $current_blog->ssl_enabled ) {
	define( 'FORCE_SSL_ADMIN', true );
	define( 'FORCE_SSL_LOGIN', true );
}
We also check to see if the domain supports HTTPS. We assume by default that it does and then do a quick lookup to determine if it has been flagged as not having a cert yet.

Context

switch_to_blog( $id )

switch_to_blog( $id )

$GLOBALS['_wp_switched_stack'][] = $GLOBALS['blog_id'];
// ...
$GLOBALS['switched'] = true;

Store a record of the current context in an array that we can walk back through.

switch_to_blog( $id )

$wpdb->set_blog_id( $new_blog );
$GLOBALS['table_prefix'] = $wpdb->get_blog_prefix();
$prev_blog_id = $GLOBALS['blog_id'];
$GLOBALS['blog_id'] = $new_blog;

Context changes:

  • $blog_id property of $wpdb
  • Database table prefix used by $wpdb to wp_#_ from wp_
  • Global $blog_id

switch_to_blog( $id )

wp_cache_init();
wp_cache_add_global_groups( $global_groups );
wp_cache_add_non_persistent_groups( array( ... ) );

Context changes:

  • Uses the global $table_prefix to reinitialize object cache with keys for the switched site.

switch_to_blog( $id )

$wp_roles->reinit();
$current_user = wp_get_current_user();
$current_user->for_blog( $new_blog );

Context changes:

  • Uses $wpdb->get_blog_prefix() to set a prefix for grabbing wp_#_user_roles from get_option()

switch_to_blog( $id )

// Delete the rewrite_rules option from
// the switched site. Good!
delete_option( 'rewrite_rules' );

// Build the permalink structure in the
// context of the main site. Bad!
$this->rewrite_rules();

// Update the rewrite_rules option for the
// switched site. Horrible!
update_option( 'rewrite_rules', $this->rules );

Does not change the context of rewrite rules.

https://jeremyfelt.com/multisite-rewrite-rules/

switch_to_blog( $id )

Does not change the context of code.

Only the theme and plugins activated for the original site will be available.

restore_current_blog()

if ( empty( $GLOBALS['_wp_switched_stack'] ) )
	return false;

$blog = array_pop( $GLOBALS['_wp_switched_stack'] );

// ...

$wpdb->set_blog_id( $blog );
$prev_blog_id = $GLOBALS['blog_id'];
$GLOBALS['blog_id'] = $blog;
$GLOBALS['table_prefix'] = $wpdb->get_blog_prefix();

Restore context to the last used site via $GLOBALS['_wp_switched_stack'].

Using the global _wp_switched_stack WP maintains, we're able to switch back down to where we started. Can be useful to loop this until it returns false.

ms_is_switched()

// Loop until $GLOBALS['_wp_switched_stack'] is clear.
while ( ms_is_switched() ) {
	restore_current_blog();
}

Determine if context is switched and when we're back to normal.

is_main_site()

function is_main_site( $site_id = null ) {
	// This is the current network's information
	global $current_site;

	if ( ! is_multisite() )
		return true;

	if ( ! $site_id )
		$site_id = get_current_blog_id();

	return (int) $site_id === (int) $current_site->blog_id;
}

is_main_network()

function is_main_network( $network_id = null ) {
    $current_network_id = (int) get_current_site()->id;

    if ( ! $network_id )
      $network_id = $current_network_id;

    if ( defined( 'PRIMARY_NETWORK_ID' ) )
      return $network_id === (int) PRIMARY_NETWORK_ID;

    if ( 1 === $current_network_id )
      return $network_id === $current_network_id;

    if ( $primary_network_id )
      return $network_id === $primary_network_id;

    $primary_network_id = $wpdb->get_var( "SELECT id FROM $wpdb->site..." );

    return $network_id === $primary_network_id;
}

get_main_network_id() will be available in 4.3

get_blog_details()

get_current_site()

Extension

Must Use Plugins

wp-content/mu-plugins/

Domain "Mapping"

Mercator - https://github.com/humanmade/Mercator

Multiple Networks

WP Multi Network - https://wordpress.org/plugins/wp-multi-network/

HyperDB

https://wordpress.org/plugins/hyperdb/

  • wp_options
  • wp_posts
  • wp_postmeta
  • wp_comments
  • wp_commentmeta
  • wp_terms
  • wp_term_taxonomy
  • wp_term_relationships
  • wp_users
  • wp_usermeta
  • wp_blogs
  • wp_blog_versions
  • wp_registration_log
  • wp_signups
  • wp_site
  • wp_sitemeta
  • wp_2_options
  • wp_2_posts
  • wp_2_postmeta
  • wp_2_comments
  • wp_2_commentmeta
  • wp_2_terms
  • wp_2_term_taxonomy
  • wp_2_term_relationships
  • wp_3_options
  • wp_3_posts
  • wp_3_postmeta
  • wp_3_comments
  • wp_3_commentmeta
  • wp_3_terms
  • wp_3_term_taxonomy
  • wp_3_term_relationships
  • wp_4_options
  • wp_4_posts
  • wp_4_postmeta
  • wp_4_comments
  • wp_4_commentmeta
  • wp_4_terms
  • wp_4_term_taxonomy
  • wp_4_term_relationships
  • wp_5_options
  • wp_5_posts
  • wp_5_postmeta
  • wp_5_comments
  • wp_5_commentmeta
  • wp_5_terms
  • wp_5_term_taxonomy
  • wp_5_term_relationships
  • wp_6_options
  • wp_6_posts
  • wp_6_postmeta
  • wp_6_comments
  • wp_6_commentmeta
  • wp_6_terms
  • wp_6_term_taxonomy
  • wp_6_term_relationships
  • wp_7_options
  • wp_7_posts
  • wp_7_postmeta
  • wp_7_comments
  • wp_7_commentmeta
  • wp_7_terms
  • wp_7_term_taxonomy
  • wp_7_term_relationships
  • wp_8_options
  • wp_8_posts
  • wp_8_postmeta
  • wp_8_comments
  • wp_8_commentmeta
  • wp_8_terms
  • wp_8_term_taxonomy
  • wp_8_term_relationships
  • wp_9_options
  • wp_9_posts
  • wp_9_postmeta
  • wp_9_comments
  • wp_9_commentmeta
  • wp_9_terms
  • wp_9_term_taxonomy
  • wp_9_term_relationships
  • wp_10_options
  • wp_10_posts
  • wp_10_postmeta
  • wp_10_comments
  • wp_10_commentmeta
  • wp_10_terms
  • wp_10_term_taxonomy
  • wp_10_term_relationships
  • wp_11_options
  • wp_11_posts
  • wp_11_postmeta
  • wp_11_comments
  • wp_11_commentmeta
  • wp_11_terms
  • wp_11_term_taxonomy
  • wp_11_term_relationships
  • wp_12_options
  • wp_12_posts
  • wp_12_postmeta
  • wp_12_comments
  • wp_12_commentmeta
  • wp_12_terms
  • wp_12_term_taxonomy
  • wp_12_term_relationships
  • wp_13_options
  • wp_13_posts
  • wp_13_postmeta
  • wp_13_comments
  • wp_13_commentmeta
  • wp_13_terms
  • wp_13_term_taxonomy
  • wp_13_term_relationships
  • wp_14_options
  • wp_14_posts
  • wp_14_postmeta
  • wp_14_comments
  • wp_14_commentmeta
  • wp_14_terms
  • wp_14_term_taxonomy
  • wp_14_term_relationships
  • wp_15_options
  • wp_15_posts
  • wp_15_postmeta
  • wp_15_comments
  • wp_15_commentmeta
  • wp_15_terms
  • wp_15_term_taxonomy
  • wp_15_term_relationships
  • wp_16_options
  • wp_16_posts
  • wp_16_postmeta
  • wp_16_comments
  • wp_16_commentmeta
  • wp_16_terms
  • wp_16_term_taxonomy
  • wp_16_term_relationships
  • wp_17_options
  • wp_17_posts
  • wp_17_postmeta
  • wp_17_comments
  • wp_17_commentmeta
  • wp_17_terms
  • wp_17_term_taxonomy
  • wp_17_term_relationships
  • wp_18_options
  • wp_18_posts
  • wp_18_postmeta
  • wp_18_comments
  • wp_18_commentmeta
  • wp_18_terms
  • wp_18_term_taxonomy
  • wp_18_term_relationships

Object Caching

Future

  • WP_Site, WP_Network, WP_Site_Query, WP_Network_Query
  • Improved network admin UI/UX
  • Established network types

Multisite

Office Hours: Tuesday, 20:00 UTC in #core-multisite

Slides: jeremyfelt.com/wcyvr-2015/

@jeremyfelt

Multisite @jeremyfelt