Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
8f469eb
First pass at adding a stylelint script.
afercia Aug 6, 2026
94dce6d
Remove custom rule from gutenberg.
afercia Aug 6, 2026
306b879
Clean up stylelintignore.
afercia Aug 6, 2026
9f3fae0
Clean up config.
afercia Aug 6, 2026
10d288f
Add Grunt task and clean up.
afercia Aug 7, 2026
656a57a
Remove stylelint-config-wordpress package.
afercia Aug 7, 2026
78aca49
Ignore admin color scheme auto generated files.
afercia Aug 8, 2026
7507a14
Ignore files copied to wp-includes js.
afercia Aug 8, 2026
5c3036a
Remove Stylelint configuration from Twenty Twenty theme.
afercia Aug 9, 2026
55d3032
Remove Stylelint configuration from Twenty Twenty-One theme.
afercia Aug 9, 2026
3895c8d
Remove comments.
afercia Aug 9, 2026
fdee94e
Add lint:css:themes script for bundled themes.
afercia Aug 9, 2026
d75b7e7
Build theme files.
afercia Aug 9, 2026
63e533e
Use the root stylelintrc for twentytwentyone.
afercia Aug 9, 2026
2386120
For twentytwentyone try adding a postcss script and run it twice.
afercia Aug 10, 2026
8db42d0
Start refining rules.
afercia Aug 10, 2026
139bc81
Add rules for empty lines before.
afercia Aug 10, 2026
9e7acb1
Solve the indentation and leading space issues avoiding to run postcs…
afercia Aug 10, 2026
fa115d8
Improve comment-empty-line-before.
afercia Aug 10, 2026
9632b7c
Improve comment.
afercia Aug 10, 2026
390f15d
Improve selector-list-comma-space-after.
afercia Aug 10, 2026
3bc303b
Refine empty libe before rule.
afercia Aug 11, 2026
b91eca3
Add selector-no-qualifying-type warning.
afercia Aug 11, 2026
a080723
Refine more rules.
afercia Aug 11, 2026
95a0ce4
Improve order of rules related to indentation.
afercia Aug 11, 2026
48f93d0
Reduce max-empty-lines to 1.
afercia Aug 11, 2026
98377f2
Disable comment-empty-line-before.
afercia Aug 11, 2026
968a159
Run stylelint directly so that it walks upwards until it finds the ro…
afercia Aug 11, 2026
207efbd
Update test-and-zip-default-themes gh action.
afercia Aug 11, 2026
45aac96
Add bacl @wordpress/scripts to twentytwentyone.
afercia Aug 11, 2026
b450b44
Add stylelint-plugin-logical-css to twentytwentyone.
afercia Aug 11, 2026
3ced1b1
Update twentytwentyone styles.
afercia Aug 11, 2026
011b671
Pass the glob as a quoted pattern.
afercia Aug 11, 2026
3d16dc2
Add optimizeLegibility to value-keyword-case exceptions.
afercia Aug 12, 2026
d081421
Add @stylistic/selector-descendant-combinator-no-non-space true.
afercia Aug 12, 2026
d8d5cd8
Adjust a few rules.
afercia Aug 17, 2026
a568299
Ignore dashicons font-family.
afercia Aug 17, 2026
c1b5056
Apply a few minor JS coding standards to stylelintrc.js.
afercia Aug 17, 2026
de4c1a9
Try warnings threshold mechanism.
afercia Aug 19, 2026
41140e9
Normalize the glob path for Windows on CI.
afercia Aug 19, 2026
8add3f2
Increase warnings threshold.
afercia Sep 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/test-and-zip-default-themes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -242,20 +242,20 @@ jobs:
persist-credentials: false

- name: Set up Node.js for themes needing minification
if: matrix.theme == 'twentytwentytwo' || matrix.theme == 'twentytwentyfive'
if: matrix.theme == 'twentytwentytwo' || matrix.theme == 'twentytwentyfive' || matrix.theme == 'twentytwentyone'

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.

