Skip to content

Ship an installable plugin zip instead of the source archive - #4

Merged
henry-mosh merged 1 commit into
mainfrom
feat/wordpress-plugin-zip-structure-523a41
Aug 4, 2026
Merged

Ship an installable plugin zip instead of the source archive#4
henry-mosh merged 1 commit into
mainfrom
feat/wordpress-plugin-zip-structure-523a41

Conversation

@henry-mosh

Copy link
Copy Markdown
Collaborator

Why

GitHub's Download ZIP button is a source archive, not an install path. It produces wordpress-plugin-main.zip, which unpacks to wordpress-plugin-main/ and carries tests/, .github/ and the Composer files with it. WordPress keys a plugin by its directory name — that name lands in the plugins list, in update checks and in every support thread — so anyone installing that way gets the plugin under the wrong slug plus a pile of development files.

GitHub's archive name can't be changed, so the fix is to publish a real release artifact and point installs at it.

What changed

  • bin/build-plugin-zip.sh — builds dist/citecue.zip with git archive --prefix=citecue/. Tracked files only, honouring export-ignore, so an untracked vendor/, .env or editor backup can never be swept into a release. It refuses to build when citecue.php's Version: header, CITECUE_VERSION and readme.txt's Stable tag: disagree, and asserts the result has one correctly-named top-level directory with no development files and the three required entries present.
  • .gitattributes — a single export-ignore list of what is developer-only.
  • .github/workflows/release.yml — a vX.Y.Z tag push rebuilds the zip, fails if the tag disagrees with the plugin header, and attaches citecue.zip to the GitHub release. workflow_dispatch builds the artifact without publishing.
  • package job in ci.yml — runs the same script on every pull request, so packaging breaks in review rather than at release time.
  • README / readme.txt — install steps now point at the release asset; a Releasing section documents the build and tag flow.

The plugin has no runtime Composer dependencies (require is just php >=7.4), so the shipped archive is citecue.php, uninstall.php, includes/ and readme.txt — 15 files.

Verification

Built and unpacked locally:

  • unpacks to a single citecue/ directory
  • 15 files, no tests/, no composer.*, no CI config
  • php -l clean on every shipped file
  • the version-mismatch guard fires as expected (tested on a throwaway commit, since removed)

Notes for the reviewer

  • Nothing in the plugin's runtime behaviour changes — this is packaging and docs only.
  • git archive reads .gitattributes from the committed tree, so the build always reflects a commit, never the dirty working tree. The script warns when building HEAD with uncommitted changes.
  • Releasing is now: bump the three version strings, push a vX.Y.Z tag. The workflow rejects a tag that disagrees with the plugin header.
  • No new third-party actions; the release upload uses the built-in gh CLI with contents: write.

🤖 Generated with Claude Code

GitHub's Download ZIP produces wordpress-plugin-main.zip, which unpacks to
wordpress-plugin-main/ and carries the tests, CI config and Composer files
with it. WordPress keys a plugin by its directory name, so that archive
installs the plugin under the wrong slug.

Build the release artifact with git archive --prefix=citecue/ instead, with
development files marked export-ignore. Tracked files only, so nothing
untracked can be swept into a release; the script also refuses to build on a
version-string mismatch and asserts the archive's shape. CI runs it on every
pull request, and a tag push publishes citecue.zip to the GitHub release.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@henry-mosh
henry-mosh merged commit 3e125fb into main Aug 4, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant