Skip to content

Refactor: Add extractPresetSlug as a generalized function to extract slugs.#78328

Open
USERSATOSHI wants to merge 1 commit into
WordPress:trunkfrom
USERSATOSHI:feat/refactor-gradient-slug-fn-in-colors
Open

Refactor: Add extractPresetSlug as a generalized function to extract slugs.#78328
USERSATOSHI wants to merge 1 commit into
WordPress:trunkfrom
USERSATOSHI:feat/refactor-gradient-slug-fn-in-colors

Conversation

@USERSATOSHI
Copy link
Copy Markdown
Contributor

What?

A follow-up PR based on #78048 (comment) that generalizes preset slug extraction into a reusable utility function.

Adds extractPresetSlug( rawValue, type ) to handle slug extraction for any preset type ('color', 'gradient', etc.), supporting both the user format (var:preset|<type>|slug) and the theme CSS-variable format (var(--wp--preset--<type>--slug)).

Why?

Previously, gradient slug extraction was done inline and only handled the var:preset|gradient| format, missing the theme var(--wp--preset--gradient--…) form.

How?

color-values.js

  • Added extractPresetSlug(rawValue, type) — generic function handling both var:preset|<type>|slug and var(--wp--preset--<type>--slug) formats
  • extractColorSlug now delegates to extractPresetSlug(rawValue, 'color') for backward compatibility

color-values.js

  • Added full test suite for extractPresetSlug covering both types, both formats, hyphenated slugs, type mismatches, non-strings, and malformed vars

color.js

  • Replaced inline gradient slug extraction with extractPresetSlug( gradientValue, 'gradient' ), now handling both preset formats

Testing Instructions

Unit test should suffice

Testing Instructions for Keyboard

Use of AI Tools

None

keeping the extractColorSlug since we have exposed this function as a public function and removing it would be a breaking change?
@github-actions github-actions Bot added the [Package] Block editor /packages/block-editor label May 15, 2026
@USERSATOSHI
Copy link
Copy Markdown
Contributor Author

I have added this, but kept extractColorSlug since I don't know whether we should remove it or not. Since we made it a public function, removing it would cause a breaking change.

cc: @ciampo

@USERSATOSHI USERSATOSHI marked this pull request as ready for review May 15, 2026 09:32
@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.

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: USERSATOSHI <tusharbharti@git.wordpress.org>

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

@ciampo ciampo added the [Type] Enhancement A suggestion for improvement. label May 15, 2026
@ciampo ciampo self-requested a review May 15, 2026 09:56
Copy link
Copy Markdown
Contributor

@ciampo ciampo left a comment

Choose a reason for hiding this comment

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

Tested in the editor, works well

Testing Instructions

Prerequisites

  • A theme that ships at least one gradient preset (or a custom gradient added via Styles → Colors → Gradients). These instructions assume a gradient with slug custom-marco-test-gradient; substitute your own slug as needed.

Steps

  1. Insert a Paragraph block and type "Hello".

  2. Open the post Options menu (three dots, top-right) → Code editor.

  3. Replace the paragraph's markup with:

    <!-- wp:paragraph {"style":{"color":{"gradient":"var(--wp--preset--gradient--custom-marco-test-gradient)"}}} -->
    <p style="background:var(--wp--preset--gradient--custom-marco-test-gradient)">Hello</p>
    <!-- /wp:paragraph -->
  4. Switch back to Visual editor. The paragraph should render with the gradient background.

  5. Select the paragraph → right sidebar Styles tab → under Color, click the Gradient swatch.

  6. In the picker, pick a different gradient, then pick Custom Marco Test Gradient again (any action that fires onChange once is enough).

  7. Switch back to Code editor.

Expected result (with this PR)

The markup collapses to:

