Providing a REST API sites endpoint for multisite

One of the objectives 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 is to determine how sites can be managed with 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/.. This has been an agenda item for the last two weeks and quite a bit has been processed. This will continue to be a topic, so please stop in for #core-multisite office hours on Tuesday 17:00 UTC and please leave your feedback in the comments on this post.

January 17 chat log and January 24 chat log in #core-multisite

Attendees: @kenshino, @vizkr, @danhgilmore, @iamfriendly, @flixos90, @schlessera, @sergeybiryukov, @pbearne, @paaljoachim, @streetlamp, @jnylen0, @loreleiaurora, @maximeculea

The requirements for the /sites/ endpoint can be summed up with these assertions:

  • The /sites/ endpoint should provide a useful set of data for each site without requiring the use of switch_to_blog().
  • It should be possible to query /sites/ for something other than ID, domain, and path.

In its current state, any /sites/ endpoint is limited to the fields in the wp_blogs table. Data such as a site’s name and description are stored in each individual site’s wp_#_options table.

Given a list of 20 sites, switch_to_blog() will be used 20 times so that get_option() can be used to retrieve things like home, siteurl, blogname, and blogdescription. An example of how inefficient this is can be found in the generation of the My Sites menu. Caching has gotten better with the introduction of WP_Site and WP_Site_Query, but there is an opportunity to change how the information is stored.

In #37923, @johnjamesjacoby suggests the introduction of a wp_blogmeta table that provides access to some site information in a common table. After discussing this in the January 17 chat, @iamfriendly and @flixos90 agreed to each take a look at coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress.’s default options stored in wp_options and determine which made sense in a shared wp_blogmeta table. Richard’s results can be found in a comment on the ticket and Felix’s in the Slack discussion.

After some discussion in the January 24 chat, that list can be pared down a bit more.

  • home
  • siteurl
  • blogname
  • blogdescription
  • admin_email

The creation of a new table, wp_blogmeta, and migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. of data for each site from wp_#_options is something that needs feedback. Without this change, a /sites/ endpoint is still possible, but may be limited. With the change, a /sites/ endpoint is much more useful, but requires a careful migration process.

#multisite, #networks-sites, #rest-api

Improving the REST API users endpoint in multisite

One of the objectives 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 is sorting how users are managed with 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/.. This was one of the agenda items for last week’s #core-multisite office hours and generated some good discussion. Here’s a wrap-up of the ideas and thoughts from that discussion.

Chat log in #core-multisite

Attendees: @iamfriendly, @johnjamesjacoby, @nerrad, @florian-tiar, @mikelking, @earnjam, @jeremyfelt

Users in multisite exist globally and are shared among sites on one or more networks. Users are associated with sites in the user 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. table with a wp_#_capabilities key.

The current state of the wp-json/wp/v2/users endpoint for multisite is:

  • A POST request for a new global user to the main site creates the user and associates them with the main site only.
  • A POST request for a new global user to a sub site creates the user and associates them with the sub site only.
  • A POST request for an existing global user results in an error.
  • A PUT request for an existing global user to a sub site updates the user’s meta with a capability for that sub site.
  • A DELETE request on multisite is invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid. and results in an error. See #38962.

It is not possible to remove a user from an individual site or to delete the user from the networknetwork (versus site, blog).

Previous tickets: #38526, #39155, #38962, #39000

The following are a few thoughts expressed separately from the above summary.

  • The right way to associate existing objects over the REST API is with a PUT request.
  • The right way to disassociate existing objects is with a PUT request.
  • Linked previous discussion – “Deleting an item should always delete an item
  • We already have functions like remove_user_from_blog() and add_user_to_blog() available to us.
  • Does “add” invite or literally add? This can probably be included as data in the PUT request.
  • What happens if an 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. client is built for single site and then that site gets switched to multisite?
  • Handling bulk actions on an endpoint would be nice. (e.g. Add a user to multiple sites) No endpoint has implemented batch handling yet though.

Initial tasks:

  • It should be possible to remove a user from a site with a PUT request to the wp-json/wp/v2/users/# endpoint.
  • It should be possible to delete a global user with a DELETE request to the wp-json/wp/v2/users/# endpoint once all sites have been disassociated.

