Skip to content

REST API endpoints for sites - #13055

Open
lloc wants to merge 24 commits into
WordPress:trunkfrom
lloc:feature/40365-rest-sites-endpoint
Open

lloc wants to merge 24 commits into
WordPress:trunkfrom
lloc:feature/40365-rest-sites-endpoint

Conversation

@lloc

@lloc lloc commented Aug 14, 2026

Copy link
Copy Markdown

Trac ticket: https://core.trac.wordpress.org/ticket/40365

There are some open questions that we should discuss in the trac ticket.

@github-actions

github-actions Bot commented Aug 14, 2026 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @jonnydmg.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

Core Committers: Use this line as a base for the props when committing in SVN:

Props realloc, spacedmonkey, peterwilsoncc, biont.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@jonnydmg jonnydmg left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a big PR to review. Good work getting this ready for core. This code a little old and some things have changed in core, so this PR needs to update accordingly.

Biggest things.

  • We need to support sites with is_site_meta_supported false. There was some work done there to support it but not complete.
  • Site endpoint needs to be registered on single site. So it always exists then return an error on single site.
  • WP_REST_Site_Meta_Fields has no test coverage at all.
  • Single site needs tests.
  • Super admin should be allowed to do everything on the endpoint.
  • Code coverage and ticket need needs to be added to every test.

This feel like we are on the right track, if I am nitpicing here, becuase I think this good to go into core and just want to get the final bits to push forward into core.

I will wait until feedback is complete to do some real testing for this PR.

Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php Outdated
* @since 7.2.0
*
* @group restapi
* @group ms-required

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have another test file for with all the tests related to it not being multisite, as there are lots of checks for is_mulitiste. There are so many this feels like a good fit for another file instead of excloding each test one at a time.

Comment thread src/wp-includes/rest-api.php Outdated
Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php Outdated
Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php Outdated
Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php Outdated

@jonnydmg jonnydmg left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a big PR to review. Good work getting this ready for core. This code a little old and some things have changed in core, so this PR needs to update accordingly.

Biggest things.

  • We need to support sites with is_site_meta_supported false. There was some work done there to support it but not complete.
  • Site endpoint needs to be registered on single site. So it always exists then return an error on single site.
  • WP_REST_Site_Meta_Fields has no test coverage at all.
  • Single site needs tests.
  • Super admin should be allowed to do everything on the endpoint.
  • Code coverage and ticket need needs to be added to every test.

This feel like we are on the right track, if I am nitpicing here, becuase I think this good to go into core and just want to get the final bits to push forward into core.

I will wait until feedback is complete to do some real testing for this PR.

Introduces WP_REST_Sites_Controller plus tests.
See #40365.
@lloc
lloc force-pushed the feature/40365-rest-sites-endpoint branch from aa03545 to cc81250 Compare August 22, 2026 07:51
@spacedmonkey

Copy link
Copy Markdown
Member

@lloc I have put together a little PR for tests for all the meta changes -lloc#1

@spacedmonkey spacedmonkey left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a PR with some unit test improvements.

lloc#2

This is has unit tests that cover single site as well.

Comment thread tests/phpunit/tests/rest-api/wpRestSitesController.php
lloc and others added 7 commits September 2, 2026 15:48
…oint-tests

Tests: Add unit tests for WP_REST_Site_Meta_Fields functionality
…oint-more-tests

Tests: Rename rest-sites-controller.php to wpRestSitesController.php …
Add format validation for the `domain` and `path` parameters in
WP_REST_Sites_Controller so malformed values are rejected with a clean
400 rest_invalid_param instead of failing later inside wp_insert_site()/
wp_update_site() (which surfaces as a 500).

domain must be a valid hostname or bare IPv4/IPv6 address, optionally
followed by a port (bracketed IPv6 is intentionally not supported, so
IPv6 addresses can't carry a port). path must start and end with a
forward slash and be made up of characters valid in a URL path segment.

Ticket #40365.
…t-check-exists' into feature/40365-rest-sites-endpoint-check-exists

# Conflicts:
#	src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php
@spacedmonkey

Copy link
Copy Markdown
Member

I have more feedback here.

lloc#4
lloc#3

This fixes some issues that were flagged by ai.

…oint-force-delete

Enhance site deletion process to support force deletion and user removal
…oint-check-exists

Check if domain exists before creating / updating.
Comment thread tests/qunit/fixtures/wp-api-generated.js Outdated
Comment thread tests/phpunit/tests/rest-api/wpRestSiteMetaFields.php Outdated

@peterwilsoncc peterwilsoncc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a few notes inline.

The highest priority issue is the permission check revealing whether or not a site exists to unauthenticated/unauthorized users.

Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php Outdated
Comment on lines +183 to +203
$parameter_mappings = array(
'domain' => 'domain__in',
'domain_exclude' => 'domain__not_in',
'exclude' => 'site__not_in',
'include' => 'site__in',
'offset' => 'offset',
'order' => 'order',
'network' => 'network__in',
'network_exclude' => 'network__not_in',
'per_page' => 'number',
'path' => 'path__in',
'path_exclude' => 'path__not_in',
'search' => 'search',
'public' => 'public',
'archived' => 'archived',
'mature' => 'mature',
'spam' => 'spam',
'deleted' => 'deleted',
'lang_id' => 'lang__in',
'lang_id_exclude' => 'lang__not_in',
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wp_blogs table includes only a couple of indexes:

  • blog_id (blog_id) -- Primary key
  • domain (domain(50),path(5))
  • lang_id (lang_id)

I think it would be good to reduce the list of get parameters down a little to avoid allowing site users to construct very inefficient queries.

I'm not suggesting removing all of the unindexed parameters but being a little picky about those that are included. For example I think network and network_exclude would need to be retained but some consideration can be taken to public, archived, etc.

One approach may be to limit the query to type = (public|archived...).

return true;
}

return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit sites.' ), array( 'status' => rest_authorization_required_code() ) );

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a read not an edit request.

if ( is_wp_error( $site ) ) {
return $site;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this down to after the context/current_user_can( 'manage_sites' ) check.

Placed here it will reveal to unathorized users whether the site exists, so people will be able to figure out the size of the network.

On an MS instance with fewer than 5000 sub-sites, visit http://localhost/wp-json/wp/v2/sites/5000 while logged out to see what I mean.

🔢 Note, this applies to most of the permission checks so you'll need to make this change throughout.

Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php Outdated
Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php Outdated
* @param WP_REST_Request $request The current request.
* @return true|WP_Error True if the domain and path are available, WP_Error otherwise.
*/
protected function check_domain_is_available( $prepared_site, $request ) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
protected function check_domain_is_available( $prepared_site, $request ) {
protected function check_url_is_available( $prepared_site, $request ) {

It checks both domain and path. This will require changes elsewhere.

@Biont

Biont commented Sep 24, 2026

Copy link
Copy Markdown

Quick question: Does this entirely supersede #9626? Let me know if there are any gaps or if we can simply close the other one.

lloc and others added 3 commits September 28, 2026 07:01
…ler.php

Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com>
…ler.php

Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com>
…ler.php

Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants