diff --git a/.gitignore b/.gitignore
index 2f4d4eb9d2..2bb7d567fb 100644
a
|
b
|
wp-tests-config.php |
76 | 76 | |
77 | 77 | # Files for local environment config |
78 | 78 | /docker-compose.override.yml |
| 79 | .vscode |
diff --git a/src/wp-includes/capabilities.php b/src/wp-includes/capabilities.php
index e3a18f6b28..5a4e34f7ef 100644
a
|
b
|
function map_meta_cap( $cap, $user_id, ...$args ) { |
524 | 524 | break; |
525 | 525 | } |
526 | 526 | |
527 | | if ( 'delete_term' === $cap && ( $term->term_id == get_option( 'default_' . $term->taxonomy ) ) ) { |
| 527 | if ( 'delete_term' === $cap && ( $term->term_id == get_option( 'default_' . $term->taxonomy ) || $term->term_id == get_option( 'default_taxonomy_' . $term->taxonomy ) ) ) { |
528 | 528 | $caps[] = 'do_not_allow'; |
529 | 529 | break; |
530 | 530 | } |
diff --git a/src/wp-includes/class-wp-taxonomy.php b/src/wp-includes/class-wp-taxonomy.php
index 716da8d384..7b47c4b5c8 100644
a
|
b
|
final class WP_Taxonomy { |
204 | 204 | */ |
205 | 205 | public $rest_controller_class; |
206 | 206 | |
| 207 | /** |
| 208 | * The default term name. If you pass an array you have to set |
| 209 | * 'name' and optionally slug' and 'description'. |
| 210 | * |
| 211 | * @since 5.0.0 |
| 212 | * @var array|string |
| 213 | */ |
| 214 | public $default_term; |
| 215 | |
207 | 216 | /** |
208 | 217 | * Whether it is a built-in taxonomy. |
209 | 218 | * |
… |
… |
final class WP_Taxonomy { |
273 | 282 | 'show_in_rest' => false, |
274 | 283 | 'rest_base' => false, |
275 | 284 | 'rest_controller_class' => false, |
| 285 | 'default_term' => null, |
276 | 286 | '_builtin' => false, |
277 | 287 | ); |
278 | 288 | |
… |
… |
final class WP_Taxonomy { |
371 | 381 | } |
372 | 382 | } |
373 | 383 | |
| 384 | // Default taxonomy term. |
| 385 | if ( ! empty( $args['default_term'] ) ) { |
| 386 | if ( ! is_array( $args['default_term'] ) ) { |
| 387 | $args['default_term'] = array( 'name' => $args['default_term'] ); |
| 388 | } |
| 389 | $args['default_term'] = wp_parse_args( $args['default_term'], array( 'name' => '', 'slug' => '', 'description' => '' ) ); |
| 390 | } |
| 391 | |
374 | 392 | foreach ( $args as $property_name => $property_value ) { |
375 | 393 | $this->$property_name = $property_value; |
376 | 394 | } |
diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php
index 491fc666a4..73be6a8f9a 100644
a
|
b
|
function wp_insert_post( $postarr, $wp_error = false ) { |
3916 | 3916 | wp_set_post_tags( $post_ID, $postarr['tags_input'] ); |
3917 | 3917 | } |
3918 | 3918 | |
| 3919 | // Add default term for all associated custom taxonomies. |
| 3920 | if ( 'auto-draft' !== $post_status ) { |
| 3921 | foreach ( get_object_taxonomies( $post_type, 'object' ) as $taxonomy => $tax_object ) { |
| 3922 | if ( ! empty( $tax_object->default_term ) && ( empty( $postarr['tax_input'] ) || ! isset( $postarr['tax_input'][ $taxonomy ] ) ) ) { |
| 3923 | $postarr['tax_input'][ $taxonomy ] = array(); |
| 3924 | } |
| 3925 | } |
| 3926 | } |
| 3927 | |
3919 | 3928 | // New-style support for all custom taxonomies. |
3920 | 3929 | if ( ! empty( $postarr['tax_input'] ) ) { |
3921 | 3930 | foreach ( $postarr['tax_input'] as $taxonomy => $tags ) { |
diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php
index d93da9f138..1d50184f69 100644
a
|
b
|
function is_taxonomy_hierarchical( $taxonomy ) { |
334 | 334 | * @since 4.7.0 Introduced `show_in_rest`, 'rest_base' and 'rest_controller_class' |
335 | 335 | * arguments to register the Taxonomy in REST API. |
336 | 336 | * @since 5.1.0 Introduced `meta_box_sanitize_cb` argument. |
| 337 | * @since 5.3.0 Introduced `default_term` argument. |
337 | 338 | * |
338 | 339 | * @global array $wp_taxonomies Registered taxonomies. |
339 | 340 | * |
… |
… |
function is_taxonomy_hierarchical( $taxonomy ) { |
405 | 406 | * to post types, which confirms that the objects are published before |
406 | 407 | * counting them. Default _update_generic_term_count() for taxonomies |
407 | 408 | * attached to other object types, such as users. |
| 409 | * @type string|array $default_term { |
| 410 | * Default term to be used for the taxonomy. |
| 411 | * |
| 412 | * @type string $name Name of default term. |
| 413 | * @type string $slug Slug for default term (default empty). |
| 414 | * @type string $description Description for default term (default empty). |
| 415 | * } |
408 | 416 | * @type bool $_builtin This taxonomy is a "built-in" taxonomy. INTERNAL USE ONLY! |
409 | 417 | * Default false. |
410 | 418 | * } |
… |
… |
function register_taxonomy( $taxonomy, $object_type, $args = array() ) { |
431 | 439 | |
432 | 440 | $taxonomy_object->add_hooks(); |
433 | 441 | |
| 442 | // Add default term. |
| 443 | if ( ! empty( $taxonomy_object->default_term ) ) { |
| 444 | if ( $term = term_exists( $taxonomy_object->default_term['name'], $taxonomy ) ) { |
| 445 | update_option('default_taxonomy_' . $taxonomy_object->name, $term['term_id'] ); |
| 446 | } else { |
| 447 | $term = wp_insert_term( $taxonomy_object->default_term['name'], $taxonomy, array( |
| 448 | 'slug' => sanitize_title( $taxonomy_object->default_term['slug'] ), |
| 449 | 'description' => $taxonomy_object->default_term['description'], |
| 450 | )); |
| 451 | |
| 452 | // Update term id in options. |
| 453 | if ( ! is_wp_error( $term ) ) { |
| 454 | update_option('default_taxonomy_' . $taxonomy_object->name, $term['term_id']); |
| 455 | } |
| 456 | } |
| 457 | } |
| 458 | |
434 | 459 | /** |
435 | 460 | * Fires after a taxonomy is registered. |
436 | 461 | * |
… |
… |
function wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false ) { |
2438 | 2463 | $terms = array( $terms ); |
2439 | 2464 | } |
2440 | 2465 | |
| 2466 | // Add default term |
| 2467 | $taxonomy_obj = get_taxonomy( $taxonomy ); |
| 2468 | |
| 2469 | // Default term for this taxonomy. |
| 2470 | if ( empty( $terms ) && ! empty ( $taxonomy_obj->default_term ) && ! empty( $default_term_id = get_option( 'default_taxonomy_' . $taxonomy ) ) ) { |
| 2471 | $terms[] = (int) $default_term_id; |
| 2472 | } |
| 2473 | |
2441 | 2474 | if ( ! $append ) { |
2442 | 2475 | $old_tt_ids = wp_get_object_terms( |
2443 | 2476 | $object_id, |
diff --git a/tests/phpunit/tests/taxonomy.php b/tests/phpunit/tests/taxonomy.php
index 6d30ccf778..155d36be28 100644
a
|
b
|
class Tests_Taxonomy extends WP_UnitTestCase { |
958 | 958 | |
959 | 959 | $this->assertEquals( $problematic_term, $term_name ); |
960 | 960 | } |
| 961 | |
| 962 | /** |
| 963 | * Test default term for custom taxonomy. |
| 964 | * |
| 965 | * @ticket 43517 |
| 966 | */ |
| 967 | function test_default_term_for_custom_taxonomy() { |
| 968 | wp_set_current_user( self::factory()->user->create( array( 'role' => 'editor' ) ) ); |
| 969 | |
| 970 | $tax = 'custom-tax'; |
| 971 | |
| 972 | // Create custom taxonomy to test with. |
| 973 | register_taxonomy( |
| 974 | $tax, |
| 975 | 'post', |
| 976 | array( |
| 977 | 'hierarchical' => true, |
| 978 | 'public' => true, |
| 979 | 'default_term' => array( |
| 980 | 'name' => 'Default category', |
| 981 | 'slug' => 'default-category', |
| 982 | ), |
| 983 | ) |
| 984 | ); |
| 985 | |
| 986 | // Add post. |
| 987 | $post_id = wp_insert_post( |
| 988 | array( |
| 989 | 'post_title' => 'Foo', |
| 990 | 'post_type' => 'post', |
| 991 | ) |
| 992 | ); |
| 993 | |
| 994 | $term = wp_get_post_terms( $post_id, $tax ); |
| 995 | $this->assertSame( get_option( 'default_taxonomy_' . $tax ), $term[0]->term_id ); |
| 996 | |
| 997 | // Add custom post. |
| 998 | register_post_type( |
| 999 | 'post-custom-tax', |
| 1000 | array( 'taxonomies' => array( $tax ) ) |
| 1001 | ); |
| 1002 | |
| 1003 | $post_id = wp_insert_post( |
| 1004 | array( |
| 1005 | 'post_title' => 'Foo', |
| 1006 | 'post_type' => 'post-custom-tax', |
| 1007 | ) |
| 1008 | ); |
| 1009 | |
| 1010 | $term = wp_get_post_terms( $post_id, $tax ); |
| 1011 | $this->assertSame( get_option( 'default_taxonomy_' . $tax ), $term[0]->term_id ); |
| 1012 | } |
961 | 1013 | } |