This repository contains WordPress themes and plugins managed within a single Git monorepo. The primary goals are consistency, shared tooling, and safer long-term maintenance while preserving historical context.
pnpm is the required package manager for this repository. To install:
npm install -g pnpmThis repository uses nx for various monorepo-related tasks:
- Calculating project graph and affected projects
- A project dependency graph is automatically calculated by
nx, for example, child themes would be dependent on their parent theme such that any change to the parent theme code causes its child themes to have the build/test pipeline run on them (see.github/workflows/). We can use thenx show projects --affectedcommand to get the list of projects affected by changes in the current branch.
- A project dependency graph is automatically calculated by
- Task orchestration and caching
- Tasks (eg.
npmscripts) can be run easily for many projects using commands likenx run-many -t buildwhich will cause all projects with annpmbuildscript to run in parallel. Results of the above command will also be cached and stored in.nx/cacheso that if the same command is run again without changes to the underlying source files, the command will finish immediately using the cached result.
- Tasks (eg.
- Repository importing
- The process of importing a new plugin or theme into the monorepo can be done using the
nx importcommand, given a repository and a monorepo path.
- The process of importing a new plugin or theme into the monorepo can be done using the
- Release process (eventually)
- The process of releasing a version of a plugin or theme may be able to be automated using the
nx releasecommand. More research is needed to determine how this might work.
- The process of releasing a version of a plugin or theme may be able to be automated using the
See the nx documentation for more information.
Using the nx generator feature, we can easily create a new theme in the monorepo using the command:
npx nx generate monorepo-plugin:theme
pnpm installFollow the on-screen instructions to generate a standalone or child theme that adheres to the current theme standards.
From the monorepo root, run the plugin generator and then install dependencies:
npx nx generate monorepo-plugin:plugin
pnpm installDuring generation, the CLI will prompt for the plugin name and, optionally, a description. Use those prompts to configure the plugin you want to scaffold.
The generator creates a new Block Plugin that follows the current monorepo plugin standards.
If wp-env start fails with port is already allocated (for example 8888), run:
pnpm run wp-env:cleanupIn order for the syncing to the mirror repos (standalone, readonly theme or plugin repositories) to work correctly for testing on the test server or performing releases, we need to add authentication for a bot user to be allowed to push to those repos. This involves:
- Create the mirror repo if it doesn't exist already.
- Set up branch protection rules to disallow commits from any user other than the bot user that will be pushing to it. It's not intended for users to make any changes to the mirror repos.
- See settings on the Belleville Terminal repository for an example.
- Update the Personal Access Token to add the new mirror repo under
Repository access>Only select repositories.- Note that the PAT is what is stored in the monorepo's
PUBLISH_REPO_TOKEN. If we change which user's PAT we want to use for authentication, we must update this secret with the new token.
- Note that the PAT is what is stored in the monorepo's
The example below assumes you are adding a theme and uses example-theme as a placeholder for the existing repository name.
⚠️ Important This process rewrites Git history. Do not run it directly on the original repository.
npx nx import <git repo url> <destination path>Then follow the on-screen wizard to finish the import.
Example:
npx nx import https://github.com/bcgov/design-system-wordpress-theme themes/design-system-wordpress-theme- Temporarily rename the directory of the new project, for example adding a
_to the beginning.- This is so that the next step can run without causing issues with the directory already existing.
- Run the relevant generator for the project type, for example
npx nx generator monorepo-plugin:theme(ormonorepo-plugin:plugin). - Provide the values to the generator that match the project, for example if the project's slug is
design-system-child-example, provide that value to the generator as the slug. - Copy the contents of the directory the generator created into the imported project directory (the one we renamed in step 1).
- We want the files to be overwritten with changes from the generator files.
- You may need to do this outside of VSCode as it doesn't seem to allow overwriting of files by default.
- Delete the generator-created directory.
- Rename the imported directory back to its original name.
- Go through the files changed using git and individually revert any changes that should not be overwritten, for example plugin/theme version should not be overwritten with the default
1.0.0set by the generator, any sample files can be deleted. - Delete any unnecessary files, like files used for linting. List of files to be delete:
- .github/
- dist/
- .gitignore
- .markdownlint*
- CODEOWNERS
- composer.lock
- package.lock
- Commit the above changes.
- Run all relevant nx targets to ensure they are functioning. See
project.jsonfor the full list of targets. - Run linting to ensure linting passes for the imported project (
pnpm lint).
⚠️ Not yet finalized
Theme- and plugin-level workflows will eventually be replaced by root-level workflows that target packages based on changed paths.
- This monorepo does not produce production releases
- Official releases continue to be cut from original repositories
- Scoped tags and release branches exist for historical reference and future planning
Todo: Determine how to automate release process using nx.
npx nx release ...This repository uses npm workspaces to manage JavaScript dependencies across themes and plugins.
{
"workspaces": ["themes/*", "plugins/*"]
}This configuration:
- Treats each theme and plugin as an independent package
- Hoists compatible dependencies to a shared root
node_modules - Enables running scripts across all packages from the repository root
From the repository root:
npm installThis installs root tooling and all workspace dependencies. There is no need to run npm install inside individual packages.
Example:
npm run buildThis runs build in each workspace where the script exists, using the workspace directory as the execution context.
Each theme or plugin must:
- Include its own
package.json - Declare all direct dependencies it requires
⚠️ Do not rely on implicitly hoisted dependencies.
Each directory containing a package.json is a separate workspace package and must be explicitly included.
Example:
{
"workspaces": [
"themes/*",
"plugins/example-plugin",
"plugins/example-plugin/Blocks/*",
"packages/*"
]
}Some tooling (e.g. @wordpress/scripts) relies on peer dependencies.
If a workspace script fails with MODULE_NOT_FOUND:
- Identify the missing module
- Add it to the workspace’s
devDependencies - Re-run
npm installfrom the repository root
All packages must implement the following npm scripts:
buildcomposer:install- If tests exist,
wp-env,test:e2e, etc.
To reduce duplication and configuration drift, this monorepo centralizes common tooling and configuration files at the repository root wherever possible. Themes and plugins consume these shared configurations rather than maintaining their own copies.
The goal is to keep packages lightweight while enforcing consistent standards across the ecosystem.
The following files and directories are intended to live at the monorepo root and be reused by all themes and plugins:
.eslint.*.markdownlint.*.prettierrc.js.stylelintrcphpcs.xml
- Shared
@wordpress/scriptsexpectations - Common overrides
- Root-level
package.jsonscripts - All linting (PHP, JS, CSS, etc.) is performed via the root
package.jsonscripts
Themes and plugins should only add package-local build configuration when they have legitimate, product-specific needs.
- PHPUnit configuration
- Playwright configuration (
packages/e2e/playwright.config.js) - wp-env configuration (
.wp-env.json) - Shared test utilities and bootstrap files (under
packages/e2e/)
Individual packages may define minimal wrapper configs that reference the shared setup.
- Root
.gitignorecontains common patterns (e.g.,node_modules,vendor,build,distlogs) - Packages keep only project-specific ignores
- All CI workflows live under
.github/workflows/at the root - TODO: Migrate from packages - Workflows target themes/plugins using path filters and workspace execution
As packages are migrated:
- Theme- or plugin-local workflows should be removed
- CI behavior is preserved via centralized workflows
package.json(required per package)- Package-specific scripts
- Dependencies used by that package
As packages move into the monorepo, it is expected that:
- Redundant config files are deleted from the package
- Package configs are simplified to reference shared root files
- GitHub workflows are removed from the package
- CI behavior is validated via root workflows
npm is the supported package manager. pnpm may be evaluated experimentally but is not part of the official workflow.
- npm remains the source of truth
- No CI changes
- No script contract changes
At the repository root, define workspaces of any package.json files in pnpm-workspace.yaml, e.g.:
packages:
- "themes/*"
- "plugins/*"
- "packages/*"brew install pnpm
pnpm install
pnpm -r run build
pnpm --filter example-theme run build