Repository navigation
REST API: Main-site-only sites endpoint, tighter response and a single user parameter - #12
Merged
lloc merged 3 commits intoOct 8, 2026
Conversation
…esponse.
Following the review on PR 13055, the sites endpoint now behaves like the
network admin and is only usable from the network's main site:
- Create, update, delete and single-site reads return a 403
`rest_cannot_{create,edit,delete,view}_not_on_main_site` error from any
other site.
- Listing your own sites (`user=me` or your own ID) and a member reading
their site stay available from any site, but only in the view context.
- Users listing their own sites cannot filter or order by fields outside
the view context (`rest_forbidden_param`), so hidden values cannot be
inferred.
- The status flags, dates, `lang_id`, `post_count` and the site meta are
now edit-context only.
- Add a read-only `admin_url` field and build `home` and `siteurl` with
get_home_url() and get_site_url(), so their filters apply.
- Replace the write-only `title` property with a create-only, writable
`blogname`, and move `user_id` out of the schema into the create route
arguments. A POST to an existing site no longer runs the create path.
- Skip the site queries when the user filter matches no sites, while
still firing `rest_site_query`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The collection filter `user` and the create-only `user_id` argument described the same relationship under two names. Both are now `user`, sharing one schema that accepts a positive user ID or "me", and get_user_id_from_param() resolves "me" to the current user. - Invalid values such as `xyz`, `0`, `-1` or an empty string are now rejected with `rest_invalid_param` before the permission check. - Numeric strings are sanitized to integers. - An unknown administrator on creation returns `rest_user_invalid_id`. - Listing the sites of another user requires the capability to manage sites (`rest_forbidden_user`). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Both read permission checks reject `context=edit` up front with `rest_forbidden_context` unless the user can manage sites, before the member, main-site and site lookup checks, so an edit-context request does not reveal whether a site exists. - get_items_permissions_check() resolves the own-user filter once and reuses it for the other-user check, so a logged-out `user=me` now returns `rest_forbidden_user`. - The check against filtering or ordering by fields outside the view context now applies to every user without the capability, and still runs before the own-sites exemption. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
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 Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses the feedback on WordPress#13055: the sites endpoint should work from the network's main site only, with the "my sites" use case kept narrow and read-only.
Main site only
rest_cannot_create_not_on_main_site,rest_cannot_edit_not_on_main_site,rest_cannot_delete_not_on_main_siteandrest_cannot_view_not_on_main_site.viewcontext only:user=meor your own ID)embedis no longer exempt for members.Permissions
context=editrequiresmanage_siteson both the collection and single-site routes (rest_forbidden_context). This is checked before the site is looked up, so it doesn't reveal whether a site ID exists.manage_sites(rest_forbidden_user).manage_sites, filtering or ordering by fields outside the view context is rejected (rest_forbidden_param). Those fields arearchived,mature,spam,deleted,lang_id,lang_id_exclude,before,after, andorderby=registered|last_updated.Response and schema
registered,registered_gmt,last_updated,last_updated_gmt,archived,mature,spam,deleted,lang_id,post_countand the registered site meta, which may hold sensitive data.admin_urlfield, built withget_admin_url().homeandsiteurlnow come fromget_home_url()andget_site_url(), so thehome_urlandsite_urlfilters apply.titleduplicatedblogname, sincewp_initialize_site()stores the title asblogname. It's gone:blognameis now writable when a site is created and ignored on update. Backslashes are kept./sites/{id}is an update, so it no longer runs the create-only path.A single
userparameteruserand the create-onlyuser_idare now oneuserparameter. It is validated to accept a positive user ID or"me", andget_user_id_from_param()resolves"me"to the current user.xyz,0,-1, an empty string, a list) are rejected withrest_invalid_param.rest_user_invalid_id.Other changes
get_itemsskips both site queries and still firesrest_site_query, so a plugin can widen the result.Testing
npm run test:php -- -c tests/phpunit/multisite.xml --filter 'WP_Test_REST_Sites_Controller|WP_Test_REST_Site_Meta_Fields': 254 tests pass.restapigroup only failsTest_oEmbed_Controller::test_proxy_with_classic_embed_provider, which also fails without these changes.composer lintandcomposer phpstanare clean.tests/qunit/fixtures/wp-api-generated.jsis regenerated for the changed args.🤖 Generated with Claude Code