Skip to content

Presets: carry the block instance, and the right post id, in the preset context - #41

Draft
mattheu wants to merge 4 commits into
mainfrom
feature/preset-callback-block-param
Draft

mattheu wants to merge 4 commits into
mainfrom
feature/preset-callback-block-param

Conversation

@mattheu

@mattheu mattheu commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

The gap

The $context param passed to apply_query_preset passes some data, but it would be great if it just passed the full WP_Block object. (In all honesty, I'm not sure why the old code passes a property called block that contains pagination data. But I don't want to break anything using this)

Reson for this - a preset can't read block context: no termId/taxonomy inside a Term Template, no postId, nothing core puts there. $context['block'] looks like it should be the block and isn't — it is a two-key array of perPage and page.

The fix

Carry the block in the context array that already exists, as block_instance:

$term_id = $context['block_instance']?->context['termId'] ?? 0;

No signature change. The callback is still function ( array $query_vars, array $context ): array, so every preset already registered keeps working without being touched.

Not named block — that key is taken and presets read it, so renaming it is breaking and out of scope. block_instance matches the "Block instance" vocabulary already in the file's docblocks, and says out loud what the older key isn't.

modify_rest_query_for_preset() sets it to null explicitly rather than omitting the key, so the context has one shape in both paths and a preset can read it with ?-> and no isset() check.

$block is null on REST

The editor preview fetches from the collection endpoint rather than rendering the block, so there is no instance to carry. That is inherent, not a gap being papered over: a preset depending on block context behaves differently in the preview from the front end, and the README says so plainly.

Behaviour change: post_id now follows the block

Worth reading rather than skimming — this is the one thing in here that can change an existing preset's output.

post_id was get_the_ID(), which reads global loop state. It is now $block->context['postId'], falling back to get_the_ID(). The block context is what core resolved for that specific block; the global post is whatever the outer loop happens to be on. On a singular template they agree. Where they diverge, a preset keying off post_id will now get a different post — the one it should have had, but a different one.

It is its own commit (Presets: take post_id from the block, not the global loop) if you want to weigh it separately.

Testing instructions

  • npm run test:php — exit 0. Runs the existing exclusion planner tests (27 checks) plus the new tests/php/query-presets-test.php (10 checks), which drives the real inc/query-presets.php against stubs: the block reaches the callback through $context['block_instance'], is null on REST with the key still present, a preset can read termId off it, $context['block'] is still pagination metadata, and post_id prefers block context over the global.
  • Negative controls, both run: deleting 'block_instance' => $block fails 2 checks; reverting post_id to get_the_ID() fails 1.
  • composer install && vendor/bin/phpcs — exit 0.
  • Playwright e2e is unchanged and was not run. No fixture added to tests/mu-plugins/test-query-presets.php: the block instance has no frontend-observable effect query-presets.spec.js could assert without inventing one, so an unasserted fixture would be noise.

No version bump (the release workflow stamps __VERSION__), no built assets.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Playwright test results — WP 7.1

passed  26 passed

Details

stats  26 tests across 8 suites
duration  1 minute, 53 seconds
commit  9f99e05

@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Playwright test results — WP 7.0

passed  26 passed

Details

stats  26 tests across 8 suites
duration  1 minute, 50 seconds
commit  9f99e05

@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Playwright test results — WP 6.9

passed  26 passed

Details

stats  26 tests across 8 suites
duration  1 minute, 33 seconds
commit  9f99e05

@mattheu mattheu changed the title Presets: give the callback the block it is rendering in Presets: carry the block instance, and the right post id, in the preset context Oct 6, 2026
mattheu and others added 2 commits October 6, 2026 17:32
A preset callback could see query vars and a small context array, but never
the WP_Block, so it could not read block context: no termId or taxonomy
inside a Term Template, no postId, nothing core puts there. The frontend
filter is handed the block, reads its context to find the preset name, and
then throws it away.

Put it in the context array as 'block_instance'. The callback signature does
not change, so every preset already written keeps working.

Not 'block': that key is taken, and holds perPage and page. It is misnamed,
but presets read it, so renaming it is breaking and stays out of scope —
which is exactly why the new key says "instance" out loud.

modify_rest_query_for_preset() sets it to null rather than omitting it, so
the context has one shape and a preset can write $context['block_instance']?->
without an isset dance. It is null there because the editor preview queries
the collection endpoint instead of rendering a block: there is no instance.
A preset leaning on block context will differ between preview and frontend,
and the docs say so rather than implying otherwise.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
filter_query_loop_block_query_vars() built 'post_id' from get_the_ID(), which
reads whatever post the global loop is on. The block's own context already
holds the post core resolved for that block, and the function reads that
context one statement earlier to find the preset name.

Prefer $block->context['postId'], falling back to get_the_ID(). On a singular
template the two agree; they diverge wherever the global post is not what the
block is rendering for.

This is a behaviour change, not a refactor: a preset keying off 'post_id'
in a context where the two differ will now get a different post. That is the
post it should have had, but it is worth saying plainly rather than finding
out in production.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mattheu
mattheu force-pushed the feature/preset-callback-block-param branch from 8933955 to 8d8e560 Compare October 6, 2026 16:32
mattheu and others added 2 commits October 6, 2026 17:36
Prose only; no executable line changes.

CLAUDE.md describes how the plugin works now, so it cannot lean on a before
and after. Drop "already holds" and the sentence about the signature being
unchanged: backward compatibility is a fact about a change, not about the
plugin, and a reader arriving later has nothing to compare it to.

"Code for that rather than expecting a block" told nobody what to do. Say the
actual instruction: check block_instance, return $query_vars unchanged when
it is null.

"isset dance" is a figure of speech. Say what it means. Likewise "front end"
as a noun, and label the Term Template snippet as illustrative so nobody goes
looking for a preset the plugin does not ship.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The README still told the reader the callback signature was unchanged. That
is a fact about a pull request, not about the plugin, and whoever opens the
README later has no prior version to hold it against. Deleted rather than
reworded: the new key lives inside the $context array, so there is no
parameter for a callback to decline, and saying so would be noise.

Split the CLAUDE.md REST line, which was a colon joining three clauses, into
one idea per sentence. The reference to modify_rest_query_for_preset() moves
into its own sentence rather than being carried parenthetically.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.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.

1 participant