Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Wordpress Laravel Package

roots/wordpress

Composer-managed WordPress package from Roots. Installs WordPress in a clean, modern directory structure with environment-based configuration, making core updates and dependencies easy to manage in version-controlled projects.

View on GitHub
Deep Wiki
Context7

Getting Started

roots/wordpress is not a library you call — it is WordPress core itself, repackaged as a Composer package. Everything it does for you is installation and versioning: instead of wget-ing a tarball or clicking "Update" in wp-admin, core becomes a locked dependency in composer.json/composer.lock like any other package. Treat it as infrastructure, not an API.

Where to look first (in this order):

  1. The generated composer.json inside the package, not the PHP files — the only Roots-authored content is the package metadata (type: wordpress-core, the installer requirement, the extra block). The rest is verbatim WordPress.
  2. roots/bedrock's composer.json — this is the canonical usage example and the de-facto documentation. If you are not on Bedrock, copy its extra.wordpress-install-dir and config.allow-plugins blocks.
  3. roots/wordpress-core-installer — the Composer plugin that actually decides where core lands on disk. When installation "does nothing", this is almost always the culprit.
  4. Roots docs (roots.io/bedrock) — the package README is one paragraph; the real guidance lives in the Bedrock docs and Trellis deploy docs.

Minimal steps (Bedrock-style project):

composer require roots/wordpress:^6.7

Then in the root composer.json:

{
  "extra": {
    "wordpress-install-dir": "web/wp"
  },
  "config": {
    "allow-plugins": {
      "composer/installers": true,
      "roots/wordpress-core-installer": true
    }
  }
}
composer install
ls web/wp/wp-load.php   # core is now on disk at the path you declared

First use case: a fresh site. composer create-project roots/bedrock my-site gives you core at web/wp, your writable content at web/app (WP_CONTENT_DIR), and wp-config.php kept outside the webroot in config/application.php. That separation — immutable core, versioned config, git-tracked content — is the entire value proposition. Once you've done one composer update roots/wordpress and watched git diff show only composer.lock, you understand the package.

Do not expect this package to scaffold a site, create wp-config.php, install a database, or register autoload classes. It ships files. Bedrock, Trellis, and Sage supply everything else.

Implementation Patterns

1. The core upgrade loop (the 90% use case)

composer outdated roots/wordpress        # what's available
composer update roots/wordpress -W       # -W: allow its installer deps to move too
git diff composer.lock                   # review: one version line should change

Then: run the test suite / smoke test on staging → deploy the artifact → verify integrity:

wp core version
wp core verify-checksums     # confirms the on-disk files match the official release

Because core is a single locked package, a security release is a one-line change you can ship in minutes:

composer require roots/wordpress:6.7.2 --no-update
composer update roots/wordpress -W

That --no-update two-step is worth internalising: it lets you pin the exact patched version and keep the lockfile diff reviewable when other packages also depend on core constraints.

2. Constraint strategy

Constraint Behaviour Use when
^6.7 auto-minor + patch on composer update most sites; matches WordPress's own minor-auto-update policy
6.7.* patches only conservative client sites
6.7.2 exact pin regulated/audited environments

