WordPress.org

Make WordPress Core

Opened 20 months ago

Closed 19 months ago

Last modified 17 months ago

#21824 closed defect (bug) (duplicate)

Custom Post Type Permalink Rules Are Not Updated Correctly When Saving Changes

Reported by: MarcusPope Owned by:
Milestone: Priority: normal
Severity: normal Version:
Component: Rewrite Rules Keywords:
Focuses: Cc:

Description

When changing permalink structures using Common Settings or Custom Structure, clicking Save Changes will only update core system rewrite rules. Custom Post Type rewrite rules are re-used from the previous setting. If you click save changes twice the correct rewrite rules are updated and used.

If you only save once, canonical.php will step in and issue a 301 redirect to the appropriate post. But if you save twice it doesn't have to do any work at all. This is actually causing an infinite 301 redirect with one of my plugins. I have a fix to prevent the recursion, but it still means it cannot find my custom post type content until I update the permalinks settings again. This behavior occurs whether you register post types in "init" or in a theme's functions.php or in a plugin.

I've seen multiple core devs and users say off-handedly that you should save the page once or twice as seen in these links:

http://wordpress.org/support/topic/permalinks-go-404-on-custom-post-types?replies=7#post-2301522

http://wordpress.org/support/topic/plugin-custom-post-type-permalinks-all-custom-post-type-pages-and-categories-result-in-404s?replies=12#post-2841550

http://wordpress.stackexchange.com/a/40591/10127

http://wordpress.org/support/topic/custom-post-type-permalink-rewrite?replies=10

The reason this behavior occurs is because flush_rewrite_rules() doesn't actually flush custom post type rewrite rules stored in WP_Rewrite::$extra_permastructs. WP_Rewrite::init() will only reset internal core posts/pages/category/etc structures. And $extra_permastructs rules are created on register_post_type() which occurs before the form post to options-permalink.php has a chance to update the structure and $front values.

So order of execution is:

  1. Change Permalink Structure and Page Post to options-permalink.php
  2. Read structure setting from database
  3. Load system permalinks
  4. Load plugins and register their permalinks
  5. options-permalink updates the structure setting value in the database
  6. Calls flush system permalinks
  7. Loads new system permalinks and merges with old CPT permalinks because it never calls register_post_type()

On a second save, step 4 will have the correct permalinks structure, so when they are merged with the already correct system permalinks all is well with the universe again.

Ideally flush_rewrite_rules() actually flushes all rewrite rules. But I'm not sure if calling register_post_type() twice in one page load is safe. It could do an ajax post for the first change, and then a full form post for custom post types - but that seems a little hackey. I don't have a good solution yet so I can't provide a patch.

To reproduce and debug this behavior, setup at least one CPT and dump the variable $this->rules at the end of the function rewrite_rules() in rewrite.php. Go into permalinks settings page, change your structure to Numeric, click save. The log file will list all of the rules but the CPT will not have "archives" in front of their URL (unless Numeric was already selected.) Now select a different structure - "Post name", click save, and the CPT urls will have "archives" in front of the url, but the others will not. Click save again, and CPT's will be fixed.

Thanks,
Marcus

Change History (5)

comment:1 nacin20 months ago

  • Component changed from Permalinks to Rewrite Rules
  • Milestone changed from Awaiting Review to 3.5

Moving to 3.5 for investigation.

comment:2 SergeyBiryukov20 months ago

The patch on #9296 appears to fix this.

Version 0, edited 20 months ago by SergeyBiryukov (next)

comment:3 duck_20 months ago

Related: #20171. I think introducing and using rewrite_init would solve this. However, another solution would also be required to help all plugins currently written as they use init.

comment:4 wonderboymusic19 months ago

  • Milestone 3.5 deleted
  • Resolution set to duplicate
  • Status changed from new to closed

Duplicate of #14345.

Note: See TracTickets for help on using tickets.