---
title: Build and release
---

`bash scripts/build.sh` is the only supported way to produce the distributable. The release workflow, Plugin Check, and a local developer all run that script.

## Build the zip

Prerequisites on `PATH`: `npm`, `composer`, `zip`, `rsync`, `php`. If `node_modules` is missing, the script runs `npm ci`.

<!-- wp:docspress/flow {"start":1,"steps":[{"title":"Build JavaScript","content":"<p><code>npm run build</code> writes <code>build/admin.js</code> and <code>build/admin.asset.php</code>.</p>"},{"title":"Install runtime Composer dependencies","content":"<p><code>composer install --no-dev --optimize-autoloader</code>. Outside CI the script restores development dependencies at the end.</p>"},{"title":"Copy the allow-list","content":"<p>rsync each item through <code>.distignore</code> into <code>build/plugin-scaffold/</code>.</p>"},{"title":"Assert required and forbidden paths","content":"<p>Missing runtime files fail the build. <code>node_modules</code>, <code>.npmrc</code>, <code>auth.json</code>, <code>.git</code>, <code>src</code>, <code>tests</code>, and <code>overlays</code> must not appear in the output.</p>"},{"title":"Compare versions and zip","content":"<p>The plugin header Version must match <code>.release-please-manifest.json</code>. Then <code>build/plugin-scaffold.zip</code> is created.</p>"}]} /-->

<!-- wp:docspress/terminal-session {"title":"Build the distributable","shell":"bash","prompt":"$","command":"bash scripts/build.sh","output":""} /-->

### Copy list

<!-- wp:docspress/fields {"title":"scripts/build.sh copy_list","description":"Each path is skipped with a warning when missing, except the later required-file assertions.","fields":[{"name":"plugin-scaffold.php","type":"string","required":true,"defaultValue":"","description":"Main plugin file. Also required in the output.","values":"","deprecated":false},{"name":"uninstall.php","type":"string","required":true,"defaultValue":"","description":"Uninstall file. Also required in the output.","values":"","deprecated":false},{"name":"includes","type":"string","required":true,"defaultValue":"","description":"PHP classes. Bootstrap.php is required in the output.","values":"","deprecated":false},{"name":"languages","type":"string","required":false,"defaultValue":"","description":"Text domain path. Present as languages/index.php.","values":"","deprecated":false},{"name":"vendor","type":"string","required":true,"defaultValue":"","description":"Runtime autoloader. vendor/autoload.php is required.","values":"","deprecated":false},{"name":"composer.json","type":"string","required":false,"defaultValue":"","description":"Copied into the zip. composer.lock is in .distignore.","values":"","deprecated":false},{"name":"LICENSE","type":"string","required":false,"defaultValue":"","description":"GPL-2.0 text.","values":"","deprecated":false},{"name":"README.md","type":"string","required":false,"defaultValue":"","description":"Copied into the zip.","values":"","deprecated":false}],"searchable":true,"compact":true} /-->

Optional extras the script copies when present:

- Root `build/` into the package `build/` (excluding the package directory and zip)
- `readme.txt` (WordPress.org overlay), with release-please marker lines stripped
- `blocks/build` into `blocks/build` (blocks overlay)

Required files after copy: `plugin-scaffold.php`, `uninstall.php`, `includes/Core/Bootstrap.php`, `vendor/autoload.php`, `build/admin.js`, `build/admin.asset.php`. The packaged autoloader must resolve `Linchpin\Plugin_Scaffold\Core\Bootstrap`.

`.distignore` is the second exclusion layer. It lists development paths including `/src`, `/tests`, `/docs`, `/overlays`, and `/scripts`.

## Release

`release-please-config.json` uses `release-type: php` for the `.` package named `plugin-scaffold`. Extra files that receive the version: `plugin-scaffold.php`, `README.md`, `.release-please-manifest.json`, and `package.json` `$.version`. Tags include `v` and do not include the component name.

`.github/workflows/release-please.yml` on `main`:

1. `googleapis/release-please-action@v5` with `secrets.GH_BOT_TOKEN`
2. On `release_created`, run Plugin Check
3. On success, run `bash scripts/build.sh` and attach `build/plugin-scaffold.zip` to the tag as `plugin-scaffold.zip`

Current manifest version: **0.1.0**. `CHANGELOG.md` records that as the initial house standard.

<!-- wp:docspress/callout {"tone":"note","title":"WordPress.org deploy is an overlay","content":"<p>SVN publish lives in the <a href=\"../overlays/wporg.md\">wporg overlay</a>, not in this repository&apos;s default workflows.</p>","collapsible":false} /-->