<!-- wp:paragraph {"gradient":"custom-marco-test-gradient"} -->
<p class="has-custom-marco-test-gradient-gradient-background has-background">Hello</p>
<!-- /wp:paragraph -->
  • style.color.gradient is gone.
  • The gradient attribute holds the slug.
  • The rendered <p> has the has-<slug>-gradient-background class instead of an inline style="background:var(...)".

Regression check (on trunk, without the PR)

After step 6, the markup still contains the original style.color.gradient: "var(--wp--preset--gradient--custom-marco-test-gradient)" and the gradient attribute is never set, because the old code only matched the var:preset|gradient|… form.

Notes

  • Don't test this on Group / Cover. Those have supports.background.gradient and route through hooks/background.js, which doesn't go through the slug extraction this PR touches.
  • The Paragraph block is the cleanest test surface because it only has supports.color.gradients, which is the exact path PR #78328 modifies.
  • Unit tests: npx jest --config test/unit/jest.config.js packages/block-editor/src/utils/test/color-values.js — should report 14/14 passing.

We should also add a CHANGELOG entry, likely a short note under Bug Fixes in packages/block-editor/CHANGELOG.md to document the new behavior for gradients: theme CSS-var gradients now decode to a slug and end up persisted as a gradient attribute rather than as a raw style.color.gradient

new RegExp( `^var\\(${ cssVarPrefix }([^)]+)\\)$` )
);
return themeFormatMatch?.[ 1 ];
return themeFormatMatch?.[ 1 ] ?? undefined;
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.

The ?? undefined here is redundant, because the optional chaining in themeFormatMatch?.[ 1 ] would already return undefined when there is no match

Copy link
Copy Markdown
Contributor Author

@USERSATOSHI USERSATOSHI May 15, 2026

Choose a reason for hiding this comment

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

I added ?? undefined since ?. would give null when there is no regex match

If we are fine with null then I can remove it

Copy link
Copy Markdown
Contributor

@ciampo ciampo May 15, 2026

Choose a reason for hiding this comment

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

I believe that (null)?.[1] returns undefined — see MDN about the ?. operator:

the expression short circuits and evaluates to undefined instead of throwing an error.

Comment on lines +30 to 45
/**
* Extracts the palette slug from a color style value, supporting both the user
* preset format and the theme CSS-variable format:
*
* - User format: `var:preset|color|slug`
* - Theme format: `var(--wp--preset--color--slug)`
*
* Returns `undefined` for plain hex values, non-strings, or any other
* unrecognised format.
*
* @param {*} rawValue Raw style value stored in the style object.
* @return {string|undefined} The palette slug, or undefined.
*/
export function extractColorSlug( rawValue ) {
return extractPresetSlug( rawValue, 'color' );
}
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.

kept extractColorSlug since I don't know whether we should remove it or not. Since we made it a public function, removing it would cause a breaking change.

AFAIK, extractColorSlug is not a public API of the @wordpress/block-editor package, and it's only imported internally to the package; therefore, it should be fine to remove it and refactor internal usage to extractPresetSlug (including existing tests)

const cssVarPrefix = `--wp--preset--${ type }--`;
const themeFormatMatch = rawValue.match(
/^var\(--wp--preset--color--([^)]+)\)$/
new RegExp( `^var\\(${ cssVarPrefix }([^)]+)\\)$` )
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.

Very nitty, but we could cache the RegExp instead of creating a new one every time. eg

const themeRegexCache = new Map();
function themeRegex( type ) {
	if ( ! themeRegexCache.has( type ) ) {
		themeRegexCache.set(
			type,
			new RegExp( `^var\\(--wp--preset--${ type }--([^)]+)\\)$` )
		);
	}
	return themeRegexCache.get( type );
}

*
* @param {*} rawValue Raw style value stored in the style object.
* @param {*} rawValue Raw style value stored in the style object.
* @param {string} type Preset type, e.g. `'color'` or `'gradient'`.
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.

We can tighten the type here to @param {'color'|'gradient'}

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

Labels

[Package] Block editor /packages/block-editor [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants