Skip to content

63946: Add "resolvable" routes for the REST API#11606

Open
rmccue wants to merge 6 commits intoWordPress:trunkfrom
rmccue:lazy-load-rest-route-options
Open

63946: Add "resolvable" routes for the REST API#11606
rmccue wants to merge 6 commits intoWordPress:trunkfrom
rmccue:lazy-load-rest-route-options

Conversation

@rmccue
Copy link
Copy Markdown
Contributor

@rmccue rmccue commented Apr 20, 2026

Adds the ability to register just-in-time resolvable routes for the REST API.

When calling register_rest_route(), you can now pass a function instead of the options for the route directly:

// Before:
register_rest_route( 'example/v1', '/ping', [
	'callback' => 'ping_callback',
	'permissions_callback' => '__return_true',
	'args' => [
		'foo' => [
			'required' => true,
			'type' => 'string',
		],
	],
	'schema' => $this->get_schema(),
] );

// After:
register_rest_route( 'example/v1', '/ping', fn () => [
	'callback' => 'ping_callback',
	'permissions_callback' => '__return_true',
	'args' => [
		'foo' => [
			'required' => true,
			'type' => 'string',
		],
	],
	'schema' => $this->get_schema(),
] );

This has the benefit that any more expensive operations (translations, args-to-schema building, etc) are only run for matched routes, rather than all of them. But, routing is still possible without this (including listing all available namespaces).

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

See also #10080


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 20, 2026

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.

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

Props rmccue, swissspidy, kraftbj.

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.

@rmccue
Copy link
Copy Markdown
Contributor Author

rmccue commented Apr 20, 2026

(cc @prettyboymp @kraftbj for feedback too, as an alternative to #10080)

@swissspidy
Copy link
Copy Markdown
Member

Love the ergonomics of this approach 👍

@kraftbj
Copy link
Copy Markdown

kraftbj commented Apr 20, 2026

On first glance, these two approaches seem complementary rather than competing, as they tackle 63946 at different layers of the stack.

#10080 defers at the namespace boundary: register_rest_route() never runs for a namespace that isn't matched, which also sidesteps whatever REST-only setup plugins put alongside registration — controller instantiation, register_rest_field, schema construction, boot-time translations, etc.

This one defers at the options boundary: register_rest_route() still runs for every route, but the options array (schema building, args-to-schema, translated strings inside the definition) is only materialized when that specific route is dispatched. Finer-grained & great for routes with heavy schemas, but inside the register call, not around it.

The two stack nicely. We could register a lazy namespace via #10080, and in the action that loads it, use resolvable options for any routes with expensive schemas that might still not be the one hit. Skip the namespace entirely, then if the namespace is hit, skip option construction for non-dispatched routes, and then only fully resolve the actually matched route.

tl;dr: :why-not-both.gif:

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.

3 participants