New tickets will be created soon for these tasks. Please leave any initial feedback in the comments on this post covering the assumptions and conclusions made above. There will be another round of discussion during tomorrow’s #core-multisite office hours at Tuesday 17:00 UTC.

/cc @rmccue and @kadamwhite

#multisite, #networks-sites, #rest-api, #users

Multisite Focused Changes in 4.7

Howdy. The 4.7 release cycle has been a chance to build on some of the work from the last couple releases 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.  If you’d like more detail, check out the full list of multisite focused changes in this release.

get_blog_details() replaced with get_site()

A lot of progress has been made over the last few releases to get things in place for this transition. Now that WP_Site and WP_Network objects exist and are accessible with functions like get_site() and get_network(), they can be implemented throughout coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress..

In WordPress 4.7, get_blog_details() was replaced throughout core code with the modern  get_site(). The roadmap for this includes deprecating get_blog_details() in WordPress 4.8, so take this cycle as a chance to move your code in that direction.

get_site() is often a direct replacement, though get_sites() can also be used to query for sites when an ID is not available.

See #37102 for details on this change.

blog_details 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. deprecated

In combination with the decision to stop using get_blog_details() throughout core, the (not widely used) blog_details filter has been deprecated. It has been added to get_site() to provide backward compatibility with the above change and will fire with a deprecation notice. 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 code should use the site_details filter instead. See #38491 for details on this change.

_network_option actions and filters get $network_id

The $network_id associated with the use of a _network_option() function is now passed to the filters and actions that fire within. This provides granular control that was not available when first introduced. See #38319, #38320, #38321, and #38322 for details on this change.

wp_get_network() deprecated

It is now recommended that get_network() is used instead. See #37553 for this change.

 

 

#4-7, #dev-notes, #multisite, #network-sites

4.6.1 Release Candidate

A Release Candidate for WordPress 4.6.1 is now available. This maintenance release fixes 16 issues reported against 4.6 and is scheduled for final release on Wednesday, September 7.

Thus far WordPress 4.6 has been downloaded almost 7 million times since its release on August 16. Please help us by testing this release candidaterelease candidate One of the final stages in the version release cycle, this version signals the potential to be a final release to the public. Also see alpha (beta). to ensure 4.6.1 fixes the reported issues and doesn’t introduce any new ones.

All Changes

Here’s a list of all closed tickets, sorted by component:

Bootstrap/Load

  • #37680PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher Warning: ini_get_all() has been disabled for security reasons

Comments

  • #37696WP_Comment_Query loses sql_clauses with object cache

Database

  • #37683$collate and $charset can be undefined in wpdb::init_charset()
  • #37689 – Issues with utf8mb4 collation and the 4.6 update

Editor

  • #37690 – Backspace causes jumping

Email

  • #37736 – Emails fail on certain server setups

External Libraries

  • #37700 – Warning: curl_exec() has been disabled for security reasons (Requests library)
  • #37720 – The minified version of the Masonry shim was not updated in #37666 (Masonry library)

HTTPHTTP HTTP is an acronym for Hyper Text Transfer Protocol. HTTP is the underlying protocol used by the World Wide Web and this protocol defines how messages are formatted and transmitted, and what actions Web servers and browsers should take in response to various commands. 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.

  • #37733cURL error 3: malformed for remote requests
  • #37768 – HTTP API no longer accepts integer and float values for the cookies argument

Post Thumbnails

  • #37697 – Strange behavior with thumbnails on preview in 4.6

Script Loader

  • #37800 – Close “link rel” dns-prefetch tagtag A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.)

TaxonomyTaxonomy A taxonomy is a way to group things together. In WordPress, some common taxonomies are category, link, tag, or post format. https://codex.wordpress.org/Taxonomies#Default_Taxonomies.

  • #37721 – Improve error handling of is_object_in_term in taxonomy.php

Themes

  • #37755 – Visual Editor: Weird unicode (Vietnamese) characters display on WordPress 4.6

TinyMCE

