Commit f369eeb2a78 for woocommerce
commit f369eeb2a7818cd43771fd18ce09c65b8aad7854
Author: Mikael Korpela <mikael@ihminen.org>
Date: Tue Oct 6 23:09:45 2026 +0300
Enable WPDS stylelint rules and build-time token fallbacks (#69250)
diff --git a/package.json b/package.json
index ccaa9a81793..3490566cfe2 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
"@woocommerce/monorepo-utils": "workspace:*",
"@wordpress/prettier-config": "4.49.0",
"@wordpress/stylelint-config": "catalog:tooling",
+ "@wordpress/theme": "catalog:wp-bundled",
"babel-loader": "9.2.x",
"chalk": "^4.1.2",
"copy-webpack-plugin": "13.0.x",
diff --git a/packages/js/internal-build/changelog/add-stylelint-wpds-plugins b/packages/js/internal-build/changelog/add-stylelint-wpds-plugins
new file mode 100644
index 00000000000..217b1529473
--- /dev/null
+++ b/packages/js/internal-build/changelog/add-stylelint-wpds-plugins
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add WPDS design token fallbacks to built CSS with the `@wordpress/theme` PostCSS plugin.
diff --git a/packages/js/internal-build/package.json b/packages/js/internal-build/package.json
index 1bd456cadb4..0ccff5203c6 100644
--- a/packages/js/internal-build/package.json
+++ b/packages/js/internal-build/package.json
@@ -59,6 +59,7 @@
"@automattic/color-studio": "^4.0.0",
"@wordpress/base-styles": "catalog:wp-bundled",
"@wordpress/postcss-plugins-preset": "catalog:wp-min",
+ "@wordpress/theme": "catalog:wp-bundled",
"chokidar": "^3.6.0",
"css-loader": "6.11.x",
"esbuild": "^0.24.0",
diff --git a/packages/js/internal-build/src/style-build/index.cjs b/packages/js/internal-build/src/style-build/index.cjs
index e44643a20e8..dc0f28ef6f7 100644
--- a/packages/js/internal-build/src/style-build/index.cjs
+++ b/packages/js/internal-build/src/style-build/index.cjs
@@ -5,6 +5,10 @@ const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' );
const path = require( 'path' );
const RemoveEmptyScriptsPlugin = require( 'webpack-remove-empty-scripts' );
const postcssPlugins = require( '@wordpress/postcss-plugins-preset' );
+// ESM-only; Node's require( esm ) returns the module namespace.
+const {
+ default: dsTokenFallbacks,
+} = require( '@wordpress/theme/postcss-plugins/postcss-ds-token-fallbacks' );
const StyleAssetPlugin = require( './style-asset-plugin.cjs' );
const WebpackRTLPlugin = require( './webpack-rtl-plugin.cjs' );
@@ -31,7 +35,10 @@ module.exports = {
loader: 'postcss-loader',
options: {
postcssOptions: {
- plugins: postcssPlugins,
+ plugins: [
+ ...postcssPlugins,
+ dsTokenFallbacks,
+ ],
},
},
},
diff --git a/plugins/woocommerce/changelog/add-stylelint-wpds-plugins b/plugins/woocommerce/changelog/add-stylelint-wpds-plugins
new file mode 100644
index 00000000000..7265be54962
--- /dev/null
+++ b/plugins/woocommerce/changelog/add-stylelint-wpds-plugins
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Lint WPDS design token usage and add token fallbacks at build time; no merchant-facing change.
diff --git a/plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/update-banner.scss b/plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/update-banner.scss
index ea82bd90f90..cd35fdeaa39 100644
--- a/plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/update-banner.scss
+++ b/plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/update-banner.scss
@@ -2,8 +2,8 @@
* <UpdateBanner> — RSM-141.
*
* Floating card pinned 16px from the canvas top, centered horizontally.
- * Uses WPDS tokens via CSS custom properties with sensible WP-admin
- * fallbacks; no custom design tokens introduced.
+ * Uses WPDS tokens via CSS custom properties; fallbacks are added at
+ * build time. No custom design tokens introduced.
*/
.wc-update-banner {
@@ -12,12 +12,12 @@
left: 50%;
transform: translateX(-50%);
width: min(720px, calc(100% - 32px));
- background: var(--wpds-color-bg-surface, #fff);
- border-radius: var(--wpds-border-radius-sm, 2px);
+ background: var(--wpds-color-background-surface-neutral-strong);
+ border-radius: var(--wpds-border-radius-sm);
box-shadow:
- var(--wpds-elevation-md, 0 1px 2px rgba(0, 0, 0, 0.06)),
+ var(--wpds-elevation-md),
0 4px 12px rgba(0, 0, 0, 0.08);
- border-left: 3px solid var(--wpds-color-bg-interactive-brand-strong, #3858e9);
+ border-left: 3px solid var(--wpds-color-stroke-surface-brand-strong);
padding: 12px 16px;
display: flex;
gap: 16px;
@@ -39,7 +39,7 @@
&__subtitle {
margin-top: 4px;
font-size: 12px;
- color: var(--wpds-color-text-secondary, #757575);
+ color: var(--wpds-color-foreground-content-neutral-weak);
}
&__expand {
@@ -48,7 +48,7 @@
border: 0;
padding: 4px 0 0 0;
margin-top: 6px;
- color: var(--wpds-color-bg-interactive-brand-strong, #3858e9);
+ color: var(--wpds-color-foreground-interactive-brand);
cursor: pointer;
font-size: 12px;
font-weight: 500;
@@ -76,7 +76,7 @@
font-size: 16px;
line-height: 1;
cursor: pointer;
- color: var(--wpds-color-text-secondary, #757575);
+ color: var(--wpds-color-foreground-content-neutral-weak);
&:disabled {
opacity: 0.5;
@@ -86,13 +86,13 @@
/* Success morph */
&--success {
- background: var(--wpds-color-bg-surface-success-weak, #ebffed);
- border-left-color: var(--wpds-color-bg-interactive-success-strong, #00ba37);
+ background: var(--wpds-color-background-surface-success-weak);
+ border-left-color: var(--wpds-color-stroke-surface-success-strong);
}
/* Failure morph */
&--failure {
- background: var(--wpds-color-bg-surface-warning, #fde6be);
+ background: var(--wpds-color-background-surface-warning);
border-left-color: #b26200;
}
}
diff --git a/plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-embed/settings-ui.scss b/plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-embed/settings-ui.scss
index 566cefc56cc..c261e4fc7d1 100644
--- a/plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-embed/settings-ui.scss
+++ b/plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-embed/settings-ui.scss
@@ -50,7 +50,7 @@ body.woocommerce_page_wc-settings.woocommerce-settings-ui-page {
var(--wpds-color-stroke-surface-neutral-weak);
display: flex;
flex-direction: column;
- gap: var(--wpds-dimension-gap-sm, 8px);
+ gap: var(--wpds-dimension-gap-sm);
padding: var(--wpds-dimension-padding-2xl) 48px;
}
@@ -73,7 +73,7 @@ body.woocommerce_page_wc-settings.woocommerce-settings-ui-page {
.wc-settings-ui-shell__header-actions {
display: flex;
flex: 0 0 auto;
- gap: var(--wpds-dimension-gap-sm, 8px);
+ gap: var(--wpds-dimension-gap-sm);
margin-inline-start: auto;
}
@@ -84,13 +84,13 @@ body.woocommerce_page_wc-settings.woocommerce-settings-ui-page {
.wc-settings-ui-shell__badge {
align-items: center;
- border-radius: var(--wpds-border-radius-lg, 8px);
+ border-radius: var(--wpds-border-radius-lg);
display: inline-flex;
- font-size: var(--wpds-typography-font-size-sm, 12px);
- font-weight: var(--wpds-typography-font-weight-regular, 400);
- line-height: var(--wpds-typography-line-height-xs, 16px);
+ font-size: var(--wpds-typography-font-size-sm);
+ font-weight: var(--wpds-typography-font-weight-regular);
+ line-height: var(--wpds-typography-line-height-xs);
min-height: 24px;
- padding: 0 var(--wpds-dimension-padding-sm, 8px);
+ padding: 0 var(--wpds-dimension-padding-sm);
&,
&--default {
@@ -208,7 +208,7 @@ body.woocommerce_page_wc-settings.woocommerce-settings-ui-page {
box-sizing: border-box;
display: flex;
flex-direction: column;
- gap: var(--wpds-dimension-gap-xl, 24px);
+ gap: var(--wpds-dimension-gap-xl);
margin: var(--wpds-dimension-gap-2xl) auto 48px;
max-width: var(--wpds-dimension-surface-width-xl);
}
diff --git a/plugins/woocommerce/client/admin/stylelint.config.js b/plugins/woocommerce/client/admin/stylelint.config.js
index b511266cde6..ec78cd4fae9 100644
--- a/plugins/woocommerce/client/admin/stylelint.config.js
+++ b/plugins/woocommerce/client/admin/stylelint.config.js
@@ -3,8 +3,5 @@ module.exports = {
ignoreFiles: [ './vendor/**/*.scss' ],
rules: {
'scss/load-partial-extension': 'always',
- // Enabled by the preset since @wordpress/stylelint-config 23.x.
- // TODO: re-enable once update-banner.scss uses valid WPDS tokens.
- 'plugin-wpds/no-unknown-ds-tokens': null,
},
};
diff --git a/plugins/woocommerce/client/blocks/.stylelintrc.json b/plugins/woocommerce/client/blocks/.stylelintrc.json
index 4bd2e23b83d..275eb527ebf 100644
--- a/plugins/woocommerce/client/blocks/.stylelintrc.json
+++ b/plugins/woocommerce/client/blocks/.stylelintrc.json
@@ -1,7 +1,11 @@
{
"extends": "@wordpress/stylelint-config/scss-stylistic",
+ "plugins": [
+ "@wordpress/theme/stylelint-plugins/no-token-fallback-values"
+ ],
"reportNeedlessDisables": true,
"rules": {
+ "plugin-wpds/no-token-fallback-values": true,
"no-descending-specificity": null,
"no-duplicate-selectors": null,
"selector-class-pattern": null,
diff --git a/plugins/woocommerce/client/blocks/package.json b/plugins/woocommerce/client/blocks/package.json
index 21784600bf3..830e008f167 100644
--- a/plugins/woocommerce/client/blocks/package.json
+++ b/plugins/woocommerce/client/blocks/package.json
@@ -155,6 +155,7 @@
"@wordpress/rich-text": "catalog:wp-min",
"@wordpress/scripts": "32.6.0",
"@wordpress/stylelint-config": "catalog:tooling",
+ "@wordpress/theme": "catalog:wp-bundled",
"ajv-cli": "3.3.x",
"allure-playwright": "^2.9.2",
"autoprefixer": "10.4.14",
diff --git a/plugins/woocommerce/client/blocks/postcss.config.js b/plugins/woocommerce/client/blocks/postcss.config.js
index 3c3296d5805..1c5dc0dd5bb 100644
--- a/plugins/woocommerce/client/blocks/postcss.config.js
+++ b/plugins/woocommerce/client/blocks/postcss.config.js
@@ -1,5 +1,6 @@
module.exports = ( { env } ) => ( {
plugins: {
+ '@wordpress/theme/postcss-plugins/postcss-ds-token-fallbacks': {},
autoprefixer: { grid: true },
cssnano: env === 'production',
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6d4b3a20712..470118a333c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -269,6 +269,9 @@ importers:
'@wordpress/stylelint-config':
specifier: catalog:tooling
version: 23.42.0(@types/react@18.3.28)(esbuild@0.24.2)(postcss@8.5.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(stylelint-scss@6.14.0(stylelint@16.26.1(typescript@5.7.3)))(stylelint@16.26.1(typescript@5.7.3))
+ '@wordpress/theme':
+ specifier: catalog:wp-bundled
+ version: 0.17.0(@types/react@18.3.28)(esbuild@0.24.2)(postcss@8.5.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(stylelint@16.26.1(typescript@5.7.3))
babel-loader:
specifier: 9.2.x
version: 9.2.1(@babel/core@7.25.7)(webpack@5.97.1(@swc/core@1.15.24))
@@ -1748,6 +1751,9 @@ importers:
'@wordpress/postcss-plugins-preset':
specifier: catalog:wp-min
version: 5.33.1(postcss@8.5.26)
+ '@wordpress/theme':
+ specifier: catalog:wp-bundled
+ version: 0.17.0(@types/react@18.3.28)(esbuild@0.24.2)(postcss@8.5.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(stylelint@16.26.1(typescript@5.7.3))
chokidar:
specifier: ^3.6.0
version: 3.6.0
@@ -3608,6 +3614,9 @@ importers:
'@wordpress/stylelint-config':
specifier: catalog:tooling
version: 23.36.0(postcss@8.5.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(stylelint-scss@6.14.0(stylelint@16.26.1(typescript@5.7.3)))(stylelint@16.26.1(typescript@5.7.3))
+ '@wordpress/theme':
+ specifier: catalog:wp-bundled
+ version: 0.17.0(@types/react@18.3.28)(esbuild@0.24.2)(postcss@8.5.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(stylelint@16.26.1(typescript@5.7.3))
ajv-cli:
specifier: 3.3.x
version: 3.3.0
diff --git a/stylelint.config.cjs b/stylelint.config.cjs
index 4fbcafcf779..1ec096d5b9a 100644
--- a/stylelint.config.cjs
+++ b/stylelint.config.cjs
@@ -4,6 +4,7 @@
*/
module.exports = {
extends: '@wordpress/stylelint-config/scss-stylistic',
+ plugins: [ '@wordpress/theme/stylelint-plugins/no-token-fallback-values' ],
reportNeedlessDisables: true,
ignoreFiles: [
'docs/**',
@@ -32,6 +33,7 @@ module.exports = {
'scss/selector-no-redundant-nesting-selector': null,
'selector-id-pattern': null,
'length-zero-no-unit': [ true, { ignoreFunctions: [ 'calc', 'var' ] } ],
+ 'plugin-wpds/no-token-fallback-values': true,
},
overrides: [
{