Skip to content
22 changes: 17 additions & 5 deletions src/wp-includes/post.php
Original file line number Diff line number Diff line change
Expand Up @@ -6222,7 +6222,7 @@ function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {
$post_types = esc_sql( $post_types );
$post_type_in_string = "'" . implode( "','", $post_types ) . "'";
$sql = "
SELECT ID, post_name, post_parent, post_type
SELECT ID, post_name, post_parent, post_type, post_status
FROM $wpdb->posts
WHERE post_name IN ($in_string)
AND post_type IN ($post_type_in_string)
Expand All @@ -6232,7 +6232,9 @@ function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {

$revparts = array_reverse( $parts );

$found_id = 0;
$found_id = 0;
$found_type_rank = 0;
$found_status_rank = 0;
foreach ( (array) $pages as $page ) {
if ( $page->post_name === $revparts[0] ) {
$count = 0;
Expand All @@ -6255,9 +6257,19 @@ function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {
&& count( $revparts ) === $count + 1
&& $p->post_name === $revparts[ $count ]
) {
$found_id = $page->ID;
if ( $page->post_type === $post_type ) {
break;
if ( is_array( $post_type ) ) {
$is_type_match = in_array( $page->post_type, $post_type, true );
} else {
$is_type_match = ( $page->post_type === $post_type );
}

$type_rank = $is_type_match ? 2 : 1;
$status_rank = is_post_status_viewable( $page->post_status ) ? 2 : 1;

if ( $type_rank > $found_type_rank || ( $type_rank === $found_type_rank && $status_rank > $found_status_rank ) ) {
$found_id = $page->ID;
$found_type_rank = $type_rank;
$found_status_rank = $status_rank;
}
}
}
Expand Down
59 changes: 59 additions & 0 deletions tests/phpunit/tests/post/getPageByPath.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,65 @@ public function test_should_match_nested_page_query_count_status() {
$this->assertIsObject( $cached_post, 'The cached post is not an object' );
}

/**
* @ticket 61996
*
* @covers ::get_page_by_path
*/
public function test_should_prefer_published_page_when_slug_conflicts_with_draft() {
global $wpdb;

$draft_parent = self::factory()->post->create_and_get(
array(
'post_type' => 'page',
'post_status' => 'draft',
'post_name' => 'draft-parent',
)
);

$draft_child = self::factory()->post->create_and_get(
array(
'post_type' => 'page',
'post_status' => 'draft',
'post_name' => 'draft-child',
'post_parent' => $draft_parent->ID,
)
);

$published_parent = self::factory()->post->create_and_get(
array(
'post_type' => 'page',
'post_status' => 'publish',
'post_name' => 'published-parent',
)
);

$published_child = self::factory()->post->create_and_get(
array(
'post_type' => 'page',
'post_status' => 'publish',
'post_name' => 'published-child',
'post_parent' => $published_parent->ID,
)
);

$wpdb->update( $wpdb->posts, array( 'post_name' => 'parent' ), array( 'ID' => $draft_parent->ID ) );
$wpdb->update( $wpdb->posts, array( 'post_name' => 'child' ), array( 'ID' => $draft_child->ID ) );
$wpdb->update( $wpdb->posts, array( 'post_name' => 'parent' ), array( 'ID' => $published_parent->ID ) );
$wpdb->update( $wpdb->posts, array( 'post_name' => 'child' ), array( 'ID' => $published_child->ID ) );

clean_post_cache( $draft_parent->ID );
clean_post_cache( $draft_child->ID );
clean_post_cache( $published_parent->ID );
clean_post_cache( $published_child->ID );

$found_child = get_page_by_path( 'parent/child' );
$this->assertSame( $published_child->ID, $found_child->ID );

$found_parent = get_page_by_path( 'parent' );
$this->assertSame( $published_parent->ID, $found_parent->ID );
}

/**
* @ticket 56689
*
Expand Down
Loading