Upgrade/Install

  • #37731 – 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. in _wp_json_sanity_check() during 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 install

 

#4-6-1

Bug Scrub for 4.6.1

The first 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. scrub for 4.6.1 will be Tuesday 23 August, 15:00 UTC in #core.

There are currently 9 11 tickets open on the 4.6.1 milestone in various stages of verification, patching, and testing. Working with these over the next several days before the bug scrub will help determine when a 4.6.1 release will be necessary.

Any tickets reported against trunk at this point in the cycle should also be checked for issues that may have been introduced in 4.6.

All testing is helpful, so please take a look if you have time.

See you on Tuesday!

 

#4-6-1, #bug-scrub

Additional register_meta() changes in 4.6

In the last 2 weeks, the direction of register_meta() has changed significantly from the original write-up. There was a meeting to discuss some of the changes and a recap of that discussion. Some other discussion after that meeting led to a much more simplified version of register_meta() that is now shipping in 4.6.

Here’s what registering 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. looked like in 4.5. This meta key has sanitization and authorization callbacks.

register_meta( 'post', 'my_meta_key', 'sanitize_my_meta_key', 'authorize_my_meta_key' );

The above code will continue to work in 4.6, though will not be considered completely registered. The callbacks will be registered, but the key will not be added to the global registry and register_meta() will return false.

Here’s what registering meta looks like in 4.6. This meta key will have sanitization and authorization callbacks, and be registered as public for the WordPress 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/..

$args = array(
    'sanitize_callback' => 'sanitize_my_meta_key',
    'auth_callback' => 'authorize_my_meta_key',
    'type' => 'string',
    'description' => 'My registered meta key',
    'single' => true,
    'show_in_rest' => true,
);
register_meta( 'post', 'my_meta_key', $args );

The above will register the meta key properly and return true.

There will no longer be a check for unique object types and subtypes for meta keys. There is no CURIE like syntax involved. Instead, be sure to uniquely prefix meta keys so that they do not conflictconflict A conflict occurs when a patch changes code that was modified after the patch was created. These patches are considered stale, and will require a refresh of the changes before it can be applied, or the conflicts will need to be resolved. with others that may be registered with different arguments.

Additional helper functions get_registered_metadata(), get_registered_meta_keys(), unregister_meta(), and registered_meta_key_exists() have been added to make the innards of the global data more accessible.

The $wp_meta_keys variable should not be altered directly. It is possible that its structure will change in the future.

Any code currently using register_meta() and expecting pre-4.6 behavior will continue to work as is. Please report any breaks in compatibility that might be found.

For the full history, see #35658. 🙂

 

 

#4-6, #dev-notes, #options-meta

register_meta() Discussion Recap (July 14, 2016)

As announced yesterday, there was a discussion today covering the future of register_meta(), something that has been in progress for WordPress 4.6 in #35658. This is a recap. 🙂

Attendees: @helen, @ocean90, @rachelbaker, @mikeschinkel, @jsternberg, @sc0ttclark, @richardtape, @swissspidy, @joemcgill, @seancjones, @achbed, @jeremyfelt

Chat log.

Overview

In #35658, register_meta() uses object subtypes when registering 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. so that key registration can be considered unique.

In 4.6 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., this information is passed as part of the 3rd argument—array( 'object_subtype' => 'books' )—to register_meta() and $object_subtype = '' has been added as an extra argument to several other pieces as a way to support that.

After exploring a bit more, it’s clear that $object_subtype will continue to spread as an additional argument throughout many _meta() functions so that registered meta is handled properly.

An alternative is to use CURIEs to describe complex meta types in a single string—'comment:reaction' rather than 'comment' and 'reaction'—so that the extra argument is not needed. Instead, processing exists to turn that string into an object type and subtype.

Examples

  • post:post
  • post:books
  • term:category
  • user:user
  • comment:reaction

The main question for today’s discussion

Is CURIE like notation the right way forward for handling complex meta types?

Decisions

After a very good and thorough conversation about the above and other points, these are the decisions for moving forward with work on #35658:

  1. Meta keys will be registered using CURIE like syntax.
    • register_meta( 'post:book', 'isbn', $args );
  2. The : used in the string to register meta keys will also be used in filters.
    • sanitize_post:book_meta_isbn
  3. CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. object types will fallback to default subtypes if one is not specified.
    • post becomes post:post, comment becomes comment:comment, user becomes user:user, and term becomes term:categoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging..
  4. Meta key registration for all/any subtypes of an object type will not be included in 4.6, but is likely something to add in the future.

Please check out the latest patches on #35658 and contribute code and thoughts on that ticketticket Created for both bug reports and feature development on the bug tracker. or share any questions/concerns in the discussion below.

Thanks everyone for attending today!

#4-6, #options-meta

register_meta() discussion on Thursday, July 14

Howdy!

There will be a meeting in #core at Thursday July 14, 19:00 UTC to discuss the changes in register_meta() for the 4.6 release. The dev notes have been published, but there is still work to be done to ensure things are great.

Of particular interest is a proposal to change to a CURIE like notation when working with the registration of 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.. Instead of using two arguments (object type and subtype), there would be one argument containing both.

As an example, If a post type was registered with books as the slug and ISBN was stored as sanitized meta:

// In WordPress 4.5
register_meta( 'post', 'isbn', 'my_sanitize_callback' );

// In current trunk for 4.6
register_meta( 'post', 'isbn', array( 'object_subtype' => 'books', 'sanitize_callback' => 'my_sanitize_callback' ) );

// After proposed change
register_meta( 'post:books', 'isbn', array( 'sanitize_callback' => 'my_sanitize_callback' ) );

Please stop in #core at Thursday July 14, 19:00 UTC tomorrow if you are interested. If you can’t make it, please leave a comment on this post with your thoughts.

#4-6, #fields-api, #options-meta

Multisite Focused Changes in 4.6

The 4.6 release cycle has been a productive one! Several major and a few minor updates are described in detail below. If you’d like even more detail, here is a full list of 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 focused changes for 4.6.

Introduce WP_Site_Query and WP_Network_Query

WordPress 4.6 introduces WP_Site_Query and WP_Network_Query as well as their companion functions, get_sites() and get_networks().

WP_Site_Query

With WP_Site_Query (or get_sites()), sites can now be queried from the $wpdb->blogs table in a flexible way by id, domain, path, and more. For a full list of supported arguments, see the documentation attached to the __construct() method.

New filters and actions associated with this change include parse_site_query, pre_get_sites, the_sites, site_search_columns, sites_clauses, and found_sites_query.

Query results are cached as part of the global sites group. This will provide a performance boost for sites using a persistent object cache.

The introduction of this class helped resolve several long standing issues with WP_MS_Sites_List_Table. Expect to see a faster and more relevant search when browsing through a networknetwork (versus site, blog)’s sites. See #36675.

For the background discussion around these changes, see #35791.

WP_Network_Query

With WP_Network_Query (or get_networks()), networks can now be queried from the $wpdb->site table by id, domain, and path. Query results are cached as part of the global networks group. For a full list of supported arguments, see the documentation attached to the __construct() method.

WordPress coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. does not provide a UIUI User interface for managing multiple networks, but any sites using 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 to do this will start to see a benefit from having this available.

New filters and actions associated with this change include parse_network_query, pre_get_networks, the_networks, networks_clauses, and found_networks_query.

For the background discussion around these changes, see #32504.

Enhancements to WP_Site and WP_Network

New utility methods

New functions get_site() and get_network() have been introduced to retrieve a specific site or network respectively. They both accept either an ID, database object or class instance as the first parameter. If that parameter is omitted, the current site / network is returned.

Property changes on WP_Site and WP_Network

The WP_Site and WP_Network objects now support access to their respective ID properties through property names which match current naming conventions. Furthermore, by accessing the properties with the new names, it is ensured that these are returned as integers rather than strings. The old properties are still accessible and valid, but these changes should encourage developers to use the new property names.

The following is the list of property improvements:

  • $site->id is the site’s ID. (previously $site->blog_id)
  • $site->network_id is the site’s parent network ID. (previously $site->site_id)
  • $network->id is now an integer instead of a string.
  • $network->site_id is the network’s main site ID. (previously $network->blog_id)

