Opened 5 weeks ago
#61996 new defect (bug)
Slug Conflict When a Published and Draft Page Share post_name
Reported by: | brookedot | Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | normal | Version: | |
Component: | Posts, Post Types | Keywords: | |
Focuses: | Cc: |
Description
It is possible (although it takes some work) to have a published page and a draft page that shares the same post_name
. When this occurs if the draft page has a lower ID then it is retrieved by get_page_by_path
in place of the published page. This is due at least in part to get_page_by_path
not checking the page status and .
- Ensure permalinks are anything other than
Plain
- Publish three nested pages, the first page here is needed to avoid a slug conflict when you later create pages with the same name. For example, to prevent
parent
from becomingparent-2
. The posts must be published so they can be selected as parent pages. Consider setting the page content to "this is draft" so it's easy to tell these apart later.
- Placeholder (slug
placeholder
)- Parent (slug
/placehoder/parent
- Child ( slug
placeholder/parent/child
- Child ( slug
- Parent (slug
- Using the Bulk Action, set all three newly created published posts to draft. There may be other ways to do this, as well.
- Publish two addition new pages with the same slugs as
parent
andchild
- Parent ( slug
parent
)- Child (slug
parent/child
)
- Child (slug
- Using Quick Edit remove the parent from the draft page
parent
(/placeholder/parent
) by setting its parent page to `Main (no parent) keeping it as a draft.
You should now have parent
and parent/child
as drafts alongside your other two published pages.
- Ensure you don't have a
-2
in eitherparent-2
orchild-2
- If all goes well, when you visit
parent/child
you will now see a 404 instead of the pages you published in step 4.
There is a screen recording of these steps here:
https://cloudup.com/cxkwjscxDfB
They can be replicated in Multisite, Single site, and WordPress playground.
Some insight into what is happening is when you return the array used to get_page_by_path
. For WordPress 6.6.1 that is https://github.com/WordPress/WordPress/blob/6.6.1/wp-includes/post.php#L5881
Using var_dump
to return the array:
<?php $sql = " SELECT ID, post_name, post_parent, post_type FROM $wpdb->posts WHERE post_name IN ($in_string) AND post_type IN ($post_type_in_string) "; $pages = $wpdb->get_results( $sql, ARRAY_A ); $revparts = array_reverse( $parts ); var_dump( $pages );
This returns post ID 63 first which is our draft child
page thus a 404 on the front end. ID 69
is the published child
page which is never displayed on the front end as ID 63 is returned first.
Here is the output of the above var_dump()
<?php array (size=4) 0 => array (size=4) 'ID' => string '63' (length=2) 'post_name' => string 'child' (length=5) 'post_parent' => string '61' (length=2) 'post_type' => string 'page' (length=4) 1 => array (size=4) 'ID' => string '69' (length=2) 'post_name' => string 'child' (length=5) 'post_parent' => string '65' (length=2) 'post_type' => string 'page' (length=4) 2 => array (size=4) 'ID' => string '61' (length=2) 'post_name' => string 'parent' (length=6) 'post_parent' => string '0' (length=1) 'post_type' => string 'page' (length=4) 3 => array (size=4) 'ID' => string '65' (length=2) 'post_name' => string 'parent' (length=6) 'post_parent' => string '0' (length=1) 'post_type' => string 'page' (length=4)
A few other related trac issues were found but nothing that matched this exactly. Please update the Component to match the closest, I almost set this as permalinks
Related to #13459 (but not a duplicate as this is the same post type)
Props @trepmal who was instrumental in debugging and reporting this bug.