Suggested change
if: matrix.theme == 'twentytwentytwo' || matrix.theme == 'twentytwentyfive' || matrix.theme == 'twentytwentyone'
if: contains( fromJSON('["twentytwentyfive", "twentytwentytwo", "twentytwentyone"]'), matrix.php )

This makes it much easier to see what the required criteria is. I'm on the fence here about whether we should actually move this to the strategy.matrix instead, though. It would become something like:

    strategy:
      fail-fast: false
      matrix:
        theme: [
            'twentytwentyfive',
            'twentytwentyfour',
            'twentytwentythree',
            'twentytwentytwo',
            'twentytwentyone',
            'twentytwenty',
            'twentynineteen',
            'twentyseventeen',
            'twentysixteen',
            'twentyfifteen',
            'twentyfourteen',
            'twentythirteen',
            'twentytwelve',
            'twentyeleven',
            'twentyten'
        ]

        include:
                - theme: 'twentytwentyfive'
                  requires-minification: true
                - theme: 'twentytwentytwo'
                  requires-minification: true
                - theme: 'twentytwentyone'
                  requires-minification: true

Then the conditional check would simply be:

if: matrix.requires-minification

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Needs a decision on the two options for the themes first.

uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: 'src/wp-content/themes/${{ matrix.theme }}/.nvmrc'
cache: npm
cache-dependency-path: src/wp-content/themes/${{ matrix.theme }}/package-lock.json

- name: Install npm dependencies
if: matrix.theme == 'twentytwentytwo' || matrix.theme == 'twentytwentyfive'
if: matrix.theme == 'twentytwentytwo' || matrix.theme == 'twentytwentyfive' || matrix.theme == 'twentytwentyone'
run: npm ci
working-directory: src/wp-content/themes/${{ matrix.theme }}

- name: Build theme assets
if: matrix.theme == 'twentytwentytwo' || matrix.theme == 'twentytwentyfive'
if: matrix.theme == 'twentytwentytwo' || matrix.theme == 'twentytwentyfive' || matrix.theme == 'twentytwentyone'
run: npm run build
working-directory: src/wp-content/themes/${{ matrix.theme }}

Expand Down
27 changes: 27 additions & 0 deletions .stylelintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Ignore WordPress plugin files.
src/wp-content/plugins/**/*

# Ignore WordPress theme files.
src/wp-content/themes/**/*

# Ignore WordPress block files.
src/wp-includes/blocks/**/*

# Ignore admin color schemes auto generated files.
src/wp-admin/css/colors/*/*.css

# Ignore WordPress included dist files.
src/wp-includes/css/dist/**/*

# Ignore files copied to wp-includes js.
src/wp-includes/js/**/*

# Ignore WordPress JS vendor files.
src/js/_enqueues/vendor/**/*

# Ignore minified CSS files.
**/*.min.css

# Ignore RTL CSS files.
**/*-rtl.css
**/*-rtl.min.css
9 changes: 9 additions & 0 deletions .stylelintignore-themes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Ignore Node modules.
node_modules

# Ignore minified CSS files.
**/*.min.css

