# Guide to Contributing Code

The following guide will help you through the process of contributing code to the themes repo.

By contributing code to our free themes, you grant its use under the [GNU General Public License v2 (or later)](LICENSE).

## Prerequisites

This repo is a [monorepo](https://en.wikipedia.org/wiki/Monorepo) which stores all the themes maintained by the Automattic Theme Team. We use [Node.js](https://nodejs.org/) to run utility functions from the top-level directory, and also to run commands for some themes, such as building CSS files.

**Node version:** Check `.nvmrc` for the current required version. `.nvmrc` is the source of truth — always use `nvm use` from the repo root.

We recommend using the [Node Version Manager](https://github.com/nvm-sh/nvm) (nvm) since it is the easiest way to install and manage Node for macOS, Linux, and Windows 10. See the Node.js site for additional installation instructions.

Some themes depend on [`node-sass`](https://npmjs.com/package/node-sass). `node-sass` uses an old version of `node-gyp` (and won't update because `node-sass` is deprecated). The old version of `node-gyp` depends on `distutils`. However, Python doesn't ship with `distutils` anymore, so you need to install it separately.

On macOS this is done with Homebrew: `brew install python-setuptools`.

On other systems it's done with PIP: `pip install setuptools`.

Also make sure you have an updated version of git installed on your computer, as well as a GitHub account with access to GHE.

## Local Environment Setup

The repo includes a `.wp-env.json` that maps the entire repo as the themes directory, so all themes are available locally:

```bash
nvm use
npm install
npx wp-env start
```

Visit `http://localhost:8888` to preview themes. Admin: `http://localhost:8888/wp-admin` (admin / password).

As an alternative to wp-env, you can use [Studio](https://developer.wordpress.com/studio/) (recommended), [Local](https://localwp.com/), [WampServer](http://www.wampserver.com/en/), or [MAMP](https://www.mamp.info/).

## Local Themes Setup

Clone the repo locally and then install the dependencies:

```bash
nvm use
npm install
composer install
```

## Coding Standards

Themes code should adhere to the [WordPress coding standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/). This repo contains a pre-commit hook which enables you to detect and fix code that doesn't follow the standards.

To set this up follow these instructions:
1. Run `npm install` in the root of the repo.
2. Run `composer install`

Now when you commit changes to a file PHPCBF will attempt to fix any issues with the file.

This will also install the [WordPress-standard Prettier Configuration](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-prettier-config/) which can (optionally) be used in your IDE or command-line to format your code via [Prettier](https://prettier.io/docs/en/editors.html).

### Browser Support

Follow the latest two versions of Chrome, Firefox, Safari, Opera, and Edge. See the Field Guide browser support page and the repo's `browserslist` config for specifics. The [WordPress Core handbook](https://make.wordpress.org/core/handbook/best-practices/browser-support/) also provides guidance for .org compatibility.

## Contributing CSS

A great way to get started with contributing to our themes is to pick up a CSS fix or patch.

A lot of our themes use SASS for styling, and then use Node to compile the final CSS. Usually, these themes will have a `sass` directory, and there will also be a `package.json` file at the root of the theme.

In order to change the styles in these themes, you need to edit the SASS file first, and then run a build command to compile the CSS. Here is the process in most cases, using Varia as an example:

1. Change to the theme's directory `cd varia`
2. Find the `.scss` file you need to edit in the `sass` directory
3. Make your changes
4. Run the build command using `npm run build`
5. You should see your updates in the newly built `.css` file/s

If you are unsure what to do, leave us a comment so that we can improve documentation for other themes that may work differently.

### Best Practices

We use the latest features from the CSS, HTML and JS specifications, where our browser support will allow it. [Caniuse.com](https://caniuse.com/) is a great way to check if a feature is supported.

We use intrinsic web design in our themes where possible. [Every Layout](https://every-layout.dev/rudiments/boxes/) is a good resource for this.

## Workflow

Here is a quick summary of our workflow:

1. Create a pull request with your changes
2. Request a review from the theme team
3. The Theme Team will provide feedback or approve your PR
4. A TeamCity build will automatically version-bump and update the changelog (see below)
5. The team will merge and deploy your PR

### Creating a pull request

When your changes are ready for review you should create a pull request. Here are a couple tips for crafting a great pull request:

* Include the purpose of your PR. Be explicit about the idea or issue your PR solves.
* Reference any existing Linear issues that relate to your PR. This allows everyone to easily see all related discussions.

The Theme Team will be notified when a new pull request is opened and we triage new issues and PRs regularly. Request a review using the team handle `@Automattic/theme-design` on the PR.

Once your PR has been approved, the Theme Team will merge and deploy your change. **Please note that merging a PR does not automatically deploy a change.**

### Automated version bumps and changelogs

When you open or push to a PR, a TeamCity build automatically:
- Bumps the version in `style.css` and `package.json` for any changed theme
- Updates the changelog in the theme's `readme.txt`
- Commits these changes to your branch with `[Automated] Version bump and changelog update`

Review these automated changes before merging and make manual adjustments if the changelog entries need refinement.

## Deploying changes

After merging to trunk, deploy your theme to WordPress.com:

1. **Theme Dashboard (preferred):** Open the Theme Dashboard in Mission Control, find your theme, click "Deploy." No sandbox needed.
2. **Sandbox:** Run `deploy pub <theme-slug>` on your sandbox.

For non-theme files (utils, config): `deploy pub <filename>`.

See also the Theme Dashboard deploy page in Mission Control for pending deploys and syntax reminders.

The easiest way to deploy a change is to let the Theme Team handle it! This is because not everyone has a sandbox or the appropriate commit rights to handle a deployment.

Deploying changes is part of the team's daily processes. We try to deploy approved changes as soon as possible, often multiple times a day. Please leave a comment if you have any questions or you want us to trigger a deploy.

**Note:** `.org` deploys are handled separately and are not part of this workflow.

## Sandbox Tools

If you use a sandbox to test or develop your themes you can use a couple of utilities to operate on that sandbox.

- From the top-level directory, run `node .theme-utils/index.mjs clean-sandbox` to bring the public themes GIT repository to a clean state.  (This will only matter if your sandbox uses GIT such as how _WordPress.com_ is currently managed.)  Alternately you can trigger that as an npm script: `npm run sandbox:clean`. `npm run sandbox:clean-all` will clean the entire sandbox.

- From the top-level directory, run `node .theme-utils/index.mjs push-to-sandbox` to push your entire working copy to the public themes folder of your sandbox.  Alternately you can trigger this as an npm script: `npm run deploy:push:all` This command will rsync your local copy with the exception of anything in the `.sandbox-ignore` file. You should clean your sandbox before pushing any changes to it. `node .theme-utils/index.mjs push-changes-to-sandbox` or `npm run deploy:push:changes` alternatively will push only files that have changed since the last deployment.

## Validation Tools

When you update a theme and open a pull request, the validation tools will automatically run as a check on your PR.

However you can run them locally as well.

```sh-session
$ node .theme-utils/index.mjs help validate-theme

validate-theme [--format=FORMAT] [--color=WHEN] [--table-width=COLUMNS] <array of theme slugs>

Validates a theme against the WordPress theme requirements.

--format=FORMAT

        Output format. Possible values: *table*, json, dir.

--color=WHEN

        Colorize the output for table or dir formats. The automatic mode only enables colors if
        an interactive terminal is detected. Possible values: *auto*, always, never.

--table-width=COLUMNS

        Explicitly set the width of the table format instead of determining it automatically.
        Will default to 120 if omitted and width cannot be determined automatically.
```

Here's an example of the output.

<img width="828" alt="image" src="https://github.com/user-attachments/assets/987d6c2f-b993-4c16-b678-1757752ea820">

This is how you run validation on a single theme:

```sh-session
$ node .theme-utils/index.mjs validate-theme grammer

Progress: [ '■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■', 100 ] 1/1

╔═════════════════════════════════════════════════════════════╤══════════════════════════╗
║ ERROR                                                       │ Message : missing 'Requi ║
║ Theme : Grammer                                             │ res at least' header met ║
║ File  : style.css                                           │ adata                    ║
╟─────────────────────────────────────────────────────────────┼──────────────────────────╢
║ WARNING                                                     │ Actual   : undefined     ║
║ Theme : Grammer                                             │ Expected : 5.9 or greate ║
║ File  : style.css                                           │ r                        ║
║                                                             │ Message  : the 'Requires ║
║                                                             │  at least' version does  ║
║                                                             │ not support theme.json   ║
╟─────────────────────────────────────────────────────────────┼──────────────────────────╢
║ WARNING                                                     │ Instance path : /setting ║
║ Theme  : Grammer                                            │ s/spacing/spacingScale   ║
║ File   : theme.json                                         │ Schema path   : #/defini ║
║ Schema : https://schemas.wp.org/trunk/theme.json            │ tions/settingsSpacingPro ║
║                                                             │ perties/properties/spaci ║
║                                                             │ ng/properties/spacingSca ║
║                                                             │ le/additionalProperties  ║
║                                                             │ Keyword       : addition ║
║                                                             │ alProperties             ║
║                                                             │ Params        : { additi ║
║                                                             │ onalProperty: 'theme' }  ║
║                                                             │ Message       : must NOT ║
║                                                             │ have additional properti ║
║                                                             │ es                       ║
╟─────────────────────────────────────────────────────────────┼──────────────────────────╢
║ WARNING                                                     │ Instance path :          ║
║ Theme  : Grammer                                            │ Schema path   : #/requir ║
║ File   : assets/fonts/font-collection.json                  │ ed                       ║
║ Schema : https://schemas.wp.org/wp/6.5/font-collection.json │ Keyword       : required ║
║                                                             │ Params        : { missin ║
║                                                             │ gProperty: 'slug' }      ║
║                                                             │ Message       : must hav ║
║                                                             │ e required property 'slu ║
║                                                             │ g'                       ║
║                                                             ├──────────────────────────╢
║                                                             │ Instance path :          ║
║                                                             │ Schema path   : #/requir ║
║                                                             │ ed                       ║
║                                                             │ Keyword       : required ║
║                                                             │ Params        : { missin ║
║                                                             │ gProperty: 'name' }      ║
║                                                             │ Message       : must hav ║
║                                                             │ e required property 'nam ║
║                                                             │ e'                       ║
╚═════════════════════════════════════════════════════════════╧══════════════════════════╝

Validation passed with warnings.
```

<img width="1728" alt="image" src="https://github.com/user-attachments/assets/68e38c35-224b-407c-8333-b4ac0b881fd8">

It works with pagers. This example shows how to match the table width to your terminal width inside a pager.

```sh-session
$ # You may need to wait a while for longer lists of themes.
$ node .theme-utils/index.mjs validate-theme --color=always --table-width=$(( $(tput cols) )) atheme,adventurer,grammer,skatepark | less -R
```

The added `--format=json` option is super helpful when combined with [`jq`](https://jqlang.github.io/jq/download/) to drill down into the data.

This, for example, is the breakdown of all the current themes and a count of the types of problems that they have:

```sh-session
$ # Scroll to see the long command →
$ node .theme-utils/index.mjs validate-theme --format=json $(find . -name 'theme.json' | awk -F/ '{print $2}' | uniq | sort | paste -s -d, -) | jq '.[].data[].message' | sort | uniq -c | sort -bgr
5815 "must NOT have additional properties"
 696 "must be object"
 551 "must be string"
 328 "the $schema version does not match style.css 'Requires at least' version"
 153 "must match exactly one schema in oneOf"
  73 "must be equal to constant"
  71 "the 'Requires at least' version does not support theme.json"
  71 "must be equal to one of the allowed values"
  47 "Missing $schema URI: undefined"
   6 "property name must be valid"
   5 "must be number"
   2 "must be >= 1"
   2 "missing 'Requires at least' header metadata"
   1 "must have required property 'version'"
   1 "must have required property 'slug'"
   1 "must have required property 'name'"
```

## Further Reading

See [AGENTS.md](AGENTS.md) for comprehensive development instructions, including directory structure, classic vs block theme guidance, CI/CD details, architectural decisions, and common pitfalls.