For background discussion around these changes, see #36717 and #37050.

Lazy-loading extended properties

Additional properties of a site object normally accessed with get_blog_details() are now automatically lazy-loaded when requested. This allows developers to use get_site() as a replacement for get_blog_details() which is likely to be deprecated in a future release. See #36935.

New Actions and Filters

Several new actions and filters were added as part of the WP_Site_Query and WP_Network_Query changes. Here are some others of note:

  • ms_loaded fires at the end of the multisite bootstrap process in ms-settings.php. At this point the current site and network are available in the global scope. See #37235.
  • pre_get_blogs_of_user allows developers to alter or short-circuit the results of get_blogs_of_user(), which can be an expensive function to run on configurations with many users. See #36707.
  • clean_site_cache fires after cache has been cleared with clear_blog_cache(). This can be useful for clearing any custom cache keys associated with a site record. See #36203.
  • network_edit_site_nav_links filters the list of links displayed at the top of Edit Site views as a “tabbed” interface. See #15800.
  • ms_sites_list_table_query_args filters the arguments passed to WP_Site_Query when building the MS Sites List Table. See #26580.

Other enhancements of note

Introduce get_current_network_id() as a helper function to find the current network’s ID. See #33900.

The MULTISITE and SUBDOMAIN_INSTALL constants can now be overridden in a project’s wp-config.php when running unit tests. See #36567.

Deprecated Functions

wp_get_sites() has been deprecated and get_sites() should be used instead. Please note when making code changes that get_sites() returns an array of WP_Site objects where wp_get_sites() returned an array of arrays.

WP Multi Network compatibility

The introduction of get_networks() in 4.6 conflicts with the function of the same name in WP Multi Network, a plugin commonly used to provide multiple networks on a multisite installation. A fix for this is already in the master branchbranch A directory in Subversion. WordPress uses branches to store the latest development code for each major release (3.9, 4.0, etc.). Branches are then updated with code for any minor releases of that branch. Sometimes, a major version of WordPress and its minor versions are collectively referred to as a "branch", such as "the 4.0 branch". of the plugin, and will be included in the next release. In the same change, many other functions were wrapped in function_exists() calls to prevent similar conflicts in the future. If you are using WP Multi Network, please be sure to update accordingly.

#4-6, #dev-notes, #multisite, #network-sites

Enhancing register_meta() in 4.6

Note: The direction of register_meta() has changed since this was published. Please see the most recent developer note explaining these changes.

In 4.6, register_meta() expands to support the registration of meta keys and what to expect from those keys. See #35658 for the discussion around this change.

The behavior of register_meta() is similar to register_post_type() in that the registration of this data is stored in the global scope. This makes an object’s meta data more accessible to parts of core and extending code.

Why make this change

In 4.5 and earlier, WordPress provided no method to explicitly register a meta key’s public state. Instead, register_meta() provided “protected” and “authenticated” meta. This can be used effectively for some things, particularly to determine what meta appears in the Custom Fields metabox when editing a post. It can not be used as a basis for arbitrarily showing meta keys and values to unauthenticated visitors.

What does this change involve

A global variable, $wp_meta_keys, contains all registered meta keys.

The function signature of register_meta() has changed to support 3 arguments, the last being an array. That array should contain data about the meta with these key/values:

  • sanitize_callback, a callable method to provide sanitization. This is the new version of the current 3rd parameter in register_meta().
  • auth_callback, a callable method to provide authorization. This is the new version of the current 4th parameter in register_meta().
  • object_subtype, a string containing an object subtype slug. If there is no object subtype, meta will not be registered and a WP_Error will be returned instead.
  • type, a string indicating what type of data the meta value will be. This is intentionally not restricted to a specific list of data types, however full names should be used when possible. (e.g. boolean, integer)
  • description, a string containing a basic description of the meta value.
  • single, whether code retrieving meta for this key should expect a single or multiple values when using something like get_post_meta().
  • show_in_rest, whether this should be shown as part of a post’s meta endpoint in the WordPress REST API. Note that this should be treated as experimental until the WordPress REST API provides support for meta.