# Ignore RTL CSS files.
**/*-rtl.css
**/*-rtl.min.css
114 changes: 114 additions & 0 deletions .stylelintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/** @type {import('stylelint').Config} */
module.exports = {
extends: '@wordpress/stylelint-config/scss-stylistic',
plugins: [
'stylelint-plugin-logical-css',
'@wordpress/theme/stylelint-plugins/no-token-fallback-values',
],
reportNeedlessDisables: true,
rules: {
'at-rule-empty-line-before': [
'always',
{
except: [ 'blockless-after-blockless' ],
ignore: [ 'first-nested', 'after-comment' ],
},
],
'at-rule-no-unknown': null,
'comment-empty-line-before': null,
'declaration-property-unit-allowed-list': [
{
'line-height': [],
},
],
'declaration-property-value-allowed-list': [
{
'flex-direction': '/^(?!(row|column)-reverse).*$/',
},
{
message: ( property, value ) =>
`Avoid "${ value }" value for the "${ property }" property. For accessibility reasons, visual, reading, and DOM order must match. Only use the reverse values when they do not affect reading order, meaning, and interaction.`,
},
],
'font-family-no-missing-generic-family-keyword': [
true,
{
ignoreFontFamilies: [ 'dashicons' ],
},
],
'font-weight-notation': 'numeric',
'function-disallowed-list': [ 'rgb' ],
'no-descending-specificity': null,
'no-invalid-position-at-import-rule': null,
'property-disallowed-list': [
[ 'order' ],
{
message:
'Avoid the order property. For accessibility reasons, visual, reading, and DOM order must match. Only use the order property when it does not affect reading order, meaning, and interaction.',
},
],
'rule-empty-line-before': [
'always',
{
except: [ 'first-nested' ],
ignore: [ 'after-comment' ],
},
],
'selector-class-pattern': [
'^[a-z][a-z0-9]*(?:(?:__|--|-)[a-z0-9]+)*$',
{
message:
'Class selector should use lowercase class segments separated with hyphens, double hyphens, or double underscores',
},
],
'selector-id-pattern': [
'^([a-z][a-z0-9]*)(-[a-z0-9]+)*$',
{
message:
'ID selector should use lowercase and separate words with hyphens',
},
],
'selector-no-qualifying-type': [
true,
{
severity: 'warning',
},
],
'value-keyword-case': [
'lower',
{
ignoreKeywords: [
'currentColor',
'optimizeLegibility'
],
},
],
'scss/at-else-empty-line-before': null,
'scss/at-extend-no-missing-placeholder': null,
'scss/at-if-closing-brace-newline-after': null,
'scss/at-if-closing-brace-space-after': null,
'scss/comment-no-empty': null,
'scss/load-partial-extension': null,
'scss/no-global-function-names': null,
'scss/operator-no-newline-after': null,
'scss/operator-no-unspaced': null,
'scss/selector-no-redundant-nesting-selector': null,
'@stylistic/max-empty-lines': 1,
'@stylistic/max-line-length': null,
'@stylistic/selector-descendant-combinator-no-non-space': true,
// Keep these lines. Don't change their order otherwise indentation will break.
// It's not about a literal 'execution order', but rather a compatibility issue.
'@stylistic/block-closing-brace-newline-before': 'always',
'@stylistic/block-opening-brace-newline-after': 'always',
'@stylistic/declaration-block-semicolon-newline-after': 'always',
'@stylistic/selector-list-comma-space-after': 'always-single-line',
'@stylistic/selector-list-comma-newline-after': 'always',
'@stylistic/declaration-colon-newline-after': 'always-multi-line',
'@stylistic/indentation': 'tab',
// End keep these lines.
},
reportDescriptionlessDisables: true,
ignorePath: '.stylelintignore',
};


15 changes: 14 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1771,8 +1771,21 @@ module.exports = function(grunt) {
'qunit:compiled'
] );

grunt.registerTask( 'lint:css', 'Runs Stylelint on core CSS and checks warning-level rule thresholds.', function() {
var done = this.async();

grunt.util.spawn( {
cmd: 'node',
args: [ 'tools/stylelint/lint-css.js' ],
opts: { stdio: 'inherit' }
}, function( error ) {
done( ! error );
} );
} );

grunt.registerTask( 'precommit:css', [
'postcss:core'
'postcss:core',
'lint:css',
] );

