Opened 9 years ago
Closed 9 years ago
#39984 closed defect (bug) (fixed)
wp_insert_term can return wrong ID when multiple existing terms are found with the same name but differnet parent
| Reported by: |
|
Owned by: |
|
|---|---|---|---|
| Milestone: | 4.8 | Priority: | normal |
| Severity: | normal | Version: | 4.2 |
| Component: | Taxonomy | Keywords: | has-patch dev-feedback needs-testing |
| Focuses: | Cc: |
Description
First reported here as an API issue https://github.com/woocommerce/woocommerce/issues/13386, it seems the problem is within the wp_insert_term logic.
To reproduce:
Create 2 terms with the same name, but different parents e.g.
- Top Level 1
- Child
- Top Level 2
- Child
You'll have 2 terms with name Child and slugs child and child-top-level-2.
Now try to add the same named Child term again to the second top level parent (in my case, Top Level 2).
var_dump( wp_insert_term( 'Child', 'category', array( 'parent' => 1158 ) ) );
The error message wil contain the term ID underneath the first top level parent (1159) instead of the correct one term under the chosen parent (1158):
object(WP_Error)#1270 (2) {
["errors"]=>
array(1) {
["term_exists"]=>
array(1) {
[0]=>
string(62) "A term with the name provided already exists with this parent."
}
}
["error_data"]=>
array(1) {
["term_exists"]=>
int(1159)
}
}
I've traced this back to the $name_matches code inside the wp_insert_term function. This code does not use the parent right now.
Patch to follow.
Attachments (2)
Change History (8)
#1
@
9 years ago
- Keywords has-patch dev-feedback needs-testing added
Added a potential patch, but it needs some more eyes and testing. It does 2 things;
- Ensures only terms from the specified parent are found to check names.
- It forces the name check if no slug was provided by the user. This is because the slug (if multiple terms with same name exists) will already have a suffix.
#2
@
9 years ago
- Component changed from General to Taxonomy
- Milestone changed from Awaiting Review to 4.8
Thanks for the detailed report and the patch, @mikejolley. I've attached a second patch that includes a test demonstrating the problem and the fix.
Regarding your point 2 - I would like to talk through what's happening here, since it seems like a change in behavior. I believe that your patch for 1 has turned up a bug, along the following lines:
- It's possible for there to be more than one member of
$name_matches, either because of accented characters (see the following block) or because of hierarchy branches like the one described in this ticket. - When no slug is provided to
wp_insert_term()and there's a name match (in the relevant part of the taxonomy), we generally want to return an error - this is one of the legacy error conditions ofwp_insert_term() - It's usually the case that the first member of the
$name_matchesarray will have the non-prefixed slug. That is: under normal circumstances (entering category names from the Dashboard), WP is responsible for generating slugs; so the first 'Child' will get the slugchild, the second will getchild-foo, etc. Since the default sort order ofget_terms()is by ID,childwill practically always be first. - This means that the
$name_match->slug === $slugcondition on line 2066 is usually met. But it's sorta coincidental that this works: if you first created 'Child' with the manual slugchild-fooand then created a second 'Child' withchild, you'd surface the bug, independently of the hierarchy issue described in this ticket.
Does that sound right to you? If so, there are really two bugs to fix here.
#3
@
9 years ago
Yeah that sounds about right. It's hard to explain this one. I think it's important we allow multiple terms with same names under different parents. I'm not sure how we'd fix this in our API if it were disallowed :)
#4
@
9 years ago
- Owner set to boonebgorges
- Status changed from new to accepted
- Version changed from trunk to 4.2
Thanks, @mikejolley.
I think it's important we allow multiple terms with same names under different parents.
Yes, WP has always allowed this. This particular weird bug was introduced as part of a refactor in support of multibyte slugs. See https://core.trac.wordpress.org/ticket/31328#comment:9 and follow-up conversation, especially [31792]. (Prior to WP 4.2, this specific kind of bug didn't occur because we used term_exists() instead of get_term_by( 'name' ); term_exists() would fall back on a slug check.)
Fix for issue 39984