perf(helpers): memoize acf_get_fields() per group - #156
Merged
Conversation
`getFieldObjectsByScreen()` asked ACF for a group's fields once per group per screen. On the sloneek front page that is 348 calls producing 21 distinct answers, because a 90-item menu resolves the same group ninety times. Measured on the work removed rather than on the page: 26-38 ms falls to 5-8 ms. End to end the page moved 16-34 ms across two rounds; the machine drifted between them, so the direct measurement is the one to trust. **This needs no invalidation, and that is the point.** Field definitions are configuration — theme JSON, not anything a visitor changes — so the memo lives for the request and nothing has to notice when it should die. A field *value* is the opposite, which is why the parked #155 could not do the same thing one layer up. The key carries the blog id and the language for the reasons the screen memo's does: groups are registered per site, and ACFML translates a field's label, instructions and choices. A group carrying neither a key nor an id has no identity and is asked every time, rather than sharing one entry with the next anonymous group. Output is byte-identical against a control pair of runs.
parisek
force-pushed
the
perf/memoize-group-fields
branch
from
August 27, 2026 12:35
594d6f2 to
189e81e
Compare
This was referenced Aug 27, 2026
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.
From which project
sloneek, from the profiling that produced #154. Stacked on #154 — the base isperf/memoize-capability-probes, so this diff shows only the new change; GitHub retargets tomainwhen #154 merges.The finding
getFieldObjectsByScreen()asks ACF for a group's fields once per group per screen. A 90-item menu resolves the same group ninety times.That is measured on the work removed. End to end the page moved 16-34 ms across two rounds — the same saving through a noisier instrument, and the machine drifted between them, so the component figure is the one to trust.
Rendered HTML is byte-identical, checked against a control pair of runs of the unchanged code because the page is not deterministic without one.
Why this one needs no invalidation
Field definitions are configuration, not content. They come from the theme's JSON, they do not depend on the page being rendered, and nothing a visitor does changes them. The memo lives for the request, and there is nothing for a hook to notice.
A field value is the opposite, which is exactly why #155 is parked: caching one layer up meant caching formatted output, and formatting runs shortcodes and arbitrary filters that can read the current page. The two look like the same optimisation and are not.
The key carries the blog id and the language for the same reasons the screen memo's does — groups are registered per site, ACFML translates a field's label, instructions and choices. A group carrying neither a key nor an id has no identity to memoize on and is asked every time, rather than sharing an entry with the next anonymous group.
What was tried and did not work
Recorded so nobody repeats it. All measured on the front page, all rejected:
get_field()where the item has no stored metaWhat remains unclaimed on this path is
get_field()for the 66 menu-item fields that hold a value (37-68 ms) andwp_get_post_terms()(9-16 ms, removable only by threading the known menu id throughformatFields()).Tests
Nine, each verified to fail without the memo where it is the mechanism under test: one group asked once, identity by
keyand byID, an anonymous group asked every time, separation by language and by blog, a non-array answer normalized, and the flush.