Opened 8 years ago
Closed 8 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: | mikejolley | Owned by: | boonebgorges |
---|---|---|---|
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
@
8 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
@
8 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_matches
array 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,child
will practically always be first. - This means that the
$name_match->slug === $slug
condition on line 2066 is usually met. But it's sorta coincidental that this works: if you first created 'Child' with the manual slugchild-foo
and 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
@
8 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
@
8 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