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

Wp Caper Laravel Package

alleyinteractive/wp-caper

WP Caper is a WordPress library from Alley Interactive for defining and managing custom capabilities and roles in code. It offers a clean API for registering capabilities and assigning them to roles, keeping permission logic consistent, version-controlled, and easier to maintain across environments.

View on GitHub
Deep Wiki
Context7

Getting Started

WP Caper is Alley Interactive's library for defining WordPress roles and capabilities in code instead of clicking them into the database via a plugin UI. In a Laravel shop you typically meet it in a Bedrock-style repo where WordPress lives alongside the Laravel app as a Composer dependency — the value is that roles/caps become reviewable, diffable, deployable artifacts rather than untracked rows in the wp_user_roles option.

Minimal steps:

  1. composer require alleyinteractive/wp-caper in the WordPress side of the repo (not the Laravel app, unless you are running WP inside Laravel).
  2. Bootstrap it from an mu-plugin, not a theme — themes get swapped, mu-plugins don't:
    // web/app/mu-plugins/roles.php
    require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
    
    Mu-plugins are not autoloaded by Composer, so the explicit require is mandatory and is the single most common reason "the package does nothing."
  3. Write your first definition file mapping roles → capabilities, and apply it with the package's WP-CLI command rather than on init. Run the CLI command with a dry-run/no-op flag first if one is exposed, and diff the output against the live site before committing.

Where to look first: the CHANGELOG entry for 3.0.0 (#300) and the README's upgrade notes. This is a major version bump with a link-only release note, which by convention means breaking changes — class names, constructor signatures, and CLI command names are all fair game. Grep your codebase for the bootstrap call and every CLI invocation before you bump the constraint. Do not assume the 2.x API surface survived.

First use case: take the pile of add_role() / add_cap() calls scattered across functions.php and a permissions plugin export, collapse them into one declarative definition, and apply it through your deploy pipeline. That alone usually justifies adoption.

Implementation Patterns

Definition-as-code, applied by CLI, not by request. The tempting pattern is to hook definitions onto init so they "always apply." Resist it: that turns every page load into a potential DB write and makes production state depend on traffic. Instead treat cap application like a migration — run it in the deploy script after composer install and before the new code takes traffic:

deploy: composer install --no-dev → wp caper apply → reload php-fpm

Idempotency and reconciliation. The package's model is declarative; your job is to decide the reconciliation policy. Adding caps is safe and repeatable. Removing them requires an explicit apply that prunes — confirm whether v3 prunes by default or only adds. Assume "add-only" until proven otherwise; silent non-removal is the bug that bites six months later when a deprecated manage_secrets cap is still granted to every editor.

One file per role, keyed by slug. Long single arrays rot. Keep a directory of roles/editor.php, roles/shop_manager.php, plus a capabilities.php of shared custom caps with a prefix (acme_manage_orders) to avoid colliding with core or third-party plugins.

Laravel as the source of truth for app permissions. The clean split is: Laravel owns application-level authorization (Gates/Policies backed by an enum of slugs), WordPress owns the enforcement surface. Share the slugs via a config file or generated enum, and have Laravel publish cap changes to WP through a queued job or a deploy hook — never call WP functions from Laravel directly. If the Laravel app needs to read current caps, go through WP-CLI JSON output or a small REST endpoint rather than reaching into the options table.

Multi-site. Definitions are per-site, so loop the sites explicitly in the deploy command. Do not assume a network-wide apply exists or is what you want; a per-site loop is easier to reason about and to re-run partially.

Testing. Assert the resulting capability state, not the definition array. A test that checks "editor has edit_others_posts" against a booted WP test install catches the reconciliation bugs that unit-testing your array never will. Also test with a real non-admin user — see the super-admin gotcha below.

Gotchas and Tips

  • The 3.0 upgrade is the whole story here. The release note is a single link to CHANGELOG.md#300. That is a deliberate signal: read it before touching composer.json. Check PHP minimum version, namespace/class renames, whether the bootstrap became a singleton or a plain instance, and whether CLI commands were renamed or regrouped. Pin ^2.0 until you have read it.
  • Capabilities live in the database, not in your code. Deleting a definition or reverting a deploy does not remove the capability — it persists in the wp_user_roles option forever. Always ship a rollback path, and keep a "reset to definitions" command for local/staging.
  • Lockout risk on administrator. Removing a cap from administrator can lock every admin out of the very screen you'd use to fix it. Rehearse on staging with a disposable admin account, and keep a WP-CLI escape hatch (wp cap add administrator ...) documented in the runbook.
  • Super admins bypass capability checks on multisite. current_user_can() returns true for a super admin regardless of role caps. Your manual testing on a super admin will pass while real editors are broken. Always verify with a plain subscriber/editor account.
  • Persistent object cache serves stale roles. After applying caps, the user_roles option cache may still be warm. Flush the object cache as part of the deploy step, or you will "verify" a change that hasn't landed.
  • Mu-plugin autoload ordering. If the package loads after code that calls it, you get a class-not-found fatal on the whole site. Guard the bootstrap with class_exists() and fail soft in non-production.
  • Filters are runtime-only. If you extend definitions via filters, remember the CLI apply runs in its own process — filters must be registered in a context the CLI loads (mu-plugin, not a controller or an is_admin() branch).
  • Never define roles in a theme. Theme switches silently orphan capability grants. Mu-plugin or a dedicated plugin, always.
  • Custom caps need map_meta_cap. A raw custom cap is all-or-nothing; if you need "can edit this order," you're in map_meta_cap territory and Caper won't do that part for you.
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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel