Opened 2 months ago
Last modified 2 months ago
#64670 new defect (bug)
WP_REST_Posts_Controller::update_item() not passing parent to wp_unique_post_slug() for draft child
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Milestone: | Awaiting Review | Priority: | normal |
| Severity: | normal | Version: | 6.9.1 |
| Component: | REST API | Keywords: | has-patch needs-testing |
| Focuses: | ui, administration, rest-api | Cc: |
Description
Editing the slug of a draft child page (or any hierarchical post type) in the block editor excludes the parent slug when determining slug interference, despite the fact that the parent slug is shown in the child's permalink, just below the slug setting input.
I believe the slug check occurs with wp_unique_post_slug() in WP_REST_Posts_Controller::update_item() of wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:967.
Environment
- WordPress 6.9.1
- Theme: Twenty Twenty-Five 1.4
- Plugins: none
- PHP 8.4.14
- nginx 1.29.3
- mysql 9.5.0
- macOS 15.7.3
Steps to Reproduce
Permalink structure: Post name
Steps 1–3 below can be done in multiple ways (block editor, wp-cli, etc.).
- Publish a page (First Page), example slug: /slug
- Publish another page (Parent Page), example slug: /parent
- Create another draft page (Child Page), set its parent to Parent Page, and save the draft
- In the block editor, edit the Child Page slug to /slug and save the draft; the slug will be changed to slug-2, even though the permalink just below the slug input shows /parent/slug and /parent/slug does not interfere with First Page /slug
Additional Notes:
- If Child Page is published, its slug can be edited to /parent/slug in the block editor.
- In draft status, Child Page can have its slug edited to /parent/slug using quick edit in admin post list.
Expected Outcomes
- Slug editing behavior for parent/child relationships should be the same in the block editor and admin post list quick edit.
- If the block editor slug setting shows a parent slug incorporated into a child's permalink, the parent slug should also be used to determine the child slug's interference (regardless of the child's status).
Possible Solutions
Before wp_unique_post_slug() is called in class-wp-rest-posts-controller.php:967, the following defines $post and $post_parent.
$post = $this->prepare_item_for_database( $request ); ... $post_parent = ! empty( $post->post_parent ) ? $post->post_parent : 0;
For a draft page, $post->post_parent comes through as null, so it's set to 0;
$post_before, defined a few lines earlier at class-wp-rest-posts-controller.php:947, does contain the parent and could possibly be used to define $post_parent similar to $post_status at line 954. For example:
if ( ! empty( $post->post_parent ) ) {
$post_parent = $post->post_parent;
} else {
$post_parent = $post_before->post_parent ? $post_before->post_parent : 0;
}
Related Tickets
In #47988 @paulbonneau noted how draft and pending statuses are changed to publish for wp_unique_post_slug() calls in WP_REST_Posts_Controller:create_item() and WP_REST_Posts_Controller::update_item(). That seems unusual and suggests room for improvement, though any changes to wp_unique_post_slug() would need careful consideration.
I share @paulbonneau's interest in wondering, "Why shouldn't we assign a post_name to a post with a draft post_status?".
#47988 also references several other tickets related to draft status and wp_unique_post_slug(), such as #47552 and #61996.
Change History (2)
This ticket was mentioned in PR #10973 on WordPress/wordpress-develop by @maulikmakwana2008.
2 months ago
#1
- Keywords has-patch added
#2
@
2 months ago
- Component changed from Permalinks to REST API
- Keywords needs-testing added
I’ve prepared a fix that preserves the existing parent ID when updating draft hierarchical posts via the REST API.
Currently, when post_parent is not included in the REST request (as in the block editor for draft child pages), wp_unique_post_slug() is called with a parent ID of 0, causing false slug conflicts with top-level posts.
The patch falls back to $post_before->post_parent when $post->post_parent is empty, ensuring slug uniqueness is evaluated using the correct parent. This aligns block editor behavior with Quick Edit and classic update flows.
Fixed : https://core.trac.wordpress.org/ticket/64670