Skip to content

Register hmUrlTabVisibility attribute server-side for all block types - #3

Open
mattheu wants to merge 10 commits into
mainfrom
fix/register-tab-visibility-attribute-server-side
Open

mattheu wants to merge 10 commits into
mainfrom
fix/register-tab-visibility-attribute-server-side

Conversation

@mattheu

@mattheu mattheu commented Jul 3, 2026 •

Copy link
Copy Markdown
Member

Summary

  • The JS editor filter adds `hmUrlTabVisibility` to all block types client-side, but there was no matching server-side registration
  • WordPress uses `additionalProperties: false` when validating the `attributes` parameter on the REST API block renderer endpoint, so any attribute unknown to the server causes a 400 error
  • This breaks `ServerSideRender` in any plugin that registers a custom block — the sanitized attributes sent by `ServerSideRender` include `hmUrlTabVisibility` (from the JS filter), but the server rejects it

Fix

Hooks into registered_block_type (fired after every register_block_type() call) to add hmUrlTabVisibility to the server-side WP_Block_Type object, mirroring the existing JS filter exactly — all blocks except core/navigation-link.

Test plan

  • Activate alongside a plugin that uses ServerSideRender for a custom block (e.g. hm-query-loop with the SSR preview PR)
  • Confirm the block renderer no longer returns rest_additional_properties_forbidden for hmUrlTabVisibility
  • Confirm existing tab visibility behaviour is unchanged on the frontend
Open WordPress Playground Preview

The JS editor filter adds hmUrlTabVisibility to all blocks client-side,
but without a matching server-side registration the REST API block
renderer rejects any request that includes the attribute. WordPress uses
additionalProperties:false when validating the attributes parameter, so
unrecognised attributes cause a 400 error.

Hooks into registered_block_type (fired after every register_block_type
call) to add the attribute to the server-side WP_Block_Type object,
mirroring the JS filter exactly — all blocks except core/navigation-link.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 3, 2026 •

Copy link
Copy Markdown

Playwright test results

skipped  10 skipped

Details

stats  10 tests across 2 suites
duration  12.2 seconds
commit  9dcc7ea

Skipped tests

chromium › multiple-endpoints.spec.js › Multiple endpoints - EP_CATEGORIES overview endpoint › Editor endpoint selector › endpoint selector appears in Tab Visibility panel with multiple registered endpoints
chromium › multiple-endpoints.spec.js › Multiple endpoints - EP_CATEGORIES overview endpoint › Editor endpoint selector › tab dropdown filters by selected endpoint
chromium › multiple-endpoints.spec.js › Multiple endpoints - EP_CATEGORIES overview endpoint › Editor endpoint selector › duplicate navigation blocks do not duplicate tabs in dropdown
chromium › multiple-endpoints.spec.js › Multiple endpoints - EP_CATEGORIES overview endpoint › category archive loads without endpoint
chromium › multiple-endpoints.spec.js › Multiple endpoints - EP_CATEGORIES overview endpoint › category archive loads with overview endpoint (no value)
chromium › multiple-endpoints.spec.js › Multiple endpoints - EP_CATEGORIES overview endpoint › category archive loads with overview endpoint and tab value
chromium › multiple-endpoints.spec.js › Multiple endpoints - EP_CATEGORIES overview endpoint › overview endpoint is distinct from tab endpoint on category archive
chromium › tab-navigation.spec.js › HM URL Tabs › should register tab variations for navigation links
chromium › tab-navigation.spec.js › HM URL Tabs › should show tab visibility controls when page has tabs
chromium › tab-navigation.spec.js › HM URL Tabs › should generate tab URLs correctly

The previous implementation accepted WP_Block_Type as the second action
argument, but that parameter was only added in WordPress 6.7. On older
installs the callback received null and silently did nothing.

Fix by accepting only the block name (1 arg, available since WP 5.0) and
looking the live object up from the registry directly.

Also add a rest_api_init priority-1 sweep over all registered block types.
This guarantees the attribute is present when WordPress builds the per-block
attributes schema for the block renderer REST endpoint, regardless of when
individual block types were registered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Jul 3, 2026
Block types are registered during init, so the safety-net sweep belongs
there rather than at rest_api_init. Using PHP_INT_MAX priority ensures
it runs after all plugins have had a chance to register their blocks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Jul 3, 2026
Nesting the hook registration inside init (priority 1) ensures it only
starts listening once WordPress's bootstrap is underway, at a consistent
and predictable point rather than at arbitrary plugin-load time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Jul 3, 2026
Single init priority-1 callback: first sweeps blocks already registered,
then attaches registered_block_type to catch any registered after.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Jul 3, 2026
WordPress core does not fire a registered_block_type action, so the
listener was dead code. The init PHP_INT_MAX sweep is sufficient —
it runs after all plugins have registered their blocks during init.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Jul 3, 2026
…hook

block_type_metadata_settings fires inside register_block_type_from_metadata(),
which all register_block_type('name', [...]) calls go through. This adds
hmUrlTabVisibility to the settings before the WP_Block_Type object is created,
so it is present in the REST API schema from the start.

Keeps the init PHP_INT_MAX sweep as a safety net for blocks registered
directly as WP_Block_Type objects, which bypass the filter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Jul 3, 2026
The helper function was only called from the init sweep, so there was no
DRY benefit to keeping it separate. Inline it and drop the function.
Also skip blocks already carrying hmUrlTabVisibility in the sweep.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
github-actions Bot added a commit that referenced this pull request Jul 3, 2026
Updated comments to clarify the purpose of filters and actions related to hmUrlTabVisibility for block types.
github-actions Bot added a commit that referenced this pull request Jul 3, 2026
github-actions Bot added a commit that referenced this pull request Jul 3, 2026
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.

2 participants