roots/wordpress-packager: The bot that turns WordPress core into clean Composer snapshots

A deep dive into the orphan-branch trick, the release watcher, and the packaging pipeline that makes legacy WordPress releases behave like modern dependencies.

8 min read • View on GitHub • More from roots

A print-shop style conveyor turns a bulky WordPress archive into neat package cards. The image shows the idea of stripping away release history and publishing clean, versioned snapshots for Composer. It explains the repo as a packaging machine rather than a traditional app.
WordPress releases go in as archives and come out as Composer-ready snapshots.
Key Takeaways

WordPress was never meant to be installed like a normal PHP package. roots/wordpress-packager exists to erase that mismatch without pretending the mismatch never existed.

The repo is not a product in the usual sense. It is a release machine, a metadata layer, and a Git transformer wrapped around one goal: make each WordPress release show up as a clean Composer dependency.

Why WordPress needed a packaging layer at all

Composer expects packages to have clear versions, predictable metadata, and a manageable Git history. WordPress ships as a monolithic upstream release stream with its own rules, its own file layout, and a long tail of baggage that does not map neatly onto dependency management.

WorkflowPackaging methodRelease freshnessHistory sizeComposer compatibilityCustom buildsMaintenance burden
roots/wordpress-packagerAutomated snapshot builds from WordPress.org releasesHigh, driven by release detectionMinimal, because each version starts freshNativeYes, including full and no-content variantsLow once the pipeline is stable
johnpbloch/wordpressPrebuilt Composer package for WordPress coreHighModerateNativeLess flexibleModerate
Manual WordPress installDownload and unpack the upstream archiveDepends on the operatorNone in Git, but no package history eitherNoManual onlyHigh
Git submodule workflowTrack WordPress as nested source dependencyVaries by update disciplineHeavy and awkwardWeak fitPossible but clumsyHigh

That is the real value here. The repo does not just redistribute WordPress. It translates WordPress into the grammar that modern PHP tooling already understands.

The trick: every release becomes a fresh Git snapshot

The center of the repo is a simple but powerful move: git checkout --orphan. Each WordPress version becomes a brand-new branch with no inherited history, then gets committed, tagged, and pushed as if it had always lived there.

The packaging pipeline is a transformation chain, not a straight download script. It turns upstream release data into a tagged Git snapshot that Composer can consume.

A close-up of a branch tree where one new branch starts from a blank origin point, then receives a commit and a tag. The image explains how orphan branches let the packager publish each release without dragging along prior history. It turns Git into a snapshot factory.
Each release starts from zero, which keeps the package repo lean and the tags easy to trust.

That orphan-branch pattern matters because it cuts the past away on purpose. The repository keeps the release identity, but not the release lineage.

git checkout --orphan 6.6.1
git add .
git commit -m "WordPress 6.6.1"
git tag 6.6.1
git push origin 6.6.1 --tags

The result is a package repo that behaves like a catalog, not an archive. There is no need to ship 20 years of history just to install the newest release.

Inside the release watcher

The bot’s job starts with watching WordPress.org for new releases. A GitHub Actions workflow checks on a schedule, compares what it finds against existing tags, and kicks off packaging only when a version is missing.

That is the quiet genius of the design. It is not a giant CI system. It is a small delivery robot that keeps asking one question: has WordPress published something new that the package repo has not captured yet?

This package helps generate Composer packages for any WordPress release.

The workflow stays narrow on purpose. Fetch release data, compare versions, build the package, publish the tag, repeat.

How the package metadata stays version-aware

The repo is doing more than moving ZIP contents around. The package model injects metadata, compatibility rules, and integrity data so the final Composer package is accurate for the exact WordPress release it represents.

Metadata concernHow the packager handles itWhy it matters
Minimum PHP versionMaps WordPress versions to their required PHP floorPrevents installing a release on the wrong runtime
Suggested extensionsAdds version-specific extension suggestions during prepareData()Keeps Composer metadata aligned with real hosting needs
ChecksumPulls SHA1 from WordPress.orgGives the generated package a trust signal tied to the upstream source
Package identityExtends Composer package modeling directlyLets the repo express WordPress as a first-class dependency object

This is what separates a clever mirror from a serious packaging system. The repo encodes compatibility, not just files.

What Roots is really building for

`roots/wordpress-packager` sits inside a larger Composer-first WordPress stack. It helps produce packages such as roots/wordpress, plus specialized variants like full and no-content builds for different project constraints.

That gives Roots a sharper position than a generic WordPress mirror. They are not only tracking core. They are shaping how WordPress enters modern application workflows.

ToolScopeWhat it solvesWhere it fits
roots/wordpress-packagerWordPress core packagingTurns releases into clean Composer snapshotsInfrastructure layer for Roots packages
johnpbloch/wordpressWordPress core packageProvides a ready-to-require core distributionDirect alternative for Composer-based installs
WPackagistPlugins and themesMakes the WordPress directory Composer-friendlyComplements core packaging, not a substitute for it
WP PackagesPlugins and themesModern metadata-backed package repositoryWorks alongside core packages in Composer workflows

The difference is not just technical. It is editorial. Roots is deciding what WordPress should look like when it enters a dependency graph.

Why this repo is a model PHP utility

The codebase reads like infrastructure that expects to live a long time. PHP 8.2+, strict typing, Symfony Console, programmatic Git control, tests with fixtures, and PHPStan at maximum strictness all point in the same direction: small surface area, high confidence.

That matters because utility code only wins when it stays boring in production. This repo does the opposite of flashy. It narrows the problem until the automation becomes dependable.

It is a good example of PHP done with discipline. The repo does one awkward thing extremely well, then gets out of the way.