Skip to content

Background: Add a PHP helper for block support classes and styles - #84209

Merged
aaronrobertshaw merged 15 commits into
trunkfrom
update/background-classes-and-styles-php-helper
Nov 4, 2026
Merged

aaronrobertshaw merged 15 commits into
trunkfrom
update/background-classes-and-styles-php-helper

Conversation

@aaronrobertshaw

@aaronrobertshaw aaronrobertshaw commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Follows up on #83122.
Core backport: wordpress-develop#14094.

Related:

What?

Adds a PHP helper that turns background attributes into classes and inline styles, like the JS getBackgroundClassesAndStyles().

wp_get_background_classes_and_styles( $block_attributes );
// array( 'class' => 'has-background', 'style' => 'background-image:var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple);' )

Why?

Five blocks copied the background block support's image defaults and has-background rule, and the copies had started to drift. Button had the first copy. Four blocks that merged since added their own:

Tab List already uses the JS helper.

How?

The helper only builds output. Callers pass what they support.

  • Image defaults: cover, and a centred position for contain
  • has-background: for an image or gradient not clipped to text
  • Block support: keeps its checks
  • Button, Post Navigation Link, Icon: ignore the clip
  • Post Navigation Link: CSS order unchanged
  • Search: passes only the gradient
  • Build: added to prefixFunctions

No style changes for values the editor saves. has-background can sit in a different place in the class list.

PHPStan's WordPress stubs are built from Core trunk, which won't have this helper until wordpress-develop#14094 lands. So this PR adds a temporary baseline entry for it. PHPStan will flag the entry for removal once the stubs move to a Core trunk with the helper.

Testing Instructions

  1. Add a Button with a contain background image and a gradient.
  2. Add a Group with a positioned background image and a gradient.
  3. On a single post template, add a Post Navigation Link with a background image and a border colour.
  4. Add an Icon with a preset gradient.
  5. Add a Search block with a gradient, with the button inside and outside.
  6. Compare the front end markup with trunk. Styles should match.
  7. Add a Heading with a gradient clipped to text. It has the clip styles and no has-background.

Use of AI Tools

Implemented and tested by a Claude Code agent.