Pair this with Renovate or Dependabot pointed at composer.json. A bot PR that bumps roots/wordpress is the cleanest possible core-update signal — one file changed, CI does the rest. Set the bot to group roots/* so a core bump doesn't arrive shredded across five PRs.

3. Full vs. no-content variant

Two Packagist packages exist off the same release tags:

  • roots/wordpress — core plus the bundled wp-content (default themes, Akismet, hello.php, index.php).
  • roots/wordpress-no-content — identical minus wp-content. Recent Bedrock releases scaffold with this one, because Bedrock already owns web/app as the content directory and a second wp-content is dead weight you then have to gitignore.

To switch on an existing project, remove before you require — they are mutually exclusive and swapping them in one command will confuse the solver:

composer remove roots/wordpress
composer require roots/wordpress-no-content:^6.7

If you keep the full variant with a custom content dir, expect web/wp/wp-content to exist and be ignored by WordPress entirely; delete it in a deploy step to avoid confusion, or just migrate to -no-content.

4. Deployment and CI

The standard Roots pattern is a build artifact, not a server-side install:

# CI
composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction
# then rsync/ship the whole web/ tree (core included) to the target

Consequences to wire up deliberately:

  • web/wp/ is gitignored and built, never committed.
  • Cache ~/.composer/cache in CI — core dists are ~20 MB per version and you'll fetch a fresh one on every build otherwise.
  • If you do run composer install on the server (Trellis does this in its deploy hooks), you need Composer present and --no-dev set, and you must never run it concurrently with traffic in a way that leaves web/wp half-written. Artifact deploys sidestep this — prefer them.

5. Working with WP-CLI

Core at a known path means WP-CLI works normally for diagnostics (wp core version, wp core verify-checksums, wp plugin list), and fails loudly for mutation: wp core update will try to write into a directory that your deploy will overwrite. Turn it off explicitly:

// config/application.php (Bedrock) — or wp-config.php
define('DISALLOW_FILE_MODS', true);
define('AUTOMATIC_UPDATER_DISABLED', true);

DISALLOW_FILE_MODS also blocks plugin/theme installs from wp-admin, which is correct — those go through composer require wpackagist-plugin/... with composer/installers routing them to web/app/plugins.

6. Local development

composer install in a fresh clone produces a working web/wp in seconds. That's the whole local bootstrap — no Docker image layer with a baked-in WordPress, no "download the zip and unzip into the right folder" README step. Whatever your local stack (Lando, DDEV, wp server, Trellis VM), it only needs to point at web/, and the first-run experience is deterministic across every developer's machine.

7. Multi-site / portfolio repos

For agencies running many sites, the pattern is one Bedrock root per site, all requiring roots/wordpress with the same constraint. Bump the constraint across the portfolio in a scripted sweep, run each site's CI, deploy independently. The lockfile is the per-site audit record of exactly which core patch is live — invaluable when a CVE lands and you need to answer "who is still on 6.6.x?" with grep.

Gotchas and Tips

allow-plugins will bite you first. Composer 2.2+ refuses to run plugins non-interactively. If web/wp never appears after composer install, check for a "roots/wordpress-core-installer ... blocked by allow-plugins" message. Both composer/installers and roots/wordpress-core-installer must be allowed in the root composer.json, and CI needs it too — the flag is not inherited from your laptop's global config.

--no-plugins silently breaks placement. The install path is not magic; it's the wordpress-core installer plugin honouring extra.wordpress-install-dir. composer install --no-plugins or COMPOSER_NO_PLUGINS=1 downloads the package and drops it in vendor/roots/wordpress instead. Same for --no-scripts in some setups. If you harden CI, whitelist these two plugins rather than disabling plugins wholesale.

Never edit web/wp. It is regenerated wholesale on every update; there is no merge, no three-way diff. Anything you need to change lives in mu-plugins (web/app/mu-plugins, autoloaded by Bedrock), a normal plugin, or a filter in config/application.php. If you find yourself patching core, you've found a missing mu-plugin.

wordpress-install-dir is relative and unforgiving. It's resolved from the project root (where composer.json lives), not from vendor/ and not from the webroot. A typo gives you a site that 404s at /wp-admin with core sitting happily in the wrong folder — and composer install reports success. After the first install, ls the path before you debug anything else.

Composer's audit is blind to WordPress advisories. composer audit and roave/security-advisories track Packagist's advisory database, which does not model WordPress core CVEs the way it models PHP library CVEs. Do not treat a clean composer audit as "core is patched." Use WPScan, wp core verify-checksums against the current release, and a calendar reminder tied to WordPress's security-release cadence (patch releases land roughly monthly, plus out-of-band criticals).

Release-candidate tags need a stability flag. Betas and RCs are published as tags (6.8-RC1-style). Requiring one without minimum-stability: dev / an explicit stability suffix in the version constraint gets you a "could not find a matching version" error that reads like the tag doesn't exist. It exists; Composer is filtering it.

Bundled defaults disappear with -no-content. If you migrate to the no-content variant and your theme does get_template_directory() fallbacks, or a plugin assumes twentytwentyfour is present, you'll get fatals on fresh installs. Ship an explicit default theme in web/app/themes, or accept that "no active theme" is a state your site can be in.

composer update roots/wordpress -W can move more than you expect. The -W is usually necessary (the installer plugin's constraint can otherwise block the bump), but it expands the transaction. Always read the composer.lock diff; if three unrelated packages moved, split the commit so a rollback of core doesn't drag them along.

This repo is a mirror — don't send it pull requests. Core bugs belong upstream at WordPress/WordPress; packaging/installer bugs belong in roots/wordpress-core-installer or roots/bedrock. Issues filed against this repository for PHP behaviour in wp-includes will be closed. Knowing this saves you a wasted afternoon writing a patch that gets regenerated away.

Switching variants mid-project leaves orphans. composer remove then require the other package, but also delete the stale web/wp/wp-content (or the empty vendor remnant) by hand — the installer won't clean up files from the previous package version, and a leftover wp-content/index.php will quietly satisfy WP_CONTENT_DIR checks while serving nothing.

Debugging checklist for "the site won't boot after deploy":

  1. Does web/wp/wp-load.php exist on the target? (composer install skipped or plugin blocked.)
  2. Does wp core version match the lockfile? (Stale artifact from cache.)
  3. Is WP_CONTENT_DIR still absolute and valid? (Path assumption broke when the release directory changed.)
  4. Is DISALLOW_FILE_MODS set, and did someone try to update anyway? (wp core verify-checksums will show modified files.)

Extension points that actually exist: the variant package you choose, extra.wordpress-install-dir, extra.installer-paths from composer/installers (for plugins/themes alongside core), and the allow-plugins allowlist. That's the whole surface. Everything else you want to change about WordPress is a WordPress change — a filter, a mu-plugin, or a config constant — not a package concern.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core