Enhancements to the Network Sites Screen in WordPress 5.3

Changes to the database

The introduction of Site metadata in WordPress 5.1 has opened up a lot of new possibilities for multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site.

Save database version and date updated in multisite site metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress.

In [46193], the database version and the updated dates are now stored in the blogmeta table.

If your setup of multisite requires the database version to be accessed from a global context, instead of looping around every site with an expensive switch_to_blog call to get_option( 'db_version' ), you maybe want to try a function like the following.

function get_site_versions() {
	global $wpdb;
	$query = $wpdb->prepare( "SELECT blog_id, meta_value FROM $wpdb->blogmeta WHERE meta_key = 'db_version' ORDER BY blog_id DESC");
	return $wpdb->get_results( $query );
}

Remove blog_versions table

Currently, there is a table in multisite called blog_versions. This table stores the database version as a number and the updated date. It was introduced in #11644 and has never been used in CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. since then.

With the database version and updated date now stored in theblogmeta table, blog_versionstable becomes redundant. In [46194], this table is removed from Core.

Changes to WP_MS_Sites_List_Table

WordPress 5.3 adds several enhancements to the WP_MS_Sites_List_Table class that allows pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party authors to take advantage of Site metadata to provide a richer experience for multisite administrators on the Networknetwork (versus site, blog) Adminadmin (and super admin) Sites screen.

These enhancements will be very familiar to those who have used and/or customized the All Posts screen.

Site Status Views

The Network Sites screen now displays a list of links with the counts of Sites by status (e.g., Public, Spam, etc.), similar to the post status links on the All Posts screen.

Network Sites screen showing site status views.

The status links can also be filtered with the new views_sites-network filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output., introduced in TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. ticketticket Created for both bug reports and feature development on the bug tracker. #37392.

For example, imagine there is a multisite where the main site acts as a directory of local restaurants and each separate site is for an individual restaurant, and restaurant owners can purchase a “subscription” that would allow them to display more information about their restaurant listing: a basic subscription would allow them to add photographs of their restaurant and an advanced subscription would additionally allow them to include their menu.

The subscription level could then be stored in the blogmeta table and “status” links can be added for the different subscription levels as follows:

add_filter( 'views_sites-network', 'myplugin_add_site_status_views' );
function myplugin_add_site_status_views( $view_links ) {
	$statuses = array(
		'free'      => _n_noop(
			'Free <span class="count">(%s)</span>',
			'Free <span class="count">(%s)</span>',
			'myplugin'
		),
		'basic'   => _n_noop(
			'Basic <span class="count">(%s)</span>',
			'Basic <span class="count">(%s)</span>',
			'myplugin'
		),
		'advanced'   => _n_noop(
			'Advanced <span class="count">(%s)</span>',
			'Advanced <span class="count">(%s)</span>',
			'myplugin'
		),
	);

	// get the count of sites with each of our custom statuses.
	$args = array(
		'meta_query' => array(
			array(
				'key'     => 'myplugin-status',
				'compare' => '=',
			),
		),
		'count' => true,
	);
	$counts = array();
	foreach ( array_keys( $statuses ) as $status ) {
		$args['meta_query'][0]['value'] = $status;
		$counts[ $status ] = get_sites( $args );
	}

	$requested_status = isset( $_GET['status'] ) ? wp_unslash( trim( $_GET['status'] ) ) : '';

	foreach ( $statuses as $status => $label_count ) {
		$current_link_attributes = $requested_status === $status ?
			' class="current" aria-current="page"' :
			'';
		if ( (int) $counts[ $status ] > 0 ) {
			$label = sprintf( translate_nooped_plural( $label_count, $counts[ $status ] ), number_format_i18n( $counts[ $status ] ) );

			$view_links[ $status ] = sprintf(
				'<a href="%1$s"%2$s>%3$s</a>',
				esc_url( add_query_arg( 'status', $status, 'sites.php' ) ),
				$current_link_attributes,
				$label
			);
		}
	}

	return $view_links;
}

When a user clicks on one of the custom status links, the rows in the list table can be limited to those sites with that specific custom Status using the existing ms_sites_list_table_query_args as follows:

