Ticket #5809: 5809.patch
File 5809.patch, 16.8 KB (added by , 10 years ago) |
---|
-
src/wp-includes/taxonomy.php
diff --git src/wp-includes/taxonomy.php src/wp-includes/taxonomy.php index b9b8042..9aa66ee 100644
function wp_insert_term( $term, $taxonomy, $args = array() ) { 2824 2824 } 2825 2825 } 2826 2826 2827 if ( $term_id = term_exists($slug) ) { 2828 $existing_term = $wpdb->get_row( $wpdb->prepare( "SELECT name FROM $wpdb->terms WHERE term_id = %d", $term_id), ARRAY_A ); 2829 // We've got an existing term in the same taxonomy, which matches the name of the new term: 2830 if ( is_taxonomy_hierarchical($taxonomy) && $existing_term['name'] == $name && $exists = term_exists( (int) $term_id, $taxonomy ) ) { 2831 // Hierarchical, and it matches an existing term, Do not allow same "name" in the same level. 2832 $siblings = get_terms($taxonomy, array('fields' => 'names', 'get' => 'all', 'parent' => $parent ) ); 2833 if ( in_array($name, $siblings) ) { 2834 if ( $slug_provided ) { 2835 return new WP_Error( 'term_exists', __( 'A term with the name and slug provided already exists with this parent.' ), $exists['term_id'] ); 2836 } else { 2837 return new WP_Error( 'term_exists', __( 'A term with the name provided already exists with this parent.' ), $exists['term_id'] ); 2827 // Terms with duplicate names are not allowed at the same level of a taxonomy hierarchy. 2828 if ( $exists = term_exists( $slug, $taxonomy ) ) { 2829 $existing_term = get_term( $exists['term_id'], $taxonomy ); 2830 2831 if ( $name === $existing_term->name ) { 2832 2833 if ( is_taxonomy_hierarchical( $taxonomy ) ) { 2834 $siblings = get_terms( $taxonomy, array( 'fields' => 'names', 'get' => 'all', 'parent' => $parent ) ); 2835 if ( in_array( $name, $siblings ) ) { 2836 return new WP_Error( 'term_exists', __( 'A term with the name and slug already exists with this parent.' ), $exists['term_id'] ); 2838 2837 } 2838 2839 2839 } else { 2840 $slug = wp_unique_term_slug($slug, (object) $args); 2841 if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) { 2842 return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error); 2843 } 2844 $term_id = (int) $wpdb->insert_id; 2840 return new WP_Error( 'term_exists', __( 'A term with the name and slug already exists in this taxonomy.' ), $exists['term_id'] ); 2845 2841 } 2846 } elseif ( $existing_term['name'] != $name ) {2847 // We've got an existing term, with a different name, Create the new term.2848 $slug = wp_unique_term_slug($slug, (object) $args);2849 if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) {2850 return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error);2851 }2852 $term_id = (int) $wpdb->insert_id;2853 } elseif ( $exists = term_exists( (int) $term_id, $taxonomy ) ) {2854 // Same name, same slug.2855 return new WP_Error( 'term_exists', __( 'A term with the name and slug provided already exists.' ), $exists['term_id'] );2856 }2857 } else {2858 // This term does not exist at all in the database, Create it.2859 $slug = wp_unique_term_slug($slug, (object) $args);2860 if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) {2861 return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error);2862 2842 } 2863 $term_id = (int) $wpdb->insert_id;2864 2843 } 2865 2844 2845 $slug = wp_unique_term_slug( $slug, (object) $args ); 2846 if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) { 2847 return new WP_Error( 'db_insert_error', __( 'Could not insert term into the database' ), $wpdb->last_error ); 2848 } 2849 2850 $term_id = (int) $wpdb->insert_id; 2851 2866 2852 // Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string. 2867 2853 if ( empty($slug) ) { 2868 2854 $slug = sanitize_title($slug, $term_id); … … function wp_unique_term_slug($slug, $term) { 3189 3175 if ( ! term_exists( $slug ) ) 3190 3176 return $slug; 3191 3177 3178 // As of 4.1, duplicate slugs are allowed as long as they're in different taxonomies. 3179 if ( get_option( 'db_version' ) >= 30056 && ! get_term_by( 'slug', $slug, $term->taxonomy ) ) { 3180 return $slug; 3181 } 3182 3192 3183 // If the taxonomy supports hierarchy and the term has a parent, make the slug unique 3193 3184 // by incorporating parent slugs. 3194 3185 if ( is_taxonomy_hierarchical($term->taxonomy) && !empty($term->parent) ) { … … function wp_update_term( $term_id, $taxonomy, $args = array() ) { 3352 3343 return new WP_Error('duplicate_term_slug', sprintf(__('The slug “%s” is already in use by another term'), $slug)); 3353 3344 } 3354 3345 3346 $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) ); 3347 3348 // Check to see if this is a shared terms that needs splitting. 3349 $_term_id = _split_shared_term( $term_id, $tt_id ); 3350 if ( ! is_wp_error( $_term_id ) ) { 3351 $term_id = $_term_id; 3352 } 3353 3355 3354 /** 3356 3355 * Fires immediately before the given terms are edited. 3357 3356 * … … function wp_update_term( $term_id, $taxonomy, $args = array() ) { 3377 3376 */ 3378 3377 do_action( 'edited_terms', $term_id, $taxonomy ); 3379 3378 3380 $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) );3381 3382 3379 /** 3383 3380 * Fires immediate before a term-taxonomy relationship is updated. 3384 3381 * … … function _update_generic_term_count( $terms, $taxonomy ) { 4003 4000 } 4004 4001 4005 4002 /** 4003 * Create a new term for a term_taxonomy item that currently shares its term. 4004 * 4005 * @param int $term_id ID of the shared term. 4006 * @param int $term_taxonomy_id ID of the term taxonomy item to receive a new term. 4007 * @param array $shared_tts Sibling term taxonomies, used for busting caches. 4008 * @return int Term ID. 4009 */ 4010 function _split_shared_term( $term_id, $term_taxonomy_id ) { 4011 global $wpdb; 4012 4013 // Don't try to split terms if database schema does not support shared slugs. 4014 $current_db_version = get_option( 'db_version' ); 4015 if ( $current_db_version < 30056 ) { 4016 return $term_id; 4017 } 4018 4019 // If there are no shared term_taxonomy rows, there's nothing to do here. 4020 $shared_tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d AND term_taxonomy_id != %d", $term_id, $term_taxonomy_id ) ); 4021 if ( ! $shared_tt_count ) { 4022 return $term_id; 4023 } 4024 4025 // Pull up data about the currently shared slug, which we'll use to populate the new one. 4026 $shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->terms WHERE term_id = %d", $term_id ) ); 4027 4028 $new_term_data = array( 4029 'name' => $shared_term->name, 4030 'slug' => $shared_term->slug, 4031 'term_group' => $shared_term->term_group, 4032 ); 4033 4034 if ( false === $wpdb->insert( $wpdb->terms, $new_term_data ) ) { 4035 return new WP_Error( 'db_insert_error', __( 'Could not split shared term.' ), $wpdb->last_error ); 4036 } 4037 4038 $new_term_id = (int) $wpdb->insert_id; 4039 4040 // Update the existing term_taxonomy to point to the newly created term. 4041 $wpdb->update( $wpdb->term_taxonomy, 4042 array( 'term_id' => $new_term_id ), 4043 array( 'term_taxonomy_id' => $term_taxonomy_id ), 4044 array( '%d' ), 4045 array( '%d' ) 4046 ); 4047 4048 // Clean the formerly shared term's cache. 4049 clean_term_cache( $term_id, $shared_term->taxonomy ); 4050 4051 return $new_term_id; 4052 } 4053 4054 /** 4006 4055 * Generate a permalink for a taxonomy term archive. 4007 4056 * 4008 4057 * @since 2.5.0 -
tests/phpunit/tests/term.php
diff --git tests/phpunit/tests/term.php tests/phpunit/tests/term.php index b6fe994..1258c4b 100644
class Tests_Term extends WP_UnitTestCase { 226 226 $this->assertFalse( is_wp_error( $term20 ) ); 227 227 } 228 228 229 /** 230 * @ticket 5809 231 */ 232 public function test_wp_insert_term_duplicate_slug_same_taxonomy() { 233 register_taxonomy( 'wptests_tax', 'post' ); 234 $t = $this->factory->term->create( array( 235 'name' => 'Foo', 236 'slug' => 'foo', 237 'taxonomy' => 'wptests_tax', 238 ) ); 239 240 $term = get_term( $t, 'wptests_tax' ); 241 242 $created = wp_insert_term( 'Foo 2', 'wptests_tax', array( 243 'slug' => 'foo', 244 ) ); 245 246 $created_term = get_term( $created['term_id'], 'wptests_tax' ); 247 $this->assertSame( 'foo-2', $created_term->slug ); 248 249 _unregister_taxonomy( 'wptests_tax', 'post' ); 250 } 251 252 /** 253 * @ticket 5809 254 */ 255 public function test_wp_insert_term_duplicate_slug_different_taxonomy() { 256 register_taxonomy( 'wptests_tax', 'post' ); 257 register_taxonomy( 'wptests_tax_2', 'post' ); 258 $t = $this->factory->term->create( array( 259 'name' => 'Foo', 260 'slug' => 'foo', 261 'taxonomy' => 'wptests_tax', 262 ) ); 263 264 $term = get_term( $t, 'wptests_tax' ); 265 266 $created = wp_insert_term( 'Foo 2', 'wptests_tax_2', array( 267 'slug' => 'foo', 268 ) ); 269 270 $this->assertFalse( is_wp_error( $created ) ); 271 272 $new_term = get_term( $created['term_id'], 'wptests_tax_2' ); 273 274 $this->assertSame( 'foo', $new_term->slug ); 275 276 _unregister_taxonomy( 'wptests_tax', 'post' ); 277 } 278 279 /** 280 * @ticket 5809 281 */ 282 public function test_wp_insert_term_duplicate_slug_different_taxonomy_before_410_schema_change() { 283 284 $db_version = get_option( 'db_version' ); 285 update_option( 'db_version', 30055 ); 286 287 register_taxonomy( 'wptests_tax', 'post' ); 288 register_taxonomy( 'wptests_tax_2', 'post' ); 289 $t = $this->factory->term->create( array( 290 'name' => 'Foo', 291 'slug' => 'foo', 292 'taxonomy' => 'wptests_tax', 293 ) ); 294 295 $term = get_term( $t, 'wptests_tax' ); 296 297 $created = wp_insert_term( 'Foo 2', 'wptests_tax_2', array( 298 'slug' => 'foo', 299 ) ); 300 301 $this->assertFalse( is_wp_error( $created ) ); 302 303 $new_term = get_term( $created['term_id'], 'wptests_tax_2' ); 304 305 /* 306 * As of 4.1, we no longer create a shared term, but we also do not 307 * allow for duplicate slugs. 308 */ 309 $this->assertSame( 'foo-2', $new_term->slug ); 310 $this->assertNotEquals( $new_term->term_id, $term->term_id ); 311 312 _unregister_taxonomy( 'wptests_tax', 'post' ); 313 update_option( 'db_version', $db_version ); 314 } 315 229 316 public function test_wp_insert_term_alias_of_no_term_group() { 230 317 register_taxonomy( 'wptests_tax', 'post' ); 231 318 $t1 = $this->factory->term->create( array( … … class Tests_Term extends WP_UnitTestCase { 353 440 $this->assertEquals( $existing_term, $found->get_error_data() ); 354 441 } 355 442 443 /** 444 * @ticket 5809 445 */ 446 public function test_wp_insert_term_should_not_create_shared_term() { 447 register_taxonomy( 'wptests_tax', 'post' ); 448 register_taxonomy( 'wptests_tax_2', 'post' ); 449 450 $t1 = wp_insert_term( 'Foo', 'wptests_tax' ); 451 $t2 = wp_insert_term( 'Foo', 'wptests_tax_2' ); 452 453 $this->assertNotEquals( $t1['term_id'], $t2['term_id'] ); 454 } 455 356 456 public function test_wp_insert_term_should_return_term_id_and_term_taxonomy_id() { 357 457 register_taxonomy( 'wptests_tax', 'post' ); 358 458 $found = wp_insert_term( 'foo', 'wptests_tax' ); … … class Tests_Term extends WP_UnitTestCase { 537 637 _unregister_taxonomy( 'wptests_tax' ); 538 638 } 539 639 640 /** 641 * @ticket 5809 642 */ 643 public function test_wp_update_term_duplicate_slug_same_taxonomy() { 644 register_taxonomy( 'wptests_tax', 'post' ); 645 646 $t1 = $this->factory->term->create( array( 647 'name' => 'Foo', 648 'slug' => 'foo', 649 'taxonomy' => 'wptests_tax', 650 ) ); 651 652 $t2 = $this->factory->term->create( array( 653 'name' => 'Foo', 654 'slug' => 'bar', 655 'taxonomy' => 'wptests_tax', 656 ) ); 657 658 $updated = wp_update_term( $t2, 'wptests_tax', array( 659 'slug' => 'foo', 660 ) ); 661 662 $this->assertWPError( $updated ); 663 $this->assertSame( 'duplicate_term_slug', $updated->get_error_code() ); 664 } 665 666 /** 667 * @ticket 5809 668 */ 669 public function test_wp_update_term_duplicate_slug_different_taxonomy() { 670 register_taxonomy( 'wptests_tax', 'post' ); 671 register_taxonomy( 'wptests_tax_2', 'post' ); 672 673 $t1 = $this->factory->term->create( array( 674 'name' => 'Foo', 675 'slug' => 'foo', 676 'taxonomy' => 'wptests_tax', 677 ) ); 678 679 $t2 = $this->factory->term->create( array( 680 'name' => 'Foo', 681 'slug' => 'bar', 682 'taxonomy' => 'wptests_tax_2', 683 ) ); 684 685 $updated = wp_update_term( $t2, 'wptests_tax_2', array( 686 'slug' => 'foo', 687 ) ); 688 689 $this->assertWPError( $updated ); 690 $this->assertSame( 'duplicate_term_slug', $updated->get_error_code() ); 691 } 692 693 /** 694 * @ticket 5809 695 */ 696 public function test_wp_update_term_should_split_shared_term() { 697 global $wpdb; 698 699 register_taxonomy( 'wptests_tax', 'post' ); 700 register_taxonomy( 'wptests_tax_2', 'post' ); 701 702 $t1 = wp_insert_term( 'Foo', 'wptests_tax' ); 703 $t2 = wp_insert_term( 'Foo', 'wptests_tax_2' ); 704 705 // Manually modify because split terms shouldn't naturally occur. 706 $wpdb->update( $wpdb->term_taxonomy, 707 array( 'term_id' => $t1['term_id'] ), 708 array( 'term_taxonomy_id' => $t2['term_taxonomy_id'] ), 709 array( '%d' ), 710 array( '%d' ) 711 ); 712 713 $posts = $this->factory->post->create_many( 2 ); 714 wp_set_object_terms( $posts[0], array( 'Foo' ), 'wptests_tax' ); 715 wp_set_object_terms( $posts[1], array( 'Foo' ), 'wptests_tax_2' ); 716 717 // Verify that the terms are shared. 718 $t1_terms = wp_get_object_terms( $posts[0], 'wptests_tax' ); 719 $t2_terms = wp_get_object_terms( $posts[1], 'wptests_tax_2' ); 720 $this->assertSame( $t1_terms[0]->term_id, $t2_terms[0]->term_id ); 721 722 wp_update_term( $t2_terms[0]->term_id, 'wptests_tax_2', array( 723 'name' => 'New Foo', 724 ) ); 725 726 $t1_terms = wp_get_object_terms( $posts[0], 'wptests_tax' ); 727 $t2_terms = wp_get_object_terms( $posts[1], 'wptests_tax_2' ); 728 $this->assertNotEquals( $t1_terms[0]->term_id, $t2_terms[0]->term_id ); 729 } 730 731 /** 732 * @ticket 5809 733 */ 734 public function test_wp_update_term_should_not_split_shared_term_before_410_schema_change() { 735 global $wpdb; 736 737 $db_version = get_option( 'db_version' ); 738 update_option( 'db_version', 30055 ); 739 740 register_taxonomy( 'wptests_tax', 'post' ); 741 register_taxonomy( 'wptests_tax_2', 'post' ); 742 743 $t1 = wp_insert_term( 'Foo', 'wptests_tax' ); 744 $t2 = wp_insert_term( 'Foo', 'wptests_tax_2' ); 745 746 // Manually modify because split terms shouldn't naturally occur. 747 $wpdb->update( $wpdb->term_taxonomy, 748 array( 'term_id' => $t1['term_id'] ), 749 array( 'term_taxonomy_id' => $t2['term_taxonomy_id'] ), 750 array( '%d' ), 751 array( '%d' ) 752 ); 753 754 $posts = $this->factory->post->create_many( 2 ); 755 wp_set_object_terms( $posts[0], array( 'Foo' ), 'wptests_tax' ); 756 wp_set_object_terms( $posts[1], array( 'Foo' ), 'wptests_tax_2' ); 757 758 // Verify that the term is shared. 759 $t1_terms = wp_get_object_terms( $posts[0], 'wptests_tax' ); 760 $t2_terms = wp_get_object_terms( $posts[1], 'wptests_tax_2' ); 761 $this->assertSame( $t1_terms[0]->term_id, $t2_terms[0]->term_id ); 762 763 wp_update_term( $t2_terms[0]->term_id, 'wptests_tax_2', array( 764 'name' => 'New Foo', 765 ) ); 766 767 // Term should still be shared. 768 $t1_terms = wp_get_object_terms( $posts[0], 'wptests_tax' ); 769 $t2_terms = wp_get_object_terms( $posts[1], 'wptests_tax_2' ); 770 $this->assertSame( $t1_terms[0]->term_id, $t2_terms[0]->term_id ); 771 772 update_option( 'db_version', $db_version ); 773 } 774 540 775 public function test_wp_update_term_alias_of_no_term_group() { 541 776 register_taxonomy( 'wptests_tax', 'post' ); 542 777 $t1 = $this->factory->term->create( array( … … class Tests_Term extends WP_UnitTestCase { 1366 1601 } 1367 1602 1368 1603 /** 1369 * @ticket 58091370 */1371 function test_update_shared_term() {1372 $random_tax = __FUNCTION__;1373 1374 register_taxonomy( $random_tax, 'post' );1375 1376 $post_id = $this->factory->post->create();1377 1378 $old_name = 'Initial';1379 1380 $t1 = wp_insert_term( $old_name, 'category' );1381 $t2 = wp_insert_term( $old_name, 'post_tag' );1382 1383 $this->assertEquals( $t1['term_id'], $t2['term_id'] );1384 1385 wp_set_post_categories( $post_id, array( $t1['term_id'] ) );1386 wp_set_post_tags( $post_id, array( (int) $t2['term_id'] ) );1387 1388 $new_name = 'Updated';1389 1390 // create the term in a third taxonomy, just to keep things interesting1391 $t3 = wp_insert_term( $old_name, $random_tax );1392 wp_set_post_terms( $post_id, array( (int) $t3['term_id'] ), $random_tax );1393 $this->assertPostHasTerms( $post_id, array( $t3['term_id'] ), $random_tax );1394 1395 $t2_updated = wp_update_term( $t2['term_id'], 'post_tag', array(1396 'name' => $new_name1397 ) );1398 1399 $this->assertNotEquals( $t2_updated['term_id'], $t3['term_id'] );1400 1401 // make sure the terms have split1402 $this->assertEquals( $old_name, get_term_field( 'name', $t1['term_id'], 'category' ) );1403 $this->assertEquals( $new_name, get_term_field( 'name', $t2_updated['term_id'], 'post_tag' ) );1404 1405 // and that they are still assigned to the correct post1406 $this->assertPostHasTerms( $post_id, array( $t1['term_id'] ), 'category' );1407 $this->assertPostHasTerms( $post_id, array( $t2_updated['term_id'] ), 'post_tag' );1408 $this->assertPostHasTerms( $post_id, array( $t3['term_id'] ), $random_tax );1409 1410 // clean up1411 unset( $GLOBALS['wp_taxonomies'][ $random_tax ] );1412 }1413 1414 /**1415 1604 * @ticket 25852 1416 1605 */ 1417 1606 function test_sanitize_term_field() {