The register_meta_args filter is available to add support for additional arguments. This need to explicitly whitelist further arguments is to reserve the right for core to add further arguments in the future; should you choose to use this filter, you should be prepared to follow along with further development. Your testing with trunk or betas is greatly appreciated!

By default, only WordPress core object types (post, user, term, comment) can be registered. To add support for custom object types, use the wp_object_types filter. This whitelisting is similar to the above.

Object sub types provide specific registration of meta keys to a type of data.

  • A standard WordPress post has an object type of “post” and an object subtype of “post”.
  • A custom post type registered with a slug of “my_cpt” has an object type of “post” and an object subtype of “my_cpt”.
  • A WordPress user has an object type of “user” and an object subtype of “user”.
  • A standard WordPress comment has an object type of “comment” and an object subtype of “comment”.
  • A standard WordPress category term has an object type of “term” and an object subtype of “category”.
  • A custom taxonomy registered with a slug of “my_tax” has an object type of “term” and an object subtype of “my_tax”.

Meta keys must be explicitly registered for each object type and subtype combination.

Additional helper functions get_registered_metadata(), get_registered_meta_keys(), unregister_meta(), and registered_meta_key_exists() have been added to make the innards of the global data more accessible.

The $wp_meta_keys variable should not be altered directly. It is possible that its structure will change in the future.

Any code currently using register_meta() and expecting pre-4.6 behavior will continue to work as is. Please report any breaks in compatibility that might be found.

Example

Here’s what registering meta looked like in 4.5. This meta key has sanitization and authorization callbacks.

register_meta( 'post', 'my_meta_key', 'sanitize_my_meta_key', 'authorize_my_meta_key' );

The above code will continue to work in 4.6, though will not be considered completely registered. The callbacks will be registered, but the key will not be added to the global registry. A WP_Error object will be returned with this explanation.

Here’s what registering meta looks like in 4.6. This meta key will have sanitization and authorization callbacks, and be registered as public for the WordPress REST API.

$args = array(
    'object_subtype' => 'post',
    'sanitize_callback' => 'sanitize_my_meta_key',
    'auth_callback' => 'authorize_my_meta_key',
    'type' => 'string',
    'description' => 'My registered meta key',
    'single' => true,
    'show_in_rest' => true,
);
register_meta( 'post', 'my_meta_key', $args );

If you are currently using register_meta() and would like to maintain support for older versions of WordPress, the best method will be to check for the registration of the sanitization and authorization callbacks after calling register_meta() and then registering them manually if not present. This manual registration is all that register_meta() was previously doing. Continuing from the example above:

// Pre-WordPress 4.6 compatibility
if ( ! has_filter( 'sanitize_post_meta_my_meta_key' ) ) {
    add_filter( 'sanitize_post_meta_my_meta_key', 'sanitize_my_meta_key', 10, 4 );
}

if ( ! has_filter( 'auth_post_meta_my_meta_key' ) ) {
    add_filter( 'auth_post_meta_my_meta_key', 'authorize_my_meta_key', 10, 6 );
}

What’s next

While the initial work on this is largely driven by the need to move the WordPress REST API forward, its scope is not limited to solving the problem of public access to metadata. By having information about the meta keys used in a code base, it becomes much easier for other pieces of code to make decisions about what can be done with this data.

This data can one day be useful to everything from the Customizer, the editing experience for all object types, the Fields API, and many plugins that rely on metadata. Work will continue on transforming this $wp_meta_keys object and the methods surrounding it to be flexible and explicit. As WordPress core becomes familiar with register_meta() and more confident in the approach, the set of default arguments can and likely will expand to include more data about registered meta keys as required.

Feedback

Please leave any feedback you have on this new iteration of register_meta() in the comments below. Test it out in your plugins and themes to be sure it is working in a backwards compatible way. Try out the new function signature and register meta for objects and their subtypes. This continues to be a work in progress and feedback is important.

#4-6, #dev-notes, #fields-api, #options-meta, #rest-api