Opened 8 weeks ago
Last modified 8 weeks ago
#47988 new defect (bug)
Unexpected behaviour when draft post has the same page_name as published post
Reported by: | ajfleming | Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | normal | Version: | |
Component: | Posts, Post Types | Keywords: | |
Focuses: | Cc: | ||
PR Number: |
Description
What steps should be taken to consistently reproduce the problem?
wp rewrite structure '/%postname%/' wp post create --post_title="Example post title" --post_status=publish --post_name=my-chosen-post-name wp post create --post_title="A draft post" --post_status=draft --post_name=my-chosen-post-name
Visit http://www.example.com/my-chosen-post-name
In case it's relevant to the ticket, what is the expected output or result?
We're expecting the published post to be displayed.
What did you see instead?
If you're authenticated and have permission to view drafts, the draft post will populate the Global $post
object and be displayed.
Anonymous users will get a 404 page or the browser will throw a Too many redirects
error.
Does the problem occur even when you deactivate all plugins and use the default theme?
Yes.
Please provide any additional information that you think we'd find useful. (OS and browser for UI defects, server environment for crashes, etc.)
The core behaviour of the WP Admin post edit screen doesn't allow us to get into this state because post_name
values are not stored for a post until it transitions to the publish
post status. When this transition does happen wp_unique_post_slug()
ensures the post_name
being saved unique.
We first encountered this issue via the Yoast SEO plugin metabox which allows a Slug to be saved for draft posts. As you can see with the WP-CLI commands above, however, there are other ways of getting to this state.
The draft post is loaded for authenticated requests because the default query vars order_by => post_date
and order => DESC
means the draft post created after the published post populates the WP_Query->post
property.
Anonymous requests are not able to view the draft post, so before returning a 404, redirect_canonical()
calls redirect_guess_404_permalink()
which builds a query for a published post where page_name
is LIKE
the post name and finds the published post and redirects to it... and the loop continues.
A possible solution would
wp_unique_post_slug()
returning an empty string for draft posts instead of the passed value.