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

Rewrite Command Laravel Package

wp-cli/rewrite-command

WP-CLI package for managing WordPress rewrite rules and permalinks from the command line. Flush rules, inspect the current rewrite list, and update permalink structure without leaving your terminal, making migrations and debugging faster.

Deep Wiki
Context7

Getting Started

wp-cli/rewrite-command ships three subcommands, and that is the whole surface area — learn them once and you're done:

Command What it actually does
wp rewrite list Prints the compiled rule array (match → query), optionally filtered
wp rewrite flush Deletes the rewrite_rules option so WP regenerates it (soft), or rewrites .htaccess (hard)
wp rewrite structure Sets permalink_structure (plus category_base / tag_base) and flushes

Verify it's wired up. It's bundled in wp-cli/wp-cli-bundle; if you're on a hand-rolled install:

wp package install wp-cli/rewrite-command:@stable
wp help rewrite list     # canonical docs for the exact version on the box
wp rewrite structure     # no args = prints current structure, non-destructive

The first use case you'll hit. You register a custom post type or a taxonomy with rewrite => ['slug' => 'guides'], deploy, and every /guides/foo/ URL 404s because WordPress cached the old rule set in the rewrite_rules option.

wp rewrite flush
curl -sI https://example.test/guides/hello/ | head -1

Soft flush is enough here — it just deletes the option, and the next front-end request rebuilds it. Reach for --hard only when you also need the Apache .htaccess block rewritten.

Where to look first when something's wrong: wp rewrite list --match=<path> tells you whether any rule claims the URL, which splits the problem cleanly into "WP has no rule" (registration/flush problem) versus "WP has a rule but the server never routed to index.php" (web-server config problem, which this package cannot fix).

Implementation Patterns

Deploy scripts: soft flush always, hard flush never (by default).

wp rewrite flush --quiet          # every deploy, idempotent, cheap

Put this after wp plugin activate / theme switch, not before — rules are generated from whatever is registered at the moment of the next request, so ordering only matters for --hard. On containerized or read-only-filesystem deploys, --hard will fail on .htaccess permissions; skip it and let infrastructure own the vhost.

Triage a 404 in two commands.

wp rewrite list --match=guides/hello
# match: guides/([^/]+)/?$   query: post_type=guides&name=$matches[1]   source: plugin

If nothing prints, the CPT/taxonomy isn't registered on the CLI context (see gotchas), or you never flushed. If the right rule prints, stop debugging WordPress and go look at try_files / mod_rewrite.

Narrow the haystack with --source. On a plugin-heavy site the list runs to hundreds of rows; --source=plugin --fields=match,query is usually the interesting slice, and --source=core is a good sanity baseline when you suspect a plugin is stomping a core rule.

Script against it — always ask for JSON.

wp rewrite list --format=json | jq -r '.[] | select(.query | test("post_type=product")) | .match'

--fields=match,query --format=csv is the low-friction variant for diffing rule sets between two environments.

Codify permalink changes instead of clicking in wp-admin. This is the pattern that survives environment promotion, because permalink_structure is just an option row:

wp rewrite structure '/%postname%/' --category-base=blog --tag-base=topic
wp rewrite structure '/%year%/%monthnum%/%postname%/' --hard   # Apache only

Leading/trailing slashes are normalized for you, so /%postname% and /%postname%/ are equivalent. Combine with wp search-replace when you're migrating a site whose structure changes at the same time.

Fan out across multisite.

wp site list --field=url | xargs -I{} wp rewrite flush --url={}

rewrite_rules is a per-site option, so a network-wide change needs a per-site flush. --hard writes the shared network .htaccess and only needs to run once.

Custom rules: register in a mu-plugin, flush from CLI. Anything added with add_rewrite_rule() / add_permastruct() / the rewrite_rules_array filter is only visible to WP-CLI if it loads on the CLI bootstrap — mu-plugins and wp plugin-activated plugins do; a functions.php snippet in an inactive theme does not. Then:

wp rewrite flush && wp cache flush

Gotchas and Tips

  • Soft vs hard is the classic footgun. wp rewrite flush does not touch .htaccess. On Apache with pretty permalinks, if your rule set changed but the file didn't, --hard is the missing piece — and it will bail with a "hard flush" error when .htaccess isn't writable by the CLI user. Check ownership before assuming a bug.
  • --hard is meaningless on nginx. Nginx has no per-site rewrite file; the package will still attempt the write and can fail or silently do nothing useful. Keep the server block's try_files $uri $uri/ /index.php?$args; in your provisioning repo and treat permalink flushing as pure WordPress state.
  • wp rewrite list writes to the database. It calls WP_Rewrite::wp_rewrite_rules(), which populates the rewrite_rules option as a side effect. So it's not a read-only inspection — and it means "I ran list and the rules look right" doesn't prove your deploy's flush worked.
  • --match takes a site-relative path. Strip the scheme and domain (--match=guides/hello, not the full URL). It's a filter over rule patterns, not a router simulation — a match here doesn't guarantee the query vars resolve to published content, so confirm with wp post list --name=hello.
  • --source is coarse. Expect buckets like core, theme, plugin, other, not "woocommerce". Use --match plus the query string to identify the true owner, then grep your codebase for the query var.
  • Rule order matters and you can't reorder from the CLI. wp rewrite list prints in match order (first hit wins). If a catch-all (.?.+?)/?$ page rule is swallowing your CPT URLs, the fix is add_rewrite_rule( ..., 'top' ) or a distinct slug — the command only observes.
  • Empty permalink structure ⇒ no rules. On plain permalinks wp rewrite list has nothing to show. wp rewrite structure first, then list. Similarly, after wp rewrite flush the option is genuinely absent until the next front-end request rebuilds it — don't treat "empty list right after flush" as breakage.
  • Page cache beats rewrite cache. Persistent object cache and full-page caches will happily serve the pre-flush 404s. wp cache flush plus a CDN purge is part of the ritual, not an optional extra.
  • Wrong context, missing rules. If wp rewrite list is missing rules you know exist, the plugin/theme defining them probably isn't loading under WP-CLI (wp plugin list --status=active to confirm, and remember --url= selects the site on multisite). This is the single most common false alarm.
  • Extension points live in WordPress, not here. There's no hook to add a subcommand worth the effort; do your customization with add_rewrite_rule(), add_permastruct(), generate_rewrite_rules, and rewrite_rules_array, then let the CLI drive the flush. Keep the registration idempotent so repeated wp rewrite flush calls are safe.
  • Pin your CI usage. --quiet on flush, explicit --format=json on list, and check exit codes — rewrite structure fails loudly on an empty permastruct, which is exactly what you want in a deploy gate.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource