From eebe54940803a7d99182e8ef5076c6da811de672 Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Sat, 3 Oct 2015 20:24:09 +0000 Subject: [PATCH] When creating terms, avoid false dupe checks due to accented characters. `wp_insert_term()` doesn't allow the creation of a term when the term `name` is the same as another term in the same hierarchy level of the same taxonomy. Previously, this duplicate check used `get_term_by( 'name' )`, which uses the database collation to determine sameness. But common collations do not distinguish between accented and non-accented versions of a character. As a result, it was impossible to create a term 'Foo' if a sibling term with an accented character existed. We address this problem by using `get_terms()` to do the duplicate check. This query returns all potentially matching terms. We then do a stricter check for equivalence in PHP, before determining whether one of the matches is indeed a duplicate. Props boonebgorges, tyxla, geza.miklo, mehulkaklotar. Fixes #33864. git-svn-id: https://develop.svn.wordpress.org/trunk@34809 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/taxonomy-functions.php | 21 ++++++++++++++++++- tests/phpunit/tests/term/wpInsertTerm.php | 25 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/taxonomy-functions.php b/src/wp-includes/taxonomy-functions.php index 8533641a1e..0692f6b833 100644 --- a/src/wp-includes/taxonomy-functions.php +++ b/src/wp-includes/taxonomy-functions.php @@ -2516,7 +2516,26 @@ function wp_insert_term( $term, $taxonomy, $args = array() ) { * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy, * unless a unique slug has been explicitly provided. */ - if ( $name_match = get_term_by( 'name', $name, $taxonomy ) ) { + $name_matches = get_terms( $taxonomy, array( + 'name' => $name, + 'hide_empty' => false, + ) ); + + /* + * The `name` match in `get_terms()` doesn't differentiate accented characters, + * so we do a stricter comparison here. + */ + $name_match = null; + if ( $name_matches ) { + foreach ( $name_matches as $_match ) { + if ( strtolower( $name ) === strtolower( $_match->name ) ) { + $name_match = $_match; + break; + } + } + } + + if ( $name_match ) { $slug_match = get_term_by( 'slug', $slug, $taxonomy ); if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) { if ( is_taxonomy_hierarchical( $taxonomy ) ) { diff --git a/tests/phpunit/tests/term/wpInsertTerm.php b/tests/phpunit/tests/term/wpInsertTerm.php index 09b0ea2089..0b5077ab28 100644 --- a/tests/phpunit/tests/term/wpInsertTerm.php +++ b/tests/phpunit/tests/term/wpInsertTerm.php @@ -628,6 +628,31 @@ class Tests_Term_WpInsertTerm extends WP_UnitTestCase { $this->assertTrue( in_array( $found['term_id'], $cached_children[ $t ] ) ); } + /** + * @ticket 33864 + */ + public function test_wp_insert_term_with_and_without_accents() { + register_taxonomy( 'wptests_tax', 'post' ); + + $t1 = $this->factory->term->create( array( + 'name' => 'FoĆ³', + 'taxonomy' => 'wptests_tax', + ) ); + $t2 = $this->factory->term->create( array( + 'name' => 'Foo', + 'taxonomy' => 'wptests_tax', + ) ); + + $this->assertInternalType( 'int', $t1 ); + $this->assertInternalType( 'int', $t2 ); + $this->assertNotEquals( $t1, $t2 ); + + $term_2 = get_term( $t2, 'wptests_tax' ); + $this->assertSame( $t2, $term_2->term_id ); + $this->assertSame( 'Foo', $term_2->name ); + + } + /** Helpers **********************************************************/ public function deleted_term_cb( $term, $tt_id, $taxonomy, $deleted_term ) {