[wp-trac] [WordPress Trac] #63946: Introduce a mechanism for lazy-loading REST routes and handlers

WordPress Trac noreply at wordpress.org
Mon Apr 20 09:22:58 UTC 2026


#63946: Introduce a mechanism for lazy-loading REST routes and handlers
--------------------------------------+------------------------------
 Reporter:  prettyboymp               |       Owner:  (none)
     Type:  enhancement               |      Status:  new
 Priority:  normal                    |   Milestone:  Awaiting Review
Component:  REST API                  |     Version:
 Severity:  normal                    |  Resolution:
 Keywords:  has-patch has-unit-tests  |     Focuses:  performance
--------------------------------------+------------------------------

Comment (by rmccue):

 Replying to [comment:8 prettyboymp]:
 > 1. **`rest_endpoints` filter**: `get_routes()` passes `$this->endpoints`
 through this filter (line 968). Plugins iterating the filtered data expect
 arrays, not Closures — storing Closures in `$this->endpoints` would break
 them.

 Any API change here is going to break ''something'', but I take the point
 there. We could handle the  with a back-compat wrapper class for any
 callable which implements ArrayAccess - it's a little unclean on the
 implementation (core) side in that sense, but should work.

 [https://3v4l.org/v6Xio#v8.4.18 Here's an example implementation], tested
 against [https://3v4l.org/v6Xio#v8.4.18 code from Really Simple Security].
 The Resolvable class here implements just-in-time resolution for any
 callable, so actually we likely wouldn't need to change the Server code
 itself either. I'll see about spinning up a PR for this.

 Note that I didn't bother adding the single-to-multiple array
 normalisation here for now - we'd need to make a decision as to whether
 the callback can provide multiple endpoints or not. I'm leaning no,
 because it makes it impossible to merge together later, which is necessary
 for registering GET/POST as separate calls.

 (Aside: This form of resolution has a secondary benefit, which is that
 it's more conducive to [https://www.npopov.com/2014/02/18/Fast-request-
 routing-using-regular-expressions.html FastRoute-style optimisations] (eg
 "put all the routes in a big regex and offload the loop to PCRE"). Typical
 sites are getting to the point that they have enough routes to make this
 approach one worth considering now; ideally, having the method as well as
 the URL would allow off-the-shelf usage of FastRoute, but that's a very
 minor optimisation/design choice.)

 > 2. **`rest_send_allow_header()`**: Calls `$server->get_routes()` without
 a namespace parameter on every REST response (line 880), which would force
 resolution of all Closures, not just the matched route's. This also runs
 per-item via `get_target_hints_for_link()` in collection responses.

 This should be fixed with the resolvable concept too. The only time a
 route's definition is "resolved" is when it's used, so we only need to
 resolve the matched route here.

 > On the point that "registering the namespaces and their routes isn't
 expensive, rather it's the argument building that's slow" — the
 registration itself is cheap, but having more entries in
 `$this->endpoints` has a per-request cost beyond route matching.
 `rest_send_allow_header()` calls `get_routes()` without a namespace
 parameter (line 880), so on every REST response the full endpoints array
 is copied, passed through the `rest_endpoints` filter, and normalized
 (lines 979-1016). This also runs per-item via
 `get_target_hints_for_link()` in collection responses. Every registered
 route — even ones whose namespace doesn't match the current request — adds
 to that cost.

 That's a downstream issue, imo, whereas I'm talking mostly about the broad
 question of "what currently makes the REST API slower (and/or more memory
 hungry) than it should be?" The answer to that is basically a) slow string
 operations of all sorts (translation, etc etc), and b) schema resolution
 (eg to build args from a schema). Neither of those actually need doing for
 any route you're not actively using, hence my reasoning behind offloading
 just the endpoint options.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/63946#comment:9>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list