add_filter( 'ms_sites_list_table_query_args', 'myplugin_sites_with_custom_status' );
function myplugin_sites_with_custom_status( $args ) {
	$status = ! empty( $_GET['status' ] ) ? wp_unslash( $_GET['status' ] ) : '';

	if ( empty( $status ) || ! in_array( $_GET['status'], array( 'free', 'basic', 'advanced' ) ) ) {
		return $args;
	}

	$meta_query = array(
		'key'   => 'myplugin-status',
		'value' => $status,
	);

	if ( isset( $args['meta_query'] ) ) {
		// add our meta query to the existing one(s).
		$args['meta_query'] = array(
			'relation' => 'AND',
			$meta_query,
			array( $args['meta_query'] ),
		);
	}
	else {
		// add our meta query.
		$args['meta_query'] = array(
			$meta_query,
		);
	}

	return $args;
}

Extra Tablenav

The posts displayed on the All Posts screen can be filtered by date and categoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging.. Plugins can also add custom filter criteria with the restrict_manage_posts filter.

To continue with the above restaurant guide example, imagine the food served by each restaurant is also stored in the blogmeta table. We could then allow Network administrators to filter the Sites by the type of food by adding a dropdown of the various cuisines:

Network Sites screen that includes a dropdown added with the "restrict_manage_sites" action.

Dropdowns like this can now be added on the Network Sites screen with the new restrict_manage_sites action ( introduced in Trac ticket #45954), as follows:

add_action( 'restrict_manage_sites', 'myplugin_add_cuisines_dropdown' );
function myplugin_add_cuisines_dropdown( $which ) {
	if ( 'top' !== $which ) {
		return;
	}

	echo '<select name="cuisine">';
	printf( '<option value="">%s</option>', __( 'All cuisines', 'myplugin' ) );

	$cuisines = array(
		'French'  => __( 'French', 'myplugin' ),
		'Indian'  => __( 'Indian', 'myplugin' ),
		'Mexican' => __( 'Mexican', 'myplugin' ),
	);
	
	$requested_cuisine = isset( $_GET['cuisine'] ) ? wp_unslash( $_GET['cuisine'] ) : '';
	
	foreach ( $cuisines as $cuisine => $label ) {
		$selected = selected( $cuisine, $requested_cuisine, false );
		printf( '<option%s>%s</option>', $selected, $label );
	}

	echo '</select>';

	return;
}

When a user selects a food type and clicks the Filter button, the rows in the list table can be limited to just those Sites that serve that cuisine using the existing ms_sites_list_table_query_args filter, as follows:

add_filter( 'ms_sites_list_table_query_args', 'myplugin_sites_with_cuisine' );
function myplugin_sites_with_cuisine( $args ) {
	if ( empty( $_GET['cuisine' ] ) ) {
		return $args;
	}

	$meta_query = array(
		'key'   => 'myplugin-cuisine',
		'value' => wp_unslash( $_GET['cuisine' ] ),
	);

	if ( isset( $args['meta_query'] ) ) {
		// add our meta query to the existing one(s).
		$args['meta_query'] = array(
			'relation' => 'AND',
			$meta_query,
			array( $args['meta_query'] ),
		);
	}
	else {
		// add our meta query.
		$args['meta_query'] = array(
			$meta_query,
		);
	}

	return $args;
}

Site Display States

As with other list tables, each row in the Sites list table can now have display states. By default, all Site statuses (other than Public) of each Site are included as display states. Additionally, the main Site for the Network also has the “Main” display state.

Network Sites screen showing display states added with the "display_site_states" filter.

When a specific Site status view has been selected by the user, that status will not be among the display states (this is just like the All Posts screen).

Plugins can also modify the display states with the new display_site_states filter, introduced in Trac ticket #37684.

To further continue our restaurant guide example, we can add our custom statuses and the cuisine served at each restaurant as display states. This can be achieved as follows:

add_filter( 'display_site_states', 'site_display_states', 10, 2 );
function site_display_states( $display_states, $site ) {
	$status = get_site_meta( $site->blog_id, 'myplugin-status', true );
	$requested_status = isset( $_GET['status'] ) ? wp_unslash( trim( $_GET['status'] ) ) : '';

	if ( $status !== $requested_status ) {
		switch ( $status ) {
			case 'free':
				$display_states['free']     = __( 'Free', 'myplugin' );
				break;
			case 'basic':
				$display_states['basic']    = __( 'Basic', 'myplugin' );
				break;
			case 'advanced':
				$display_states['advanced'] = __( 'Advanced', 'myplugin' );
				break;
		}
	}

	$cuisine = get_site_meta( $site->blog_id, 'myplugin-cuisine', true );
	$requested_cuisine = isset( $_GET['cuisine'] ) ? wp_unslash( trim( $_GET['cuisine'] ) ) : '';

	if ( $cuisine !== $requested_cuisine ) {
		$display_states[ $cuisine ] = $cuisine;
	}

	return $display_states;
}

Misc changes

Return for short circuits for multisite classes.

Fixing a bugbug A bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority. created in the [44983] original patchpatch A special text file that describes changes to code, by identifying the files and lines which are added, removed, and altered. It may also be referred to as a diff. A patch can be applied to a codebase for testing., introduced pre query filters in multisite classes. This bug made short circuit act differently from other short circuits and as it still continues to execute. Now after the filter networks_pre_query and sites_pre_query run, the code will exit straight away. This allows developers to completely hot-wire the network and site query, to load from another source, such as a different cache or Elastic search.

Improved performance for site and network lookups by ID

In earlier versions of WordPress when running the code get_site( 12345 ) was run and no ID with that site exists, the result is not being cached. That means every subsequent lookup will still cause a DB query to be fired, which is unnecessary. In [45910] non-existent sites data is stored as -1 instead of false to save further database lookups.

#5-3, #dev-notes, #multisite, #networks-sites

New Network and Sites Query Filters

WordPress 5.2 introduces new short circuit filters to WP_Site_Query and WP_Network_Query.

These two filters, sites_pre_query and network_pre_query, were introduced in [44983] and run before the database queries are executed. This enables short-circuiting the database query entirely to return custom results. Returning a non-null value from either filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. will bypass WordPress’s default networknetwork (versus site, blog) and sites queries respectively (similar to the users_pre_query filter introduced in #44373).

Sites Query Filter

Developers should note that filtering functions that require pagination information are encouraged to set the found_sites property of the WP_Site_Query object (which is passed to the filter by reference). If WP_Site_Query does not perform a database query, it will not have enough information to generate these values itself.

Using the Filter

Below is a rough example of how a pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party can use the filter to replace the default behavior of WP_Site_Query with a call to a remote data store.

function myplugin_do_external_site_query( $sites, $site_query ) {
	$response = wp_remote_get( 'https://my-remote-data-store/foo/bar' );

	if ( 200 === wp_remote_response_code( $response ) ) {
		$response           = json_decode( wp_remote_retrieve_body( $response ) );
		$sites              = array_map( 'intval', $response->site_ids );
		$query->found_sites = (int) $response->found_sites;
	}

	return $sites;
}
add_filter( 'sites_pre_query', 'myplugin_do_external_site_query', 10, 2 );

Networks Query Filter

Developers should note that filtering functions that require pagination information are encouraged to set the total_networks property of the WP_Network_Query object (which is passed to the filter by reference). If WP_Network_Query does not perform a database query, it will not have enough information to generate these values itself.

Using the Filter

Below is a rough example of how a plugin can use the filter to replace the default behavior of WP_Network_Query with a call to a remote data store.

function myplugin_do_external_network_query( $networks, $network_query ) {
	$response = wp_remote_get( 'https://my-remote-data-store/foo/bar' );

	if ( 200 === wp_remote_response_code( $response ) ) {
		$response              = json_decode( wp_remote_retrieve_body( $response ) );
		$networks              = array_map( 'intval', $response->network_ids );
		$query->total_networks = (int) $response->total_networks;
	}

	return $networks;
}
add_filter( 'network_pre_query', 'myplugin_do_external_network_query', 10, 2 );

Other Similar Query Filters

Similar filters for WP_User_Query and count_users() were added in WordPress 5.1.

Several additional filters for similar query objects are currently being explored and worked on, and are currently slated for a future release:

  • A short circuit for WP_Comment_Query (#45800).
  • A short circuit for WP_Term_Query with a plan to add a terms_pre_query filter (#41246).

Why Add These Filters?

These query pre-filters enable plugins to use an alternate database store for queries, for example returning results from an external service such as an Elasticsearch server. The process started with the main post query, and these are now being expanded that to other queries in WordPress.

#5-2, #dev-notes, #multisite, #networks-sites

Multisite Support for Site Metadata in 5.1

WordPress multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site introduces a new database table to store metadata associated with sites. This allows for the storage of arbitrary site data relevant in a multisite / networknetwork (versus site, blog) context.

Site metadata provides an alternative to using options and can be retrieved from multiple sites in a more performant way—without calling switch_to_blog(). Sites can now also be queried by their metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. with parameters supported by WP_Meta_Query.

The new wp_blogmeta table is a global table in WordPress and developers should be cautious not to overuse it. There is a trade-off between using site options and site metadata, so it is recommended to think about every piece of extra data associated with a site and how it should be stored.

  • Use options when the data concerns only the site itself. Using an option should continue to be the default approach for site data.
  • Use site metadata when the data also needs to be heavily used in the network context, especially when sites need to be queried by it.

A network update is required to install the new database table. The site meta APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. includes a function is_site_meta_supported() to ensure no unexpected errors occur when that process has not run yet. As of WordPress 5.1, there is only a single use-case for the site meta in coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. which regards the fatal error protection mechanism (see #44458).

This is how the API can be used:

  • get_site_meta( $id, $meta_key, $single )
  • update_site_meta( $id, $meta_key, $meta_value, $prev_value )
  • add_site_meta( $id, $meta_key, $meta_value, $unique )
  • delete_site_meta( $id, $meta_key, $meta_value )

All of these functions are only available in multisite, however they work similarly to other metadata wrapper functions, such as for posts, terms, comments and users. In addition to these functions, it is now possible to use the common meta query arguments when querying sites with WP_Site_Query or its wrapper get_sites().

Note that the database table for site metadata is called wp_blogmeta. This is because wp_sitemeta is already used for another database table, and furthermore the new name works consistently alongside the related wp_blogs table that stores the most essential site data. The API exposed and described here uses the correct term “site”.

For background information on these changes, see #37923 and #40229.

An additional under-the-hood change related to this is that the metadata API is now loaded earlier in the WordPress bootstrap process so that it is available as early as the multisite bootstrap code. See #40948 for more information.

Props @jeremyfelt for review.

#5-1, #dev-notes, #multisite, #networks-sites

Multisite agenda: December 18

This is the agenda for the weekly office hours meeting on Tuesday, December 18th, 2018 at 17:00 UTC in #core-multisite.

As mentioned in #core-multisite last week, it’s been a while since the last organized multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site office hours. Let’s use this as an opportunity to regroup and determine what’s next in 2019. In particular, these topics will be covered:

  • Status of progress made in 2018. Nothing has shipped officially yet, but a full recap of all changes currently in trunktrunk A directory in Subversion containing the latest development code in preparation for the next major release cycle. If you are running "trunk", then you are on the latest revision. needs to be written so that the current state can be communicated.
  • Expectations for 2019. What reasonably matches (and doesn’t match) the overall WordPress project focus for the next year.
  • Office hours in 2019. What time, how frequently, who is leading them.

In addition to those general topics, @flixos90 would like to reserve 10-20 minutes to chat about the multisite integrations of WSOD protection in Servehappy. The coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. ticketticket Created for both bug reports and feature development on the bug tracker. is #44458 and patches are also applied as a pull request on GitHub.

Please join the chat if you’re interested in one of the topics. In case you cannot make the respective meeting, we will be working on publishing a recap post afterwards. If you have some thoughts beforehand or would like something related to be part of the agenda, feel free to share your ideas in the comments for this post. See you in the chat!

#agenda, #multisite, #networks-sites

Multisite Recap for the week of November 13th

Office Hours Recap

The agenda for this office hours meeting was to discuss adopting TrelloTrello Project management system using the concepts of boards and cards to organize tasks in a sane way. This is what the make.wordpress.com/marketing team uses for example: https://trello.com/b/8UGHVBu8/wp-marketing. as a way to manage status, progress, and ownership on tasks, as well as progress on multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site roadmap with a target to publish an initial version before WCUS.

The meeting’s chat log

Attendees: @desrosj, @flixos90, @jeremyfelt, @spacedmonkey, @vizkr

Chat Summary:

  • The full roadmap draft should be in place by November 21st, in order for the document to be published a week later, on November 28th, so that it is out before WordCampWordCamp WordCamps are casual, locally-organized conferences covering everything related to WordPress. They're one of the places where the WordPress community comes together to teach one another what they’ve learned throughout the year and share the joy. Learn more. US. @flixos90 and @jeremyfelt will have another look to complete the remaining sections.
  • After discussing possible usage of Trello in a collaborative way, the conclusion was that what is missing the most is an easy-to-use UIUI User interface to manage required tasks and assignees for tickets on TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress.. However most of the functionality is already in place and could be used through workarounds, so the decision was made not to use Trello for now. Instead the goal is to be more precise with defining tasks when assigning a ticketticket Created for both bug reports and feature development on the bug tracker. and generally assign tickets around between the responsible parties for a part of it more deliberately, instead of having a single owner through most of a ticket’s lifecycle. In a perfect world, there would be more possibilities to choose from when assigning a ticket to somebody, such as “update patchpatch A special text file that describes changes to code, by identifying the files and lines which are added, removed, and altered. It may also be referred to as a diff. A patch can be applied to a codebase for testing.” or “write unit tests”, but for now these tasks can also be determined in regular comment text.

Next meeting

The next office hours will take place on November 21th, 2017, 17:00 UTC. Its agenda will be to review the roadmap draft and then discuss #42252.

Ticket Scrub Recap

No ticket scrub took place this week.

Next meeting

The next ticket scrub will take place on November 20th, 2017, 18:00 UTC. Its agenda will be to determine the current state and required tasks of tickets scheduled for 5.0 and assign them accordingly.

If you were unable to attend one of these meetings but have feedback, please share your thoughts in the comments on this post. In case there’s a need for further discussion we will ensure to make time for it in one of next week’s chats. See you next week!

#multisite, #networks-sites, #summary

Multisite Recap for the week of November 6th

Office Hours Recap

The agenda for this office hours meeting was open floor.

The meeting's chat log

Attendees: @florian-tiar, @spacedmonkey, @desrosj, @flixos90, @mikelking, @jeremyfelt

Chat Summary:

  • There was a loose discussion on the tickets that should be focused on at the beginning of the 5.0 cycle.
  • Caching in WP_Site_Query will be a big focus at first. Tickets #42252, #42280, #42251. There was a brief discussion on some approaches.
  • Implementing new install and update methods in #41333.
  • Using the metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. for networknetwork (versus site, blog) options in #37181.
  • The new multisite roadmap is getting there and should be ready to publish before WordCampWordCamp WordCamps are casual, locally-organized conferences covering everything related to WordPress. They're one of the places where the WordPress community comes together to teach one another what they’ve learned throughout the year and share the joy. Learn more. US.

Next meeting

The next office hours will take place on November 14th, 2017, 17:00 UTC. Its agenda will be:

  • Discuss adopting TrelloTrello Project management system using the concepts of boards and cards to organize tasks in a sane way. This is what the make.wordpress.com/marketing team uses for example: https://trello.com/b/8UGHVBu8/wp-marketing. as a way to manage status, progress, and ownership on tasks.
  • Progress on multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site roadmap with a target to publish an initial version before WCUS.
  • Any progress on 5.0 tickets.

#4-9, #multisite, #network-sites, #summary

Multisite Focused Changes in 4.9

Here’s an overview of the developer facing changes made in multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site for the 4.9 cycle. If you’re interested in more detail, checkout the full list of tickets.

clean_blog_cache() replaces refresh_blog_details()

Since 3.5, refresh_blog_details(), which accepts a site ID, has been a wrapper of the clean_blog_cache() function, which requires a site object.

In WordPress 4.9, clean_blog_cache() has been adjusted to also accept a site ID and to invalidate caches for a deleted site in the same way. From now on clean_blog_cache() should be used instead of refresh_blog_details() which will be deprecated in a future release.

More importantly, the refresh_blog_details action has been deprecated in favor of the clean_site_cache action. See #40201.

New function get_main_site_id()

The WP_Network class has historically contained a $blog_id property indicating the ID of the main site of that networknetwork (versus site, blog). However, since this property was never part of the wp_site database table, it is set manually in the multisite bootstrapping process. This results in it only being set for the current network. For any other network, code like get_network( $id )->blog_id would return 0.

The new get_main_site_id() function introduced in 4.9 provides the site ID of any network in an easy way. The function accepts an optional $network_id parameter, which defaults to the current network. Furthermore the magic property logic in WP_Network has been adjusted so that the $blog_id property (and its magic $site_id equivalent) is automatically set when requested. This ensures get_network( $id )->blog_id will always return a meaningful value. See #29684.

Refactored user capability and role switching

Switching the available roles and the current user’s capabilities no longer happens in switch_to_blog() and restore_current_blog(). Instead it has been moved to a new function, wp_switch_roles_and_user(), which is hooked into the site switching process. This provides a performance improvement by temporarily unhooking the function in cases where roles and capabilities do not need to be switched.

In addition, the available user roles are now correctly switched when switching sites, with refactored behavior in the WP_User and WP_Roles classes making this possible. These changes are more closely explained in the 4.9 post about role and capability improvements. For related tickets, see #36961 and #38645.

Site administrators can edit user roles through the REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/.

While site administrators cannot edit user details in multisite, they are able to modify a user’s roles. In WordPress 4.9 this can now be achieved through the REST API by making a request such as PUT wp/v2/users/<id> and passing only the roles argument in the request body. No other arguments must be given as those would require the current user to have network administrator capabilities. See #40263.

Other Notes

  • The new can_add_user_to_blog filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. can be used to prevent a user from adding specific users to a site or with a specific role. See #41101.
  • The old site network adminadmin (and super admin) email address gets notified of a change to the address. See related security improvements for 4.9 and #39117.

#4-9, #dev-notes, #multisite, #networks-sites

Multisite Recap for the week of October 9th

Office Hours Recap

The agenda for this office hours meeting was to review 4.9 bug and task tickets that still need to be finished and merged within BetaBeta A pre-release of software that is given out to a large group of users to trial under real conditions. Beta versions have gone through alpha testing in-house and are generally fairly close in look, feel and function to the final product; however, design changes often occur as part of the process., particularly continuing from where the ticketticket Created for both bug reports and feature development on the bug tracker. scrub meeting stopped.

The meeting’s chat log

Attendees: @earnjam, @flixos90, @jeremyfelt, @jjj, @johnbillion, @josheby, @spacedmonkey, @stevenkword

Chat Summary:

  • #41936: It was decided that the new filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. pre_get_main_site_id should not actually set the WP_Network::$blog_id property when used and only override the return value when accessing it, as it could otherwise have unexpected consequences if a hook set for it was (temporarily) removed. The latest patchpatch A special text file that describes changes to code, by identifying the files and lines which are added, removed, and altered. It may also be referred to as a diff. A patch can be applied to a codebase for testing. had one issue where a variable had not been correctly renamed after moving the code from the function to the class method. It was furthermore discussed how verbose and strict casting the value returned by a filter should be. It was decided to only return the filter value if 0 < (int) $value. Both issues have since been fixed in the latest patch.
  • #38570 and #41652: @sergey is taking care of these i18ni18n Internationalization, or the act of writing and preparing code to be fully translatable into other languages. Also see localization. Often written with a lowercase i so it is not confused with a lowercase L or the numeral 1. Often an acquired skill. tickets.
  • #41789: @johnbillion will provide feedback.
  • As there is now a 5.0 milestone on TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress., the priority tickets that were previously flagged with “Future Release” and “early” are now being moved into the actual milestone.
  • #40364: @flixos90 asked for feedback for this rather complex ticket, as it should preferably get ready early in the 5.0 cycle. That ticket should be discussed in detail in one of the next few weeks, once the multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site work for 4.9 has wrapped up.

Next meeting

The next office hours will take place on October 17th, 2017, 16:00 UTC. Its agenda will be to continue discussing 4.9 tickets and the dev-note for the Networks & Sites component.

Ticket Scrub Recap

The agenda for this ticket scrub was to review 4.9 bug and task tickets that still need to be finished and merged within Beta, similar to the office hours meeting agenda this week (see above).

The meeting’s chat log

Attendees: @afercia, @flixos90, @jeremyfelt, @jjj, @paaljoachim, @spacedmonkey

Chat Summary:

  • #41936: It was decided that moving the logic that is currently in get_main_site_id() is okay to be moved to WP_Network:get_main_site_id(), since that data is very specific to each individual networknetwork (versus site, blog). It must furthermore be ensured that all values are properly typecast into the expected type (WP_Network::$blog_id is a string, WP_Network::$site_id is an integer and WP_Network::get_main_site_id() should always return an integer). Minor tweaks suggested were returning get_current_blog_id() instead of a hardcoded value of 1 in get_main_site_id() for non-multisite environments and using an internal variable for the cache key used. @spacedmonkey and @flixos90 will make sure this gets ready.
  • #42093: @jeremyfelt has been working on providing an easy way to run unit tests for a subdomain install. This ticket is currently a task scheduled for 4.9, but may as well be punted to 5.0 in case it does not get ready in time.
  • #39419: It was agreed on that the doc blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. for the globals should indicate replacements to use for those that are deprecated. @jeremyfelt has since updated the patch. It is still being considered whether globals such as $table_prefix, which are used there, but not actually set up there initially should be listed as well.
  • #41789: It was briefly discussed how to be most precise about the documentation of the get_sites() (and related WP_Site_Query method) return value, without making the description overly complex. @jeremyfelt added the final idea as a comment on the ticket and is now waiting for feedback. It was also mentioned that documentation for the other query classes should probably be changed in a similar way, however the ticket for now should only deal with sites and networks.

Next meeting

The next ticket scrub will take place on October 16th, 2017, 17:00 UTC. Its agenda will be to continue discussing 4.9 tickets, particularly the issue that came up with #40228.

If you were unable to attend one of these meetings but have feedback, please share your thoughts in the comments on this post. In case there’s a need for further discussion we will ensure to make time for it in one of next week’s chats. See you next week!

#4-9, #multisite, #networks-sites, #summary

Multisite Recap for the week of October 2nd

Office Hours Recap

The agenda for this office hours meeting was to prepare remaining open enhancements for the 4.9 release.

The meeting’s chat log

Attendees: @flixos90, @spacedmonkey, @jeremyfelt

Chat Summary:

  • #40228 – Review the latest patches for using get_site_by() in get_blog_details().
  • #40201 – Review the latest patches for using get_site() in clean_blog_cache(). @flixos90 and @jeremyfelt agreed that requiring a site ID is okay for clean_blog_cache(), moving the refresh_blog_details hook into clean_blog_cache() is appropriate, and deprecating the refresh_blog_details hook in favor of clean_site_cache is good.
  • @flixos90 committed to committing #40201 and #40228 before 4.9 betaBeta A pre-release of software that is given out to a large group of users to trial under real conditions. Beta versions have gone through alpha testing in-house and are generally fairly close in look, feel and function to the final product; however, design changes often occur as part of the process..
  • #42072 and #42073 – Discussed both of these, which involve limiting get_sites() calls to 1 result when only 1 result is used. @jeremyfelt took ownership of these for 4.9.
  • #41762 – Agreed to use WP_Network_Query in ms_load_current_site_and_network(), but to keep the current-network cache key for now.

Next meeting

The next office hours will take place on October 4, 2017, 16:00 UTC. Its agenda will be to go over remaining bugs for 4.9 and the progress of this cycle’s dev notesdev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include: a description of the change; the decision that led to this change a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase..

Ticketticket Created for both bug reports and feature development on the bug tracker. Scrub Recap

The agenda for this ticket scrub was to review remaining enhancements for the 4.9 release.

The meeting’s chat log

Attendees: @ramiy, @sergey, @afragen, @flixos90, @spacedmonkey, @jeremyfelt, @johnjamesjacoby, @desrosj

Chat Summary:

  • #40180 – Discussion on some of the remaining details for get_site_by().
  • #40228 – Agreed to finish and commit #40180 so that the patches for get_site_by() in get_blog_details() would be easier to review.
  • #40201 – Discussion if clean_blog_cache() should support an empty argument as a replacement for refresh_blog_details(). Agreement that it’s okay to continue requiring that a site be specified.
  • Discussion on when or whether to deprecate refresh_blog_details() or its hook refresh_blog_details, which is now a part of clean_blog_cache(). It seems that it’s okay to postpone this until get_site_by() and clean_blog_cache() are more widely used.

Next meeting

@jeremfelt did not clarify early enough whether or not a ticket scrub will take place on October 3, 2017, 17:00 UTC. 🙈 A loose agenda would be to cover remaining bugs for the 4.9 cycle.

If you were unable to attend one of these meetings but have feedback, please share your thoughts in the comments on this post. In case there’s a need for further discussion we will ensure to make time for it in one of next week’s chats. See you next week!

#4-9, #multisite, #network-sites, #summary

Multisite Recap for the week of September 25th

Office Hours Recap

No office hours meeting took place this week.

Next meeting

The next office hours will take place on October 3rd, 2017, 16:00 UTC. Its agenda will be to get the 4.9 enhancements ready to be merged before BetaBeta A pre-release of software that is given out to a large group of users to trial under real conditions. Beta versions have gone through alpha testing in-house and are generally fairly close in look, feel and function to the final product; however, design changes often occur as part of the process., and then coordinate remaining work on 4.9 bugbug A bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority. tickets.

Ticketticket Created for both bug reports and feature development on the bug tracker. Scrub Recap

The agenda for this ticket scrub was to look through the multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site tickets without a response.

The meeting’s chat log

Attendees: @afragen, @flixos90, @schlessera, @spacedmonkey

Chat Summary:

  • The issue with the suggestion in #41443 is that wpmu_validate_blog_signup() is supposed to validate new sites submitted by regular users, not by administrators, so that function would not be applicable for usage on the New Site networknetwork (versus site, blog) adminadmin (and super admin) page. However, some restrictions for new user-submitted sites do not apply to admin-created sites, so these restrictions should be reviewed and possibly adjusted to work more similarly to each other.
  • #41685 is a very early ticket, since it requires the site metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. and related blogmeta database table in order to be worked on. It was agreed on that it would generally make sense to store site database versions in the new table instead of an entirely separate table. However, since these versions are not used anywhere in coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. and since it is questionable whether the blog_versions table can be removed for backward-compatibility reasons, this still needs a deeper discussion once site meta is actually part of core.
  • #41936 was figured out to be a minor bug with the new get_main_site_id() not taking the possibly already set WP_Network::$blog_id property into account. This should definitely be fixed for 4.9. The current patchpatch A special text file that describes changes to code, by identifying the files and lines which are added, removed, and altered. It may also be referred to as a diff. A patch can be applied to a codebase for testing. by @spacedmonkey moves the logic from the function to the WP_Network class method, which is not preferable, but might end up being the only way to accomplish the goal without running into an infinite loopLoop The Loop is PHP code used by WordPress to display posts. Using The Loop, WordPress processes each post to be displayed on the current page, and formats it according to how it matches specified criteria within The Loop tags. Any HTML or PHP code in the Loop will be processed on each post. https://codex.wordpress.org/The_Loop. issue. @flixos90 will try to find a better way to fix the issue, but if nobody finds one, the current patch is solid enough to go in. This can happen last minute though, as this will be a bug-fix and does not need to be merged before beta.

Next meeting

The next ticket scrub will take place on October 2nd, 2017, 17:00 UTC. Its agenda will be reviewing the 4.9 enhancements and coordinating who works on the possibly required changes so that another review can happen during the office hours a day later.

If you were unable to attend one of these meetings but have feedback, please share your thoughts in the comments on this post. In case there’s a need for further discussion we will ensure to make time for it in one of next week’s chats. See you next week!

#4-9, #multisite, #networks-sites, #summary