grunt.registerTask( 'precommit:php', [
Expand Down
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@
"sinon": "16.1.3",
"sinon-test": "~3.1.6",
"source-map-loader": "5.0.0",
"stylelint": "16.26.1",
"stylelint-plugin-logical-css": "2.1.0",
"typescript": "6.0.3",
"update-browserslist-db": "1.3.1",
"uuid": "14.0.1",
Expand Down Expand Up @@ -126,6 +128,12 @@
"grunt": "grunt",
"lint:jsdoc": "wp-scripts lint-js",
"lint:jsdoc:fix": "wp-scripts lint-js --fix",
"lint:css": "node ./tools/stylelint/lint-css.js",
"lint:css:fix": "wp-scripts lint-style \"src/**/*.{css,scss}\" --fix",
"lint:css:thresholds": "node ./tools/stylelint/check-warning-thresholds.js",
"lint:css:thresholds:update": "node ./tools/stylelint/check-warning-thresholds.js --update",
"lint:css:themes": "wp-scripts lint-style \"src/wp-content/themes/**/*.{css,scss}\" --ignore-path .stylelintignore-themes",
"lint:css:themes:fix": "npm run lint:css:themes -- --fix",
"typecheck:js": "tsc --build",
"env:start": "node ./tools/local-env/scripts/start.js && node ./tools/local-env/scripts/docker.js run -T --rm php composer update -W",
"env:stop": "node ./tools/local-env/scripts/docker.js down",
Expand Down
12 changes: 0 additions & 12 deletions src/wp-content/themes/twentytwenty/.stylelintrc.json

This file was deleted.

4 changes: 2 additions & 2 deletions src/wp-content/themes/twentytwenty/assets/css/font-inter.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ Inter variable font. Usage:

@font-face {
font-family: "Inter var";
font-weight: 100 900; /* stylelint-disable-line font-weight-notation */
font-weight: 100 900;
font-style: normal;
font-display: swap;
src: url(../fonts/inter/Inter-upright-var.woff2) format("woff2");
}

@font-face {
font-family: "Inter var";
font-weight: 100 900; /* stylelint-disable-line font-weight-notation */
font-weight: 100 900;
font-style: italic;
font-display: swap;
src: url(../fonts/inter/Inter-italic-var.woff2) format("woff2");
Expand Down
21 changes: 1 addition & 20 deletions src/wp-content/themes/twentytwenty/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions src/wp-content/themes/twentytwenty/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@
"concurrently": "^9.2.1",
"postcss": "^8.5.6",
"postcss-cli": "^11.0.1",
"rtlcss": "^4.3.0",
"stylelint-a11y": "^1.2.3"
"rtlcss": "^4.3.0"
},
"browserslist": [
"extends @wordpress/browserslist-config"
Expand All @@ -56,7 +55,6 @@
"build:vendor-prefixes-style": "postcss -r --no-map style.css assets/css/editor-style-block.css assets/css/editor-style-classic.css",
"build:vendor-prefixes-esb": "postcss -r --no-map assets/css/editor-style-block.css ",
"build:vendor-prefixes-esc": "postcss -r --no-map assets/css/editor-style-classic.css",
"lint:css": "wp-scripts lint-style 'style.css' 'assets/**/*.css'",
"lint:js": "wp-scripts lint-js 'assets/**/*.js'",
"lint:pkg-json": "wp-scripts lint-pkg-json"
}
Expand Down
4 changes: 2 additions & 2 deletions src/wp-content/themes/twentytwenty/style-rtl.css
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,15 @@ Inter variable font. Usage:

@font-face {
font-family: "Inter var";
font-weight: 100 900; /* stylelint-disable-line font-weight-notation */
font-weight: 100 900;
font-style: normal;
font-display: swap;
src: url(./assets/fonts/inter/Inter-upright-var.woff2) format("woff2");
}

@font-face {
font-family: "Inter var";
font-weight: 100 900; /* stylelint-disable-line font-weight-notation */
font-weight: 100 900;
font-style: italic;
font-display: swap;
src: url(./assets/fonts/inter/Inter-italic-var.woff2) format("woff2");
Expand Down
4 changes: 2 additions & 2 deletions src/wp-content/themes/twentytwenty/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,15 @@ Inter variable font. Usage:

@font-face {
font-family: "Inter var";
font-weight: 100 900; /* stylelint-disable-line font-weight-notation */
font-weight: 100 900;
font-style: normal;
font-display: swap;
src: url(./assets/fonts/inter/Inter-upright-var.woff2) format("woff2");
}

@font-face {
font-family: "Inter var";
font-weight: 100 900; /* stylelint-disable-line font-weight-notation */
font-weight: 100 900;
font-style: italic;
font-display: swap;
src: url(./assets/fonts/inter/Inter-italic-var.woff2) format("woff2");
Expand Down
10 changes: 0 additions & 10 deletions src/wp-content/themes/twentytwentyone/.stylelintignore

This file was deleted.

Loading
Loading