Global terms removed in WordPress 6.1

Global terms is an old feature from the MU days of WordPress when 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 and single site installs had separate code bases. It has been abandoned and unmaintained for a significant amount of time, and in WordPress 6.1, it has finally and officially been removed.

Here’s a brief timeline of events leading up to this change.

WordPress 3.0 (2010): Phase 1

The first phase of removing global terms was in WordPress 3.0.

  • The user interface for global terms was completely removed in [14854].
  • The “on” switch in CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. was removed in [14880], though plugins were free to call install_global_terms() directly, if they dared.

2010-2022:

  • A Global Terms 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 was created and released with the goal of moving the code there from Core. The plugin broke with the release of WordPress 3.5 and has not been updated.
  • With the introduction of term splitting in WordPress 4.2, the feature became even more broken and 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.-ridden.
  • When term 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. was introduced in WordPress 4.4 (see #10142), the affects on global terms were (rightfully) not considered. I haven’t actually tested, but it’s safe to say that term meta does not work with global terms, and would cause a number of issues.
  • Searches of the plugin directory show no meaningful usage of the global terms related functions with the exception of global_terms_enabled() (more on this below).

WordPress 6.1 (2022): Phase 2

This release will mark the completion of the second and final phase of removing global terms.

  • All global term related functions have been officially deprecated and will now throw proper deprecated notices (see [54240]).
  • The functions have also been no-opped (no operationed) and calling them will have no effect, except for triggering a deprecated notice. There are a two exceptions which are detailed below.

global_terms() function

This function used to be hooked to the term_id_filter 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.. This is no longer the case. However, the function will continue to return the $term_id value passed to it in case it’s being called directly in the wild.

global_terms_enabled() function

This function previously returned a boolean indicating whether global terms were enabled or not. Even though there is almost no usage of this function in the plugin directory, it’s the function with the highest probability of being used.

After [54240], global_terms_enabled() will always return false.

sitecategories database table

Sites that had global terms enabled at one point in time will likely have a sitecategories table in their database. This table will not be touched with these changes. Most sites should be able to safely remove this table.

For more information on this change, see #21734 on TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress..

Props @davidbaumwald for reviewing.

#dev-notes, #dev-notes-6-1, #networks-sites

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

Multisite Recap for the week of September 11th

Office Hours Recap

The agenda for this office hours meeting was to resolve the remaining discussion and blockers for #29684, the proposed get_main_site_id() function and related integration.

The meeting’s chat log

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

Chat Summary:

  • The main purpose this function could serve initially is to auto-fill the $blog_id property of the WP_Network class, which currently is only being populated for the current networknetwork (versus site, blog) in the bootstrap process. There is no database field for the main site of a network, therefore custom logic must run for it to be set. get_main_site_id() makes it easy to detect the main site for a network, and magic getters in WP_Network would allow to automatically set the property once it is first accessed, using the new function. In the end of the discussion it was decided that the logic to auto-fill the property makes sense and can be merged with the new function.
  • It was also discussed whether a network option should be used to store the main site ID. This would bring a performance benefit 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 setups without an object cache and without the network constants enabled. On the other hand, the main site ID at this point is not really an option, since many areas of WordPress assume it is always the site whose domain and path match the network’s ones. Getting rid of this restriction is something that could be evaluated more closely in the future, but for now this restriction exists, and introducing a network option would give the impression that it would be possible to change the main site ID without any issues. Therefore it was decided to not use a network option at this point, but it can be reconsidered later in a separate ticketticket Created for both bug reports and feature development on the bug tracker..
  • Another topic was whether the actual logic should go into the get_main_site_id() function or whether the function is not required at all and instead the logic should be part of WP_Network. Eventually it was agreed to go with the regular function and call it from WP_Network. Moving the logic into a private WP_Network method would not align well with existing coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. patterns, where pretty much everything relies on a function. As long as there is no methodological approach for this, functions should remain the source as it currently is.
  • Naming of the new function was discussed as well. It was suggested to call the function get_main_site_id_for_network() or get_network_main_site_id() to be more precise. On the other hand, is_main_site() already exists and would have been called similarly in order to align with the new function. Furthermore the function is available for non-multisites, making the extra network affix a bit more confusing. It was decided to proceed with the current idea of get_main_site_id().
  • All remaining items were solved and as of now the patch has been merged into core.

Next meeting

The next office hours will take place on September 19, 2017, 16:00 UTC. Its agenda will be to further plan 4.9 work and which tickets should receive the main focus in the few remaining weeks until 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. 1.

Ticket Scrub Recap

The agenda for this ticket scrub was to review and discuss some multisite tickets in the 4.9 milestone.

The meeting’s chat log

Attendees: @afragen, @desrosj, @flixos90, @jeremyfelt, @sergey, @vizkr

Chat Summary:

  • The first ticket discussed was #40764: @afragen asked for feedback. @flixos90 verified that 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. applies cleanly. @desrosj plans to review the patch itself soon.
  • #41285 was discussed: @jeremyfelt was asked for feedback and responded that he is confident that this change can happen, at least for the $public global. He will dive deeper into whether the $site_id global is safe to remove as well. He furthermore stated that the related tickets #34217 and #39419 should be considered as well. A response from Automatticians working on wordpress.com would be much appreciated.
  • #40364 was the last ticket for the meeting: The proposed action hook names used in the new functions wp_insert_site(), wp_update_site() and wp_delete_site() using the same names were questioned and whether it may be more useful to use more precise names using past tense, such as wp_inserted_site(), so that it is clear they run after the database transaction. It was also considered to run multiple actions. Eventually it was decided to go with the simple approach for now, and stick with one action having the function name. Regarding timing, while the latest patch may possibly be merged at this point, it should rather wait until #41333 has also been completed, to have the full new site 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. in core in one release. The latter ticket is something that can be worked on during the 4.9 beta, to aim for an early 5.0 merge.

Next meeting

The next ticket scrub will take place on September 18, 2017, 17:00 UTC. Its agenda will be to review multisite bug tickets awaiting review with a focus on recently opened tickets.

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