@aaronrobertshaw aaronrobertshaw added [Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi [Type] Enhancement A suggestion for improvement. labels Oct 8, 2026
@aaronrobertshaw aaronrobertshaw self-assigned this Oct 8, 2026
@aaronrobertshaw aaronrobertshaw added [Package] Block library /packages/block-library Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json labels Oct 8, 2026
@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

🤖 PR meta 🤖

🎉 Props

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: aaronrobertshaw <aaronrobertshaw@git.wordpress.org>
Co-authored-by: westonruter <westonruter@git.wordpress.org>
Co-authored-by: andrewserong <andrewserong@git.wordpress.org>

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


Props Bot commands

You can trigger Props Bot actions by commenting on this PR:

  • @propsbot add <username> to give props to a GitHub user. Requires write access.
  • @propsbot remove <username> to leave a user out of the props. Requires write access.
  • @propsbot refresh to refresh this list. Adding the props-bot label works too.

Updated as activity occurs, without notifying anyone named here. Add the props-bot label to refresh.

📦 Bundle size

Size Change: 0 B

Total Size: 8.61 MB

394d2b4 Run

⚡ Performance

Show the results

Client side metrics exclude the server response time.

front-end-block-theme

Metric 3cae16e trunk % Change
timeToFirstByte 48.3 ms +3.42% -2.59% 49.3 ms +9.63% -4.16% -2.03%
largestContentfulPaint 82 ms +12.2% -2.44% 84 ms +9.52% -4.76% -2.38%
lcpMinusTtfb 34.05 ms +20.12% -7.05% 33.85 ms +15.81% -9.45% 0.59%
wpBeforeTemplate 24.38 ms +3.69% -2.26% 24.46 ms +8.34% -2.41% -0.33%
wpTemplate 19.99 ms +4.4% -2.8% 20.31 ms +4.38% -4.83% -1.58%
wpTotal 44.44 ms +3.6% -2.34% 45.25 ms +9.22% -3.71% -1.79%
wpMemoryUsage 7.72 MB +0% -0% 7.68 MB +0% -0% 0.44%
wpDbQueries 16 +0% -0% 16 +0% -0% 0%

front-end-classic-theme

Metric 3cae16e trunk % Change
timeToFirstByte 34.95 ms +6.15% -2% 40.2 ms +0.62% -1.87% -13.06%
largestContentfulPaint 80 ms +2.5% -0% 88 ms +4.55% -0% -9.09%
lcpMinusTtfb 45.15 ms +1.11% -3.88% 48.55 ms +4.94% -1.75% -7%
wpBeforeTemplate 21.04 ms +4.18% -3.28% 21.1 ms +1.71% -2.32% -0.28%
wpTemplate 11.29 ms +6.02% -3.28% 15.69 ms +3.82% -6.18% -28.04%
wpTotal 32.08 ms +6.23% -1.96% 37.07 ms +0.35% -1.62% -13.46%
wpMemoryUsage 6.30 MB +0% -0% 6.37 MB +0% -0% -1.2%
wpDbQueries 9 +0% -0% 13 +0% -0% -30.77%

media-processing

Metric 3cae16e trunk % Change
mediaProcessingJpeg 387.04 ms +2.17% -2.54% 391.15 ms +1.35% -1.44% -1.05%
mediaProcessingAvif 5545.93 ms +2.46% -0.16% 5758.62 ms +0.58% -0.38% -3.69%
mediaProcessingJpegToAvif 3832.17 ms +0.57% -1.95% 3928.02 ms +0.68% -0.21% -2.44%

media-upload

Metric 3cae16e trunk % Change
jpegUploadProcessing 1445.8 ms +1.29% -0.59% 1463.58 ms +1.55% -0.43% -1.21%
pngUploadProcessing 234.4 ms +2.85% -1.2% 237.12 ms +5.61% -2.91% -1.15%
largeJpegUploadProcessing 1452.96 ms +0.38% -0.7% 1453.9 ms +1.34% -0.47% -0.06%
multipleImageUploadProcessing 1576.59 ms +1.37% -0.76% 2013.66 ms +1.05% -19.11% -21.71%

post-editor

Metric 3cae16e trunk % Change
serverResponse 433.51 ms +10.18% -1.98% 450.97 ms +4.17% -5.33% -3.87%
firstPaint 362.28 ms +15.68% -16.3% 376.78 ms +16.97% -12.12% -3.85%
domContentLoaded 841.56 ms +1.8% -1.14% 835.25 ms +2.72% -0.91% 0.76%
loaded 842.47 ms +1.82% -1.12% 836.19 ms +2.74% -0.88% 0.75%
firstContentfulPaint 498 ms +1.17% -1.74% 489.11 ms +3.29% -1.7% 1.82%
firstBlock 2150.66 ms +1.56% -0.68% 2126.64 ms +0.28% -0.36% 1.13%
type 16.15 ms +10.53% -7.31% 15.62 ms +11.27% -3.2% 3.39%
typeWithoutInspector 17.18 ms +8.32% -9.6% 15.51 ms +15.73% -6.38% 10.77%
typeWithTopToolbar 22.95 ms +3.27% -6.23% 24.1 ms +11% -6.97% -4.77%
typeContainer 8.15 ms +11.66% -9.45% 8.19 ms +12.21% -9.52% -0.49%
focus 111.88 ms +6.88% -0.97% 111.57 ms +18.79% -4.91% 0.28%
firstFocus 238.49 ms +0% -0% 240.83 ms +0% -0% -0.97%
selectAll 402.98 ms +1.43% -3.39% 417.18 ms +0.28% -2.59% -3.4%
undo 31.34 ms +2.14% -9.09% 29.78 ms +5.51% -6.51% 5.24%
listViewOpen 81.32 ms +6.91% -11.58% 74.72 ms +14.03% -7.87% 8.83%
inserterOpen 40.47 ms +4.25% -1.75% 40.61 ms +7.17% -2.66% -0.34%
inserterHover 11.27 ms +4.61% -1.86% 10.82 ms +8.41% -12.01% 4.16%
inserterSearch 8.44 ms +4.62% -5.45% 8.75 ms +8.57% -6.74% -3.54%
loadPatterns 637.89 ms +1.99% -5.96% 618.75 ms +4.88% -8% 3.09%
wpTotal 423.94 ms +10.4% -2.01% 440.23 ms +4.53% -5.18% -3.7%
wpMemoryUsage 14.76 MB +0% -0% 14.73 MB +0% -0% 0.24%
wpDbQueries 55 +0% -0% 55 +0% -0% 0%

site-editor

Metric 3cae16e trunk % Change
serverResponse 405.02 ms +0.53% -1.23% 412.7 ms +1.68% -8.22% -1.86%
firstPaint 358.85 ms +11.1% -1.38% 378.34 ms +13.41% -3.49% -5.15%
domContentLoaded 879.7 ms +2.21% -0.94% 907.58 ms +4% -2.19% -3.07%
loaded 880.71 ms +2.19% -0.92% 908.55 ms +4.03% -2.19% -3.06%
firstContentfulPaint 507.51 ms +5.38% -2.3% 528.61 ms +2.41% -1.11% -3.99%
firstBlock 2521.3 ms +4.34% -1.59% 2602.92 ms +1.36% -1.87% -3.14%
type 17.98 ms +7.06% -3.62% 19.76 ms +3.95% -5.57% -9.01%
navigate 116.81 ms +5.7% -6.18% 119.88 ms +10.75% -8.49% -2.56%
loadPatterns 1329.46 ms +3.33% -4.38% 1363.72 ms +2.43% -7.51% -2.51%
loadPages 996.91 ms +1.96% -1.96% 987.51 ms +3.08% -1.93% 0.95%
wpTotal 394.39 ms +0.55% -1.25% 401.88 ms +1.73% -8.46% -1.86%
wpMemoryUsage 12.78 MB +0% -0% 12.74 MB +0% -0% 0.27%
wpDbQueries 45 +0% -0% 45 +0% -0% 0%

394d2b4 Run

🏁 Flaky tests

Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

Actions are reachable via RIGHT/LEFT arrow keys in /test/e2e/specs/site-editor/dataviews-list-layout-keyboard.spec.js, passed after 1 failed attempt.
Error: expect(locator).toBeFocused() failed

Locator:  getByRole('row', { name: 'Page One Edit Actions' }).getByRole('button', { name: 'Edit' })
Expected: focused
Received: inactive
Timeout:  5000ms

Call log:
  - Expect "toBeFocused" getByRole('row', { name: 'Page One Edit Actions' }).getByRole('button', { name: 'Edit' }) with timeout 5000ms
  - waiting for getByRole('row', { name: 'Page One Edit Actions' }).getByRole('button', { name: 'Edit' })
    14 × locator resolved to <button type="button" tabindex="-1" class="components-button is-small" id="view-list-0-177-primary-action-edit-post">Edit</button>
       - unexpected value "inactive"

    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/site-editor/dataviews-list-layout-keyboard.spec.js:172:5
should re-trigger autocomplete when backspacing into a completed mention in /test/e2e/specs/editor/various/autocomplete-and-mentions.spec.js, passed after 2 failed attempts.
Error: apiRequestContext.fetch: socket hang up
Call log:
  - → DELETE http://localhost:8891/wp-json/wp/v2/users/29?force=true&reassign=1
    - user-agent: Playwright/1.63.0 (x64; ubuntu 24.04) node/24.20 CI/1
    - accept: */*
    - accept-encoding: gzip,deflate,br
    - X-WP-Nonce: 78a42c4b5a
    - cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_da433b7faafd8180ebeb1624ceeeab7e=admin%7C1793976874%7C1lg1EcEQMGR0iCg4fxl55HZSNtbEKJK8q71plmDVoAe%7C848d60f7542af4049d2b09f659ddec52daa79f00918b2bfc5439f0ed14a7ca49; wp-settings-time-1=1793804698

    at RequestUtils.rest (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/rest.ts:111:39)
    at RequestUtils.deleteUser (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/users.ts:91:30)
    at map (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/users.ts:116:51)
    at RequestUtils.deleteAllUsers (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/users.ts:116:5)
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/autocomplete-and-mentions.spec.js:73:3

should show the homepage actions again on the previous homepage in /test/e2e/specs/site-editor/homepage-settings.spec.js, passed after 2 failed attempts.
Error: apiRequestContext.fetch: socket hang up
Call log:
  - → DELETE http://localhost:8891/wp-json/wp/v2/pages/287?force=true
    - user-agent: Playwright/1.63.0 (x64; ubuntu 24.04) node/24.20 CI/1
    - accept: */*
    - accept-encoding: gzip,deflate,br
    - X-WP-Nonce: 78a42c4b5a
    - cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_da433b7faafd8180ebeb1624ceeeab7e=admin%7C1793976874%7C1lg1EcEQMGR0iCg4fxl55HZSNtbEKJK8q71plmDVoAe%7C848d60f7542af4049d2b09f659ddec52daa79f00918b2bfc5439f0ed14a7ca49; wp-settings-time-1=1793804518

    at RequestUtils.rest (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/rest.ts:111:39)
    at RequestUtils.call (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/pages.ts:27:20)
    at map (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/pages.ts:56:37)
    at RequestUtils.deleteAllPages (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/pages.ts:56:9)
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/site-editor/homepage-settings.spec.js:43:3
Error: locator.click: Error: strict mode violation: getByRole('row').filter({ has: getByRole('gridcell').getByLabel('About') }) resolved to 2 elements:
    1) <div class="" role="row" id="_r_d_">…</div> aka locator('[id="_r_d_"]')
    2) <div class="" role="row" id="_r_p_">…</div> aka locator('[id="_r_p_"]')

