Content types: flush rewrite rules on rewrite-impacting changes#78058
Conversation
Defers a soft flush_rewrite_rules() to the next init (priority 30, after register_post_type/register_taxonomy at priority 20) via an option flag, so the regenerated rules see the post-update registration state. Triggers on: publish ↔ non-publish status transitions, slug rename while published, has_archive or public toggle while published (post types), public toggle while published (taxonomies), and trash or force-delete of a previously published record. Label/supports/etc. edits do not trigger. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Flaky tests detected in 63ade6f. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/25508364216
|
| * Seeds a wp_user_taxonomy draft directly via `wp_insert_post`. | ||
| * See {@see seed_post_type_draft} for why we bypass the REST controller. | ||
| */ | ||
| private function seed_taxonomy_draft( $slug, $title, $config = array() ) { |
There was a problem hiding this comment.
Nit: these helper could be combined since they are almost identical. For example here only post_type changes.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
ntsekouras
left a comment
There was a problem hiding this comment.
Left some nits, but LGTM. Thanks!
…axonomies
`publicly_queryable` flips `register_taxonomy()`'s effective `query_var`,
which swaps the `add_rewrite_tag` query string between `{slug}=` and
`taxonomy={name}&term=`. Without this, toggling it on a published
taxonomy left stale rewrite rules in place.
Effective-value comparison (treating an absent field as equal to
`public`) avoids a redundant flush when the field is set to its
implicit default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`hierarchical` flips `register_post_type()`'s rewrite-tag regex between `(.+?)` (nested) and `([^/]+)` (flat) and swaps the query-var fallback between `pagename=` and `name=`. Without this, toggling it on a published post type left stale rules in place. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks, @ntsekouras! I've fixed a couple of minor gaps in the meantime:
|
The two `*_create_draft_does_not_schedule` tests bypass the REST controller via direct `wp_insert_post`, so they don't exercise any of the controller scheduling logic. The `*_update_draft_to_draft_does_not_schedule` tests already cover the "no flush for unpublished" guarantee through the REST path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
What?
Adds functionality to flush rewrite rules when there are affected changes to user-defined post types and taxonomies.
When a
wp_user_post_typeorwp_user_taxonomywrite changes a field that affects rewrite rules, the rules are regenerated on the next request so that archive URLs, single-post permalinks, and taxonomy term URLs match the current registration.Part of #77600.
Why?
User-defined post types and taxonomies materialize into
register_post_type()/register_taxonomy()calls oninitpriority 20. Without flushing, WordPress's cachedrewrite_rulesoption still reflects the previous registration, so:has_archivedoesn't add or remove the archive URL.publicdoesn't add or remove the single permalink rules.The same story applies to taxonomy term URLs when a taxonomy slug or
publicflag changes.How?
The flush is deferred rather than inline. Registration runs on
initpriority 20, before any REST handler executes - flushing inline would regenerate rules from the pre-update registration. Instead:create_item/update_item/delete_item) compare pre/post state and, when a rewrite-impacting field changed, set an option flag (_gutenberg_user_content_types_flush_rewrite_rules, autoload off).initpriority 30 handler - running aftergutenberg_register_user_defined_post_types()andgutenberg_register_user_defined_taxonomies()at priority 20 - picks up the flag, deletes it, and callsflush_rewrite_rules( false ).Note: we're doing a soft flush only: the standard
.htaccessblock doesn't depend on individual post type / taxonomy registrations, so a hard flush would gain nothing and write the file unnecessarily.The changes consider the following conditions necessary to trigger a rewrite rule flush:
publishboundaryhas_archivetoggled while publishedpublictoggled while publishedTesting Instructions
book, label "Books", andPublicon,Has archiveon. Save./?post_type=book(or the pretty permalink/book/) - the archive should resolve.bookpost type, rename the slug tolibrary. Save./library/- the archive should now resolve under the new slug, and/book/should 404.genre, attach to a post type, assign a term, visit/genre/<term>/, then rename the slug and confirm the new URL resolves and the old one doesn't._gutenberg_user_content_types_flush_rewrite_rulesshould remain absent inwp_optionsafter such edits.vendor/bin/phpunit --filter User_Content_Types_Rewrite_Flush_Testornpm run test:unit:php:base -- --filter User_Content_Types_Rewrite_Flush_TestTesting Instructions for Keyboard
None
Screenshots or screencast
None
Use of AI Tools
Opus 4.7