Multisite!


@jeremyfelt

Structure of multisite and the bootstrap process.

How plugins and themes are loaded.

Importance of context.

Common solutions to missing features.

Router of Requests

* 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

wp_#_tablename

wp_#_capabilities

wp_2_capabilities | a:1:{s:11:"contributor",b:1;}
wp_5_capabilities | a:1:{s:13:"administrator",b:1}

wp-content/uploads/sites/#/


[jeremyfelt@wsuwp www]$ ls wp-content/uploads/sites

1     1040  1080  1122  1162  1202  1251  129   1327
100   1041  1081  1123  1163  1203  1252  1290  1328
1000  1042  1082  1124  1164  1204  1253  1291  1329

WP_CACHE_KEY_SALT#:$group:$key

Bootstrap

ms-settings.php

sunrise.php

ms_load_current_site_and_network()

@global WP_Network $current_site

$current_site->id;      // ID of the network from wp_site
$current_site->domain;
$current_site->path;    // Leading and trailing slashes
$current_site->blog_id; // The ID of the network's main site
mysql> SELECT * FROM wp_site;
+----+---------------------------+------+
| id | domain                    | path |
+----+---------------------------+------+
|  1 | jeremyfelt.com            | /    |
+----+---------------------------+------+

@global WP_Site $current_blog

$current_blog->blog_id; // ID of the site from wp_blogs
$current_blog->site_id; // ID of the site's network
$current_blog->domain;
$current_blog->path;    // Leading and trailing slashes
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/ |
+---------+---------+----------------+----------+

Subdirectory Configuration

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()

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

sunrise.php

Plugins & Themes

Must Use Plugins

wp-content/mu-plugins/

Network Active Plugins

wp-admin/network/plugins.php

Site Active Plugins

wp-admin/plugins.php

Network Enabled Themes

wp-admin/network/themes.php

Site Enabled Themes

wp-admin/network/site-themes.php

Context

switch_to_blog( $id )

Changes the context of the request

switch_to_blog( $id )

Stores current context

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

switch_to_blog( $id )

Sets database context

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

switch_to_blog( $id )

Sets object cache context

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

switch_to_blog( $id )

Sets context of core roles

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

switch_to_blog( $id )

Does not change the context of code

switch_to_blog( $id )

Does not change the context of rewrite rules.

// 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 );

restore_current_blog()

Restores saved context

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();

ms_is_switched()

Checks for switched context

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

is_main_site()

is_main_network()

get_blog_details()

get_current_site()

Common requests

Domain "Mapping"

Mercator

https://github.com/humanmade/Mercator

Arbitrary Domains & Paths

Multiple Networks

WP Multi Network

https://wordpress.org/plugins/wp-multi-network/

Content Syndication

WordPress 4.6

WP_Site_Query

get_sites()

get_site()

WP_Network_Query

Multisite!


Slides:
jeremyfelt.com/wceu-2016/