Call log:
  - waiting for getByRole('row').filter({ has: getByRole('gridcell').getByLabel('About') })

    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/site-editor/homepage-settings.spec.js:151:22

394d2b4 Run

@aaronrobertshaw
aaronrobertshaw force-pushed the update/background-classes-and-styles-php-helper branch 2 times, most recently from 3e80bc4 to e2d29dc Compare October 8, 2026 05:56
@aaronrobertshaw aaronrobertshaw added [Type] Code Quality Issues or PRs that relate to code quality and removed [Type] Enhancement A suggestion for improvement. Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json labels Oct 8, 2026
@github-actions github-actions Bot added the [Package] Block editor /packages/block-editor label Oct 8, 2026
@aaronrobertshaw
aaronrobertshaw force-pushed the update/background-classes-and-styles-php-helper branch from 98b4dba to 3848408 Compare October 8, 2026 12:11
@aaronrobertshaw
aaronrobertshaw force-pushed the update/background-classes-and-styles-php-helper branch 4 times, most recently from d2d345d to 493a0bc Compare October 20, 2026 05:13
@aaronrobertshaw
aaronrobertshaw force-pushed the update/background-classes-and-styles-php-helper branch from 493a0bc to 52404fb Compare October 21, 2026 05:21
@aaronrobertshaw
aaronrobertshaw force-pushed the update/background-classes-and-styles-php-helper branch from 9610ccd to 5e11cb4 Compare October 21, 2026 12:41
@aaronrobertshaw
aaronrobertshaw marked this pull request as ready for review October 21, 2026 13:16
@aaronrobertshaw
aaronrobertshaw force-pushed the update/background-classes-and-styles-php-helper branch from 5e11cb4 to 701ca1a Compare October 27, 2026 07:53

