Skip to content

State Styles: Scope per-instance rules to the block's root element - #14039

Open
aaronrobertshaw wants to merge 1 commit into
WordPress:trunkfrom
aaronrobertshaw:backport/states-selector-scoping
Open

aaronrobertshaw wants to merge 1 commit into
WordPress:trunkfrom
aaronrobertshaw:backport/states-selector-scoping

Conversation

@aaronrobertshaw

Copy link
Copy Markdown

Backport of Gutenberg PR WordPress/gutenberg#83986

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

Per-instance state styles never applied to a block whose root selector starts with another block's class. List Item registers .wp-block-list > li, so scoping swapped .wp-block-list for the instance class and emitted .wp-states-xxxx > li, which matches nothing. The instance class is on the li itself.

This PR backports:

  • a new wp_get_state_selector_ancestor() that returns the leading compound and its combinator when that compound names a different block,
  • a $block_name parameter on wp_build_state_selector() so the ancestor is kept and the instance class lands on the block's own compound,
  • and the accompanying states block support tests, including one that reads core/list-item's registered selectors rather than a literal.

Testing instructions

Only the front end can be exercised here, since the editor half is not in Core yet. :hover is not a valid state for List Item (WP_Theme_JSON::VALID_BLOCK_PSEUDO_SELECTORS lists Button and Navigation Link only), so use a breakpoint state.

  1. Activate a block theme.
  2. Add a post, switch to the code editor, and paste:
<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item {"style":{"@mobile":{"color":{"text":"#ff00d0"}}}} -->
<li>Narrow me</li>
<!-- /wp:list-item -->
<!-- wp:list-item -->
<li>Second item</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->
  1. Publish and view the post. Narrow the window below 480px. The first item turns pink, the second does not.
  2. View source and find the generated rule:
@media (width <= 480px){.wp-block-list > .wp-states-9f0f8a0d{color:#ff00d0 !important;}}

Without the patch the same markup emits .wp-states-9f0f8a0d > li, which matches nothing, so the item stays its normal colour at any width.

  1. Check a block whose root selector is its own class is unaffected. Give a Button a :hover colour the same way and confirm it still works.

Use of AI

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: the mechanical port and the test port; I reviewed and verified both.

@aaronrobertshaw aaronrobertshaw self-assigned this Oct 6, 2026
@github-actions

github-actions Bot commented Oct 6, 2026

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.

@Mamaduka

Copy link
Copy Markdown
Member

Hey, @aaronrobertshaw

What is the status of this backport PR? Are there any other blockers, or does this just need a review/approval?

@github-actions

Copy link
Copy Markdown

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 aaronrobertshaw, mamaduka.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

…ment.

When a block's root selector starts with another block's class, such as List
Item's `.wp-block-list > li`, scoping swapped that leading compound for the
instance class and produced `.wp-states-xxxx > li`, which matches nothing. The
instance class is on the block's own wrapper, so keep a leading compound that
names a different block as an ancestor and put the instance class on the
block's own compound.

A leading compound followed by a `wp-block-*` class still describes a nested
element, so those selectors keep the existing swap.
@aaronrobertshaw
aaronrobertshaw force-pushed the backport/states-selector-scoping branch from c45346d to f3d7805 Compare October 19, 2026 06:04
@aaronrobertshaw
aaronrobertshaw requested review from andrewserong, ramonjd, talldan and tellthemachines and a balanced review from Copilot and removed request for Copilot October 19, 2026 06:08
@aaronrobertshaw

Copy link
Copy Markdown
Author

Sorry @Mamaduka I missed this at the end of last week. I've rebased. There are no blockers, we just need a review and approval 🙏

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The localized fix includes targeted regression coverage, with no unresolved review findings.

No open issues 🎉

What changed in this PR

Fixes per-instance state styles for blocks such as List Item whose selectors begin with an ancestor block’s class.

Changes:

  • Preserves ancestor selectors while placing the instance class on the block’s own element.
  • Passes the block name into selector scoping.
  • Adds selector and responsive-style regression tests.
File Description
tests/​phpunit/​tests/​block-supports/​states.php Tests ancestor scoping, registered selectors, and responsive styles.
src/​wp-includes/​block-supports/​states.php Adds ancestor detection and block-aware selector scoping.

Review effort: Balanced

@ramonjd ramonjd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Faithful backport of WordPress/gutenberg#83986.

Tests pass with --group 66252.

The List Item turns pink below 480px on the front end.

On trunk it doesn't.

Button hover still works.

Image

I also ran every core block selector through the new scoping.

Only List Item's output changes.

Nice 👋

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants