npm-based build and deploy toolkit for any WordPress plugin.
Compile SCSS and JavaScript, package a production zip, rsync to your server, and optionally publish to WordPress.org SVN — all driven by one config file in your plugin.
A modern, config-first alternative to Grunt.
- Plugin authors replacing Grunt / custom shell scripts
- Teams that want one standard workflow across multiple plugins
- Free plugins on WordPress.org or commercial / private plugins (SVN is optional)
In your WordPress plugin root:
npm install @alimir/wp-toolkit --save-devPackage: @alimir/wp-toolkit on npm
While developing the toolkit itself, link it locally:
npm install /path/to/wp-toolkit --save-dev1. Create your plugin config (this is where your paths and settings go):
cp node_modules/@alimir/wp-toolkit/wp-toolkit.config.example.mjs wp-toolkit.config.mjsEdit wp-toolkit.config.mjs — set your slug, asset paths, deploy targets, and release options.
2. Add environment variables (secrets never go in the config file):
cp node_modules/@alimir/wp-toolkit/.env.example .env3. Add npm scripts to your plugin package.json:
{
"scripts": {
"build": "wp-toolkit build",
"build:js": "wp-toolkit build:js",
"build:css": "wp-toolkit build:css",
"dev": "wp-toolkit dev",
"i18n": "wp-toolkit i18n",
"i18n:json": "wp-toolkit i18n:json",
"product": "wp-toolkit product",
"release": "wp-toolkit release"
},
"devDependencies": {
"@alimir/wp-toolkit": "^2.0.1"
}
}4. Build:
npm run buildOutput lands in build/<your-slug>/ plus build/<your-slug>.zip.
| Command | Description |
|---|---|
wp-toolkit build |
Full production build + zip |
wp-toolkit build:js |
Compile and minify JavaScript only |
wp-toolkit build:css |
Compile SCSS and minify CSS only |
wp-toolkit dev |
Watch SCSS/JS and rebuild on change |
wp-toolkit deploy <name> |
Rsync build/ to a configured server (default: prod) |
wp-toolkit product [name] |
Build, then deploy (default: prod) |
wp-toolkit release |
Build, then publish to WordPress.org SVN |
wp-toolkit i18n |
Generate .pot file (requires WP-CLI) |
wp-toolkit i18n:json |
Generate JSON from .po files |
WP_RELEASE_DRY_RUN=1 npm run release # preview SVN changes, no commit
WP_RELEASE_YES=1 npm run release # skip interactive confirmation
WP_RELEASE_MESSAGE="Release 1.2.0" npm run releaseAll plugin-specific settings live in wp-toolkit.config.mjs. Every asset path is explicit — wp-toolkit does not guess filenames from your slug.
The config uses one lifetime structure. Required sections are validated on startup with clear errors when something is missing or invalid.
| Section | Required | Purpose |
|---|---|---|
| Identity | yes | slug, mainFile, textDomain |
assets |
yes | js.bundles, css.sassEntries (use [] / {} when unused) |
build |
yes | excludes and release packaging options |
release |
no | WordPress.org SVN (enabled: true + svnUrl) |
deploy |
no | Rsync targets for commercial / private plugins |
i18n |
no | POT generation (domain + potFile when present) |
variants |
no | Alternate builds (regional, white-label, …) |
export default {
slug: 'my-plugin',
mainFile: 'my-plugin.php',
textDomain: 'my-plugin',
assets: {
js: {
bundles: [
{
sources: ['assets/js/src/app.js'],
output: 'assets/js/my-plugin.js',
minOutput: 'assets/js/my-plugin.min.js',
},
],
},
css: {
sassEntries: {
'assets/css/my-plugin.css': 'assets/sass/my-plugin.scss',
},
},
},
build: {
excludes: ['assets/sass', 'assets/js/src'],
},
// WordPress.org:
release: { enabled: true, svnUrl: 'https://plugins.svn.wordpress.org/my-plugin' },
// Commercial / private:
// release: { enabled: false },
// deploy: { prod: { envPrefix: 'DEPLOY_PROD' } },
};npm run build # → build/my-plugin.zip
npm run dev # watch assets
npm run release # WP.org only
npm run product # deploy onlyvalidation.inheritExcludes is on by default — paths in build.excludes are automatically blocked from release zips.
Version in zip + versioned zip name (commercial plugins):
build: {
zipName: '{slug}.{version}.zip',
versionFile: { enabled: true, includeInZip: true },
},Deploy to multiple servers — add a name, add matching .env vars:
deploy: {
prod: { envPrefix: 'DEPLOY_PROD' },
staging: { envPrefix: 'DEPLOY_STAGING' },
},wp-toolkit product stagingPre/post build hooks — run your own commands as part of wp-toolkit build:
build: {
hooks: {
preBuild: ['npm run codegen'],
postBuild: ['npm run notify:slack'],
},
},Hooks accept shell strings or objects:
{ command: 'node', args: ['scripts/generate.php'], cwd: 'tools' }Use when you need a second build with different strings or zip name.
Deploy on a variant is optional — omit it for build-only variants.
variants: {
regional: {
zipSuffix: '-regional',
replacements: [{ from: 'example.com', to: 'example.ir' }],
files: ['**/*.php'],
deploy: 'staging', // optional — name from deploy.{name} above
},
},wp-toolkit build --variant regional
wp-toolkit product --variant regional # build + deploy (uses variant.deploy)Add custom npm scripts for convenience:
"build:regional": "wp-toolkit build --variant regional",
"product:regional": "wp-toolkit product --variant regional"| Option | Purpose |
|---|---|
slug |
Plugin folder name, zip name, deploy path |
mainFile |
Main plugin PHP file |
textDomain |
Translation text domain |
assets.js.bundles |
JS bundles — each needs sources, output, minOutput |
assets.js.minify |
Standalone minify targets ({ input, output }) |
assets.css.sassEntries |
SCSS input → CSS output map |
assets.css.minifySeparate |
Keep unminified .css alongside .min.css |
assets.watch |
Extra directories to watch in dev |
build.excludes |
Paths excluded from build/ |
build.devOnlyFiles |
Files stripped from the production zip |
build.preprocess |
Flags for /* @if PRO */ conditional blocks |
build.hooks |
preBuild and postBuild shell commands |
build.zipName |
Zip filename template ({slug}, {version}, …) |
build.versionFile |
Write a version txt beside or inside the zip |
build.trimTrailingWhitespace |
Strip trailing spaces/tabs from text files in the release bundle (default: true) |
deploy |
Named rsync targets (prod, staging, …) |
release |
WordPress.org SVN (enabled: true requires svnUrl) |
i18n |
POT generation (domain, potFile) |
validation.inheritExcludes |
Merge build.excludes into release checks (default: true) |
validation.forbidden |
Extra paths that must not appear in a release zip |
validation.checkMinifiedAssets |
Warn if PHP enqueues unminified assets (default: true) |
In wp-toolkit.config.mjs:
release: {
enabled: true,
wpAssets: 'wp-assets',
svnUrl: 'https://plugins.svn.wordpress.org/my-plugin',
},In .env:
WP_SVN_USER=your-wordpress-org-username
WP_SVN_PASSWORD=your-application-password
WP_SVN_URL=https://plugins.svn.wordpress.org/my-plugin
Release behaviour:
- Sparse SVN checkout (fast; avoids flooding output with old tags)
- Blocks re-releasing the same version tag
- Asks you to type
yesbefore committing
release: { enabled: false },
deploy: { prod: { envPrefix: 'DEPLOY_PROD' } },npm run productMultiple JS bundles, custom rsync, inline variant deploy
Multiple JS bundles — add more entries under assets.js.bundles:
assets: {
js: {
bundles: [
{ sources: ['assets/js/src/app.js'], output: 'assets/js/my-plugin.js', minOutput: 'assets/js/my-plugin.min.js' },
{ sources: ['admin/assets/js/src/admin.js'], output: 'admin/assets/js/admin.js', minOutput: 'admin/assets/js/admin.min.js' },
],
},
},Custom rsync args — add to any deploy target:
deploy: {
staging: {
envPrefix: 'DEPLOY_STAGING',
rsync: { args: ['-avzP', '--delete-after'] },
},
},Variant deploy override — only if you need different rsync per variant:
variants: {
regional: {
deploy: { target: 'staging', rsync: { args: ['-avzP', '--delete-after'] } },
},
},Copy .env.example to .env in your plugin root. Never commit .env.
Deploy target names in config use envPrefix. That prefix becomes your .env keys:
| Config | .env keys |
|---|---|
deploy.prod.envPrefix: 'DEPLOY_PROD' |
DEPLOY_PROD_HOST, DEPLOY_PROD_DEST, DEPLOY_PROD_PORT |
| Variable | Used by |
|---|---|
DEPLOY_<NAME>_HOST |
Rsync SSH host |
DEPLOY_<NAME>_PORT |
SSH port (optional) |
DEPLOY_<NAME>_DEST |
Remote plugin directory (absolute path) |
WP_SVN_USER |
WordPress.org SVN username |
WP_SVN_PASSWORD |
WordPress.org application password |
WP_SVN_URL |
SVN repository URL |
WP_RELEASE_DRY_RUN |
Preview release without committing |
WP_RELEASE_YES |
Skip confirmation prompt |
WP_RELEASE_MESSAGE |
Custom SVN commit message |
- Node.js 18+
zipandrsynconPATHsvn— only for WordPress.org releasewp(WP-CLI) — only fori18ncommands- Optional:
pngquant,jpegoptimfor image compression during build
your-plugin/
├── wp-toolkit.config.mjs ← your plugin settings (commit this)
├── .env ← secrets (gitignored)
├── package.json
├── assets/
├── build/ ← generated (gitignored)
└── node_modules/
MIT