@andrewserong andrewserong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All smoke-testing nicely for me in the editor and site frontend!

Image

Tiny nits:

  • Same as in #84208 (review) should we move to the 7.3 directory?
  • In #84208 there were also tests for the icon and post navigation link blocks. Worth doing here, too?

LGTM! 🚀

@aaronrobertshaw
aaronrobertshaw force-pushed the update/background-classes-and-styles-php-helper branch 2 times, most recently from f5ad449 to 52c8b3c Compare November 2, 2026 03:08
@aaronrobertshaw

Copy link
Copy Markdown
Contributor Author

Thanks for testing @andrewserong 👍

should we move to the 7.3 directory?

Yep, done. Same across all five PRs and the Core backport.

tests for the icon and post navigation link blocks

Good call, I've added tests for both. I've also tidied up the helper's naming and test docblocks to match the other helpers, and rebased on trunk.

PHPStan landed this week and doesn't know the new helper yet so I've added a temp baseline for that as well.

@aaronrobertshaw
aaronrobertshaw force-pushed the update/background-classes-and-styles-php-helper branch from adc97c0 to 72f0cbd Compare November 4, 2026 04:02
Comment thread tools/phpstan/baseline.neon Resolved
@aaronrobertshaw
aaronrobertshaw force-pushed the update/background-classes-and-styles-php-helper branch from 0b17dc4 to f51bedf Compare November 4, 2026 13:25
aaronrobertshaw and others added 15 commits November 4, 2026 22:44
Return early when the block attributes are not an array, like the colour
helper. Point the text clip comments at the helper and give the unset()
guard its reason. Drop tests that repeat block support coverage or lock in
PHP-only behaviour, and keep one Button test proving it ignores the clip.
The block library calls wp_get_background_classes_and_styles(), which
the build prefixes to gutenberg_get_background_classes_and_styles() for
the plugin, but which PHPStan resolves from the WordPress stubs. The
stubs were generated from core trunk, which lacks the function, so its
calls were baselined as not found.

Generate the stubs from wordpress-develop PR 14094, which backports the
helper, and drop the four baselined errors. Regenerate them from trunk
once the backport is committed.

Co-Authored-By: Claude Opus 5.5 (medium effort) <noreply@anthropic.com>
Claude-Code-Session-Id: cfcf15e8-ccc1-4d78-a7c9-51f73e8e4b92
@aaronrobertshaw
aaronrobertshaw force-pushed the update/background-classes-and-styles-php-helper branch from f51bedf to 394d2b4 Compare November 4, 2026 14:47
@aaronrobertshaw
aaronrobertshaw enabled auto-merge (squash) November 4, 2026 14:50
@aaronrobertshaw
aaronrobertshaw merged commit 9bf8c66 into trunk Nov 4, 2026
98 of 100 checks passed
@aaronrobertshaw
aaronrobertshaw deleted the update/background-classes-and-styles-php-helper branch November 4, 2026 15:09
@github-actions github-actions Bot added this to the Gutenberg 24.5 milestone Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi [Package] Block editor /packages/block-editor [Package] Block library /packages/block-library [Type] Code Quality Issues or PRs that relate to code quality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants