Managing Premium WordPress Plugins with Composer, Bedrock, and Private Repositories
Every serious WordPress site ends up needing premium plugins. ACF Pro for custom fields on complex editorial sites. Gravity Forms for conditional-logic forms. WooCommerce Subscriptions for recurring billing. Yoast Premium, Rank Math Pro, WP Rocket, WP All Import Pro — the list goes on. All of these are paid products that are not on the WordPress.org plugin directory, which means they’re not in the default Composer repositories and you can’t just composer require wp-plugin/acf-pro.
If you’re using Bedrock, this is one of the first real obstacles you’ll hit. Premium plugins are exactly where “just zip it and upload to wp-admin” is tempting, and exactly where that approach quietly breaks your dependency discipline. This guide covers every practical way to install premium WordPress plugins via Composer — vendor-provided repositories, paid aggregators, private Satis instances, and manual package definitions — along with how to store license keys securely, handle plugin updates across multiple sites, and survive the occasional vendor endpoint change.
Why Not Just Upload the Zip?
The temptation with premium plugins is to download the zip, upload it to wp-admin, and move on. That works — once — and immediately breaks Bedrock’s core invariant: every piece of third-party code is declared in composer.json.
The specific failure modes:
- Your next deploy wipes the plugin. Bedrock’s
.gitignoreexcludesweb/app/plugins/, so plugins installed via the admin aren’t in Git. When CI runscomposer installon the server, it creates a newplugins/directory with only the plugins incomposer.json. - Nobody else on the team has the plugin. A new developer who clones the repo and runs
composer installgets a broken site, because the plugin only exists on the server you uploaded it to. - There’s no version lock. You installed ACF Pro 6.2.8 on production, but the staging site has whatever zip someone uploaded six months ago. Debugging becomes impossible.
- Updates become manual. Every plugin needs to be re-downloaded, re-zipped, and re-uploaded by hand on every site. Multiply by 20 sites and you’re spending a day a month on plugin updates.
The fix is to route premium plugins through Composer like everything else. The tools exist — you just have to learn which one fits each plugin.
Four Ways to Install Premium Plugins with Composer
In rough order of preference:
- 1. Vendor-provided Composer repository — if the plugin vendor runs their own Composer endpoint.
- 2. Paid aggregator — services like Deliciousbrains’ Composer repository.
- 3. Private Satis repository — your own Composer repository for purchased plugins.
- 4. Raw zip URL via package definition — last resort for plugins with no other option.
Option 1 — Vendor-Provided Composer Repositories
The cleanest option, when available. A growing number of premium plugin vendors run their own Composer endpoints that you point at with your license key. Examples as of April 2026:
- ACF Pro — connect.advancedcustomfields.com
- Gravity Forms —
gravity.composer.rocketgenius.com - WP Rocket —
wp-rocket.meComposer endpoint - Yoast Premium — vendor-provided
- WooCommerce Subscriptions and most Automattic premium extensions — via Packagist Commercial or direct vendor repo
Adding a Vendor Repository
In composer.json:
"repositories": [ { "type": "composer", "url": "https://connect.advancedcustomfields.com" }]
Then install:
composer require wpengine/advanced-custom-fields-pro
License Keys in auth.json
Your license key goes in auth.json at the project root, never in composer.json:
{ "http-basic": { "connect.advancedcustomfields.com": { "username": "YOUR_ACF_LICENSE_KEY", "password": "example.com" } }}
Critical:
- Add
auth.jsonto.gitignoreimmediately. Leaked license keys are a real and common problem. - Distribute it securely to your team — 1Password shared vaults, a Vault server, or encrypted config management (Trellis has Ansible Vault for this).
- In CI, store the
auth.jsoncontents as an encrypted secret and write it to disk beforecomposer install.
Option 2 — Paid Aggregators
If you have lots of premium plugins across multiple sites, a paid aggregator can consolidate licensing and Composer access. The two big names:
- Deliciousbrains Composer repository — subscription service that hosts a curated set of premium plugins (the Deliciousbrains team maintains the packages). Good for teams who want a single bill and a single Composer endpoint for many plugins.
- WPackagist Premium and other community-run mirrors — variable coverage, worth checking for specific plugins.
Configure the same way — add the repository URL, put credentials in auth.json, composer require each plugin.
Aggregators are convenient but come with tradeoffs: you’re paying a markup on the underlying licenses, and the aggregator can drop a plugin from their catalog if the vendor changes terms. For a small number of premium plugins, direct vendor repositories are usually better.
Option 3 — Private Satis Repository
When you’ve purchased a plugin directly from a vendor who doesn’t provide a Composer endpoint, the cleanest solution is to host your own Composer repository with Satis.
Satis is a static Composer repository generator. You give it a satis.json listing the packages you want to host and where to find them (usually Git repositories or direct zip URLs), run satis build, and it generates a static packages.json file that Composer can read.
A typical agency workflow:
- Create a private GitHub repository for each premium plugin you’ve purchased. Push the plugin’s source code (with your license embedded via environment variables, not hardcoded).
- Create a Satis config that lists all these repositories.
- Host the generated Satis output somewhere — GitHub Pages, an S3 bucket, a dedicated server behind HTTP basic auth.
- Point your projects at the Satis URL, add credentials to
auth.json, andcomposer requireas normal.
Downsides: you maintain the repository. Every plugin update means downloading the new version from the vendor, pushing to your Git, and rebuilding Satis. For one or two plugins it’s overhead; for ten it’s a real weekly task. Automation (a cron job that checks for updates, downloads new versions, and commits) can help.
Option 4 — Raw Zip URLs via Package Definition
The fallback for plugins with no Composer story at all. Add a package-type repository to composer.json:
{ "type": "package", "package": { "name": "premium-vendor/premium-plugin", "version": "3.2.1", "type": "wordpress-plugin", "dist": { "type": "zip", "url": "https://vendor.com/premium-plugin-3.2.1.zip?license=XYZ" }, "require": { "composer/installers": "^2" } }}
This works, but:
- The zip URL often contains your license key — don’t commit it to Git. Use environment variables and substitute at install time.
- You have to bump the version string manually every time you want to update.
- If the vendor changes their download URL scheme, your pipeline breaks.
Use this option when you have no choice. Migrate to Satis or a vendor repository when one becomes available.
Storing License Keys Securely
License keys are secrets. Treat them like database passwords:
auth.jsonin.gitignore— always. No exceptions.- Shared in a password manager — 1Password, Bitwarden, or a team vault.
- In CI, injected as a secret environment variable and written to
auth.jsonat install time. - On servers managed by Trellis, stored in Ansible Vault alongside database credentials.
- Rotated when a team member leaves. If they had access to the vault, rotate.
Trellis 1.30+ added Composer custom-header authentication, which is useful for vendors that authenticate by HTTP header rather than HTTP Basic Auth. Check the Trellis changelog for the exact syntax.
Updating Premium Plugins
Updates work the same as for free plugins:
composer update wpengine/advanced-custom-fields-procomposer update --no-dev --optimize-autoloader
Commit the updated composer.lock, test on staging, deploy to production. For teams running multiple sites, Renovate or Dependabot can automate the PR creation — both support private Composer repositories with authentication.
Since Bedrock 1.30, pairing Composer updates with WP Sec Adv gives you automated security advisories on every plugin — premium plugins included, as long as they’re in the Wordfence Intelligence feed.
Common Pitfalls
The Vendor Changes Endpoints
Vendor Composer endpoints occasionally change URLs or authentication methods. Monitor the vendor’s Composer documentation and follow their blog. When it happens, the fix is a composer.json and possibly auth.json update.
CI Doesn’t Have auth.json
If your CI fails with “could not authenticate against connect.advancedcustomfields.com”, you forgot to inject the secret. Every CI pipeline needs a step that writes auth.json from an encrypted environment variable before composer install.
License Expired
When a license expires, composer install fails silently or with a 401. Set calendar reminders for license renewals, or (for teams with many plugins) centralize license tracking in a spreadsheet or dedicated tool.
Plugin Supports Composer But Not Its Dependencies
Occasionally a premium plugin ships vendored dependencies that conflict with other plugins’ vendored dependencies. The Roots blog post on namespace prefixing with PHP-Scoper covers the mitigation. Short answer: plugin vendors should scope their dependencies; when they don’t, you can’t do much except report the issue.
Multi-Site License Terms
Most premium plugins license per-site or per-seat, not per-developer-using-Composer. Having a Composer-installable plugin does not make it legal to install on unlimited sites. Check vendor terms; some vendors have agency or unlimited licenses explicitly for Composer-based workflows.
A Real-World Example: Managing 20 Sites with Shared Premium Plugins
If your agency runs 20+ sites that share premium plugins, here’s a concrete workflow that scales:
- Central Satis repository for any plugin without a vendor Composer endpoint. Automated update check job that downloads new plugin versions weekly.
- Vendor Composer endpoints for ACF Pro, Gravity Forms, WP Rocket, Yoast Premium.
- Central
auth.jsontemplate stored in the agency password manager, distributed to developers on onboarding. - Ansible Vault for production server Composer credentials, distributed via Trellis.
- Renovate bot configured across all site repos, opening PRs for plugin updates and batching them weekly.
- License spreadsheet tracking every license key, renewal date, and which sites use it.
Total ongoing maintenance: about 2 hours per week for the lead developer. Before this workflow, we spent that many hours per site per month.
Frequently Asked Questions
Does every premium plugin support Composer?
No. A growing majority do via vendor-provided repositories, but some are still zip-file-only. For those, Satis or the raw zip URL approach is your fallback.
Can I commit auth.json if my repository is private?
Strongly recommended not to. Private repositories leak — through clone-to-public mistakes, compromised developer laptops, or acquisition events. Keep secrets out of Git regardless of repository visibility.
What if a plugin vendor’s license terms forbid Composer distribution?
Check the license. Some vendors explicitly forbid rehosting (even on a private Satis) because their update and anti-piracy mechanisms depend on their own distribution servers. Respect those terms — use the vendor’s own repository if they provide one, or the raw zip URL approach with URL rewriting on install.
How do I handle a premium plugin that’s bundled with a theme purchase?
Common with premium WordPress themes that bundle Revolution Slider or similar. Either use the theme vendor’s Composer repository if they have one, or treat the bundled plugin as a separate Satis entry if the theme license permits.
Can I use Dependabot or Renovate with premium plugin repositories?
Yes. Both support Composer and authentication. Configure the bot with the same credentials you use in CI, and it will open PRs for plugin updates automatically.
Premium Plugins the Right Way
Getting premium plugins into Composer is the single highest-leverage change you can make for maintaining a professional Bedrock workflow. Once every plugin is declared, versioned, and reproducibly installed, deploys become predictable, rollbacks are trivial, and onboarding a new developer drops from “three hours of zip uploads” to git clone && composer install.
At Emnes, all 18 of our production sites run with every plugin Composer-managed, across a mix of vendor Composer endpoints, Satis, and aggregators. If you want help setting up the same workflow for your agency, get in touch.
Related reading: the Bedrock complete guide, migrating to Bedrock without downtime, and our upcoming post on the full Roots stack.