wp/wp-includes/taxonomy.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     5  * @package WordPress
     5  * @package WordPress
     6  * @subpackage Taxonomy
     6  * @subpackage Taxonomy
     7  */
     7  */
     8 
     8 
     9 //
     9 //
    10 // Taxonomy Registration
    10 // Taxonomy registration.
    11 //
    11 //
    12 
    12 
    13 /**
    13 /**
    14  * Creates the initial taxonomies.
    14  * Creates the initial taxonomies.
    15  *
    15  *
    17  * backward compatibility reasons), and again on the {@see 'init'} action. We must
    17  * backward compatibility reasons), and again on the {@see 'init'} action. We must
    18  * avoid registering rewrite rules before the {@see 'init'} action.
    18  * avoid registering rewrite rules before the {@see 'init'} action.
    19  *
    19  *
    20  * @since 2.8.0
    20  * @since 2.8.0
    21  *
    21  *
    22  * @global WP_Rewrite $wp_rewrite The WordPress rewrite class.
    22  * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
    23  */
    23  */
    24 function create_initial_taxonomies() {
    24 function create_initial_taxonomies() {
    25 	global $wp_rewrite;
    25 	global $wp_rewrite;
    26 
    26 
    27 	if ( ! did_action( 'init' ) ) {
    27 	if ( ! did_action( 'init' ) ) {
   191  * @return string[]|WP_Taxonomy[] An array of taxonomy names or objects.
   191  * @return string[]|WP_Taxonomy[] An array of taxonomy names or objects.
   192  */
   192  */
   193 function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
   193 function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
   194 	global $wp_taxonomies;
   194 	global $wp_taxonomies;
   195 
   195 
   196 	$field = ( 'names' == $output ) ? 'name' : false;
   196 	$field = ( 'names' === $output ) ? 'name' : false;
   197 
   197 
   198 	return wp_filter_object_list( $wp_taxonomies, $args, $operator, $field );
   198 	return wp_filter_object_list( $wp_taxonomies, $args, $operator, $field );
   199 }
   199 }
   200 
   200 
   201 /**
   201 /**
   212  *
   212  *
   213  * @since 2.3.0
   213  * @since 2.3.0
   214  *
   214  *
   215  * @global array $wp_taxonomies The registered taxonomies.
   215  * @global array $wp_taxonomies The registered taxonomies.
   216  *
   216  *
   217  * @param array|string|WP_Post $object Name of the type of taxonomy object, or an object (row from posts)
   217  * @param string|string[]|WP_Post $object Name of the type of taxonomy object, or an object (row from posts)
   218  * @param string               $output Optional. The type of output to return in the array. Accepts either
   218  * @param string                  $output Optional. The type of output to return in the array. Accepts either
   219  *                                     taxonomy 'names' or 'objects'. Default 'names'.
   219  *                                        'names' or 'objects'. Default 'names'.
   220  * @return array The names of all taxonomy of $object_type.
   220  * @return string[]|WP_Taxonomy[] The names or objects of all taxonomies of `$object_type`.
   221  */
   221  */
   222 function get_object_taxonomies( $object, $output = 'names' ) {
   222 function get_object_taxonomies( $object, $output = 'names' ) {
   223 	global $wp_taxonomies;
   223 	global $wp_taxonomies;
   224 
   224 
   225 	if ( is_object( $object ) ) {
   225 	if ( is_object( $object ) ) {
   226 		if ( $object->post_type == 'attachment' ) {
   226 		if ( 'attachment' === $object->post_type ) {
   227 			return get_attachment_taxonomies( $object, $output );
   227 			return get_attachment_taxonomies( $object, $output );
   228 		}
   228 		}
   229 		$object = $object->post_type;
   229 		$object = $object->post_type;
   230 	}
   230 	}
   231 
   231 
   232 	$object = (array) $object;
   232 	$object = (array) $object;
   233 
   233 
   234 	$taxonomies = array();
   234 	$taxonomies = array();
   235 	foreach ( (array) $wp_taxonomies as $tax_name => $tax_obj ) {
   235 	foreach ( (array) $wp_taxonomies as $tax_name => $tax_obj ) {
   236 		if ( array_intersect( $object, (array) $tax_obj->object_type ) ) {
   236 		if ( array_intersect( $object, (array) $tax_obj->object_type ) ) {
   237 			if ( 'names' == $output ) {
   237 			if ( 'names' === $output ) {
   238 				$taxonomies[] = $tax_name;
   238 				$taxonomies[] = $tax_name;
   239 			} else {
   239 			} else {
   240 				$taxonomies[ $tax_name ] = $tax_obj;
   240 				$taxonomies[ $tax_name ] = $tax_obj;
   241 			}
   241 			}
   242 		}
   242 		}
   332  * @since 4.4.0 The `public` argument now controls whether the taxonomy can be queried on the front end.
   332  * @since 4.4.0 The `public` argument now controls whether the taxonomy can be queried on the front end.
   333  * @since 4.5.0 Introduced `publicly_queryable` argument.
   333  * @since 4.5.0 Introduced `publicly_queryable` argument.
   334  * @since 4.7.0 Introduced `show_in_rest`, 'rest_base' and 'rest_controller_class'
   334  * @since 4.7.0 Introduced `show_in_rest`, 'rest_base' and 'rest_controller_class'
   335  *              arguments to register the Taxonomy in REST API.
   335  *              arguments to register the Taxonomy in REST API.
   336  * @since 5.1.0 Introduced `meta_box_sanitize_cb` argument.
   336  * @since 5.1.0 Introduced `meta_box_sanitize_cb` argument.
       
   337  * @since 5.4.0 Added the registered taxonomy object as a return value.
       
   338  * @since 5.5.0 Introduced `default_term` argument.
   337  *
   339  *
   338  * @global array $wp_taxonomies Registered taxonomies.
   340  * @global array $wp_taxonomies Registered taxonomies.
   339  *
   341  *
   340  * @param string       $taxonomy    Taxonomy key, must not exceed 32 characters.
   342  * @param string       $taxonomy    Taxonomy key, must not exceed 32 characters.
   341  * @param array|string $object_type Object type or array of object types with which the taxonomy should be associated.
   343  * @param array|string $object_type Object type or array of object types with which the taxonomy should be associated.
   361  *                                                shown as a submenu of the object type menu. If false, no menu is shown.
   363  *                                                shown as a submenu of the object type menu. If false, no menu is shown.
   362  *                                                `$show_ui` must be true. If not set, default is inherited from `$show_ui`
   364  *                                                `$show_ui` must be true. If not set, default is inherited from `$show_ui`
   363  *                                                (default true).
   365  *                                                (default true).
   364  *     @type bool          $show_in_nav_menus     Makes this taxonomy available for selection in navigation menus. If not
   366  *     @type bool          $show_in_nav_menus     Makes this taxonomy available for selection in navigation menus. If not
   365  *                                                set, the default is inherited from `$public` (default true).
   367  *                                                set, the default is inherited from `$public` (default true).
   366  *     @type bool          $show_in_rest          Whether to include the taxonomy in the REST API.
   368  *     @type bool          $show_in_rest          Whether to include the taxonomy in the REST API. Set this to true
       
   369  *                                                for the taxonomy to be available in the block editor.
   367  *     @type string        $rest_base             To change the base url of REST API route. Default is $taxonomy.
   370  *     @type string        $rest_base             To change the base url of REST API route. Default is $taxonomy.
   368  *     @type string        $rest_controller_class REST API Controller class name. Default is 'WP_REST_Terms_Controller'.
   371  *     @type string        $rest_controller_class REST API Controller class name. Default is 'WP_REST_Terms_Controller'.
   369  *     @type bool          $show_tagcloud         Whether to list the taxonomy in the Tag Cloud Widget controls. If not set,
   372  *     @type bool          $show_tagcloud         Whether to list the taxonomy in the Tag Cloud Widget controls. If not set,
   370  *                                                the default is inherited from `$show_ui` (default true).
   373  *                                                the default is inherited from `$show_ui` (default true).
   371  *     @type bool          $show_in_quick_edit    Whether to show the taxonomy in the quick/bulk edit panel. It not set,
   374  *     @type bool          $show_in_quick_edit    Whether to show the taxonomy in the quick/bulk edit panel. It not set,
   394  *         @type string $slug         Customize the permastruct slug. Default `$taxonomy` key.
   397  *         @type string $slug         Customize the permastruct slug. Default `$taxonomy` key.
   395  *         @type bool   $with_front   Should the permastruct be prepended with WP_Rewrite::$front. Default true.
   398  *         @type bool   $with_front   Should the permastruct be prepended with WP_Rewrite::$front. Default true.
   396  *         @type bool   $hierarchical Either hierarchical rewrite tag or not. Default false.
   399  *         @type bool   $hierarchical Either hierarchical rewrite tag or not. Default false.
   397  *         @type int    $ep_mask      Assign an endpoint mask. Default `EP_NONE`.
   400  *         @type int    $ep_mask      Assign an endpoint mask. Default `EP_NONE`.
   398  *     }
   401  *     }
   399  *     @type string        $query_var             Sets the query var key for this taxonomy. Default `$taxonomy` key. If
   402  *     @type string|bool   $query_var             Sets the query var key for this taxonomy. Default `$taxonomy` key. If
   400  *                                                false, a taxonomy cannot be loaded at `?{query_var}={term_slug}`. If a
   403  *                                                false, a taxonomy cannot be loaded at `?{query_var}={term_slug}`. If a
   401  *                                                string, the query `?{query_var}={term_slug}` will be valid.
   404  *                                                string, the query `?{query_var}={term_slug}` will be valid.
   402  *     @type callable      $update_count_callback Works much like a hook, in that it will be called when the count is
   405  *     @type callable      $update_count_callback Works much like a hook, in that it will be called when the count is
   403  *                                                updated. Default _update_post_term_count() for taxonomies attached
   406  *                                                updated. Default _update_post_term_count() for taxonomies attached
   404  *                                                to post types, which confirms that the objects are published before
   407  *                                                to post types, which confirms that the objects are published before
   405  *                                                counting them. Default _update_generic_term_count() for taxonomies
   408  *                                                counting them. Default _update_generic_term_count() for taxonomies
   406  *                                                attached to other object types, such as users.
   409  *                                                attached to other object types, such as users.
       
   410  *     @type string|array  $default_term {
       
   411  *         Default term to be used for the taxonomy.
       
   412  *
       
   413  *         @type string $name         Name of default term.
       
   414  *         @type string $slug         Slug for default term. Default empty.
       
   415  *         @type string $description  Description for default term. Default empty.
       
   416  *     }
   407  *     @type bool          $_builtin              This taxonomy is a "built-in" taxonomy. INTERNAL USE ONLY!
   417  *     @type bool          $_builtin              This taxonomy is a "built-in" taxonomy. INTERNAL USE ONLY!
   408  *                                                Default false.
   418  *                                                Default false.
   409  * }
   419  * }
   410  * @return WP_Error|void WP_Error, if errors.
   420  * @return WP_Taxonomy|WP_Error The registered taxonomy object on success, WP_Error object on failure.
   411  */
   421  */
   412 function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
   422 function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
   413 	global $wp_taxonomies;
   423 	global $wp_taxonomies;
   414 
   424 
   415 	if ( ! is_array( $wp_taxonomies ) ) {
   425 	if ( ! is_array( $wp_taxonomies ) ) {
   428 
   438 
   429 	$wp_taxonomies[ $taxonomy ] = $taxonomy_object;
   439 	$wp_taxonomies[ $taxonomy ] = $taxonomy_object;
   430 
   440 
   431 	$taxonomy_object->add_hooks();
   441 	$taxonomy_object->add_hooks();
   432 
   442 
       
   443 	// Add default term.
       
   444 	if ( ! empty( $taxonomy_object->default_term ) ) {
       
   445 		$term = term_exists( $taxonomy_object->default_term['name'], $taxonomy );
       
   446 		if ( $term ) {
       
   447 			update_option( 'default_term_' . $taxonomy_object->name, $term['term_id'] );
       
   448 		} else {
       
   449 			$term = wp_insert_term(
       
   450 				$taxonomy_object->default_term['name'],
       
   451 				$taxonomy,
       
   452 				array(
       
   453 					'slug'        => sanitize_title( $taxonomy_object->default_term['slug'] ),
       
   454 					'description' => $taxonomy_object->default_term['description'],
       
   455 				)
       
   456 			);
       
   457 
       
   458 			// Update `term_id` in options.
       
   459 			if ( ! is_wp_error( $term ) ) {
       
   460 				update_option( 'default_term_' . $taxonomy_object->name, $term['term_id'] );
       
   461 			}
       
   462 		}
       
   463 	}
       
   464 
   433 	/**
   465 	/**
   434 	 * Fires after a taxonomy is registered.
   466 	 * Fires after a taxonomy is registered.
   435 	 *
   467 	 *
   436 	 * @since 3.3.0
   468 	 * @since 3.3.0
   437 	 *
   469 	 *
   438 	 * @param string       $taxonomy    Taxonomy slug.
   470 	 * @param string       $taxonomy    Taxonomy slug.
   439 	 * @param array|string $object_type Object type or array of object types.
   471 	 * @param array|string $object_type Object type or array of object types.
   440 	 * @param array        $args        Array of taxonomy registration arguments.
   472 	 * @param array        $args        Array of taxonomy registration arguments.
   441 	 */
   473 	 */
   442 	do_action( 'registered_taxonomy', $taxonomy, $object_type, (array) $taxonomy_object );
   474 	do_action( 'registered_taxonomy', $taxonomy, $object_type, (array) $taxonomy_object );
       
   475 
       
   476 	return $taxonomy_object;
   443 }
   477 }
   444 
   478 
   445 /**
   479 /**
   446  * Unregisters a taxonomy.
   480  * Unregisters a taxonomy.
   447  *
   481  *
   469 
   503 
   470 	global $wp_taxonomies;
   504 	global $wp_taxonomies;
   471 
   505 
   472 	$taxonomy_object->remove_rewrite_rules();
   506 	$taxonomy_object->remove_rewrite_rules();
   473 	$taxonomy_object->remove_hooks();
   507 	$taxonomy_object->remove_hooks();
       
   508 
       
   509 	// Remove custom taxonomy default term option.
       
   510 	if ( ! empty( $taxonomy_object->default_term ) ) {
       
   511 		delete_option( 'default_term_' . $taxonomy_object->name );
       
   512 	}
   474 
   513 
   475 	// Remove the taxonomy.
   514 	// Remove the taxonomy.
   476 	unset( $wp_taxonomies[ $taxonomy ] );
   515 	unset( $wp_taxonomies[ $taxonomy ] );
   477 
   516 
   478 	/**
   517 	/**
   561 		'choose_from_most_used'      => array( __( 'Choose from the most used tags' ), null ),
   600 		'choose_from_most_used'      => array( __( 'Choose from the most used tags' ), null ),
   562 		'not_found'                  => array( __( 'No tags found.' ), __( 'No categories found.' ) ),
   601 		'not_found'                  => array( __( 'No tags found.' ), __( 'No categories found.' ) ),
   563 		'no_terms'                   => array( __( 'No tags' ), __( 'No categories' ) ),
   602 		'no_terms'                   => array( __( 'No tags' ), __( 'No categories' ) ),
   564 		'items_list_navigation'      => array( __( 'Tags list navigation' ), __( 'Categories list navigation' ) ),
   603 		'items_list_navigation'      => array( __( 'Tags list navigation' ), __( 'Categories list navigation' ) ),
   565 		'items_list'                 => array( __( 'Tags list' ), __( 'Categories list' ) ),
   604 		'items_list'                 => array( __( 'Tags list' ), __( 'Categories list' ) ),
   566 		/* translators: Tab heading when selecting from the most used terms */
   605 		/* translators: Tab heading when selecting from the most used terms. */
   567 		'most_used'                  => array( _x( 'Most Used', 'tags' ), _x( 'Most Used', 'categories' ) ),
   606 		'most_used'                  => array( _x( 'Most Used', 'tags' ), _x( 'Most Used', 'categories' ) ),
   568 		'back_to_items'              => array( __( '← Back to Tags' ), __( '← Back to Categories' ) ),
   607 		'back_to_items'              => array( __( '← Back to Tags' ), __( '← Back to Categories' ) ),
   569 	);
   608 	);
   570 	$nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
   609 	$nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
   571 
   610 
   614 
   653 
   615 	if ( ! get_post_type_object( $object_type ) ) {
   654 	if ( ! get_post_type_object( $object_type ) ) {
   616 		return false;
   655 		return false;
   617 	}
   656 	}
   618 
   657 
   619 	if ( ! in_array( $object_type, $wp_taxonomies[ $taxonomy ]->object_type ) ) {
   658 	if ( ! in_array( $object_type, $wp_taxonomies[ $taxonomy ]->object_type, true ) ) {
   620 		$wp_taxonomies[ $taxonomy ]->object_type[] = $object_type;
   659 		$wp_taxonomies[ $taxonomy ]->object_type[] = $object_type;
   621 	}
   660 	}
   622 
   661 
   623 	// Filter out empties.
   662 	// Filter out empties.
   624 	$wp_taxonomies[ $taxonomy ]->object_type = array_filter( $wp_taxonomies[ $taxonomy ]->object_type );
   663 	$wp_taxonomies[ $taxonomy ]->object_type = array_filter( $wp_taxonomies[ $taxonomy ]->object_type );
   677 
   716 
   678 	return true;
   717 	return true;
   679 }
   718 }
   680 
   719 
   681 //
   720 //
   682 // Term API
   721 // Term API.
   683 //
   722 //
   684 
   723 
   685 /**
   724 /**
   686  * Retrieve object_ids of valid taxonomy and term.
   725  * Retrieve object_ids of valid taxonomy and term.
   687  *
   726  *
   699  *
   738  *
   700  * @since 2.3.0
   739  * @since 2.3.0
   701  *
   740  *
   702  * @global wpdb $wpdb WordPress database abstraction object.
   741  * @global wpdb $wpdb WordPress database abstraction object.
   703  *
   742  *
   704  * @param int|array    $term_ids   Term id or array of term ids of terms that will be used.
   743  * @param int|array    $term_ids   Term ID or array of term IDs of terms that will be used.
   705  * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names.
   744  * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names.
   706  * @param array|string $args       Change the order of the object_ids, either ASC or DESC.
   745  * @param array|string $args       Change the order of the object_ids, either ASC or DESC.
   707  * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success.
   746  * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success.
   708  *  the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
   747  *  the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
   709  */
   748  */
   723 	}
   762 	}
   724 
   763 
   725 	$defaults = array( 'order' => 'ASC' );
   764 	$defaults = array( 'order' => 'ASC' );
   726 	$args     = wp_parse_args( $args, $defaults );
   765 	$args     = wp_parse_args( $args, $defaults );
   727 
   766 
   728 	$order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC';
   767 	$order = ( 'desc' === strtolower( $args['order'] ) ) ? 'DESC' : 'ASC';
   729 
   768 
   730 	$term_ids = array_map( 'intval', $term_ids );
   769 	$term_ids = array_map( 'intval', $term_ids );
   731 
   770 
   732 	$taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'";
   771 	$taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'";
   733 	$term_ids   = "'" . implode( "', '", $term_ids ) . "'";
   772 	$term_ids   = "'" . implode( "', '", $term_ids ) . "'";
   798  * @since 4.4.0 Converted to return a WP_Term object if `$output` is `OBJECT`.
   837  * @since 4.4.0 Converted to return a WP_Term object if `$output` is `OBJECT`.
   799  *              The `$taxonomy` parameter was made optional.
   838  *              The `$taxonomy` parameter was made optional.
   800  *
   839  *
   801  * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
   840  * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
   802  *
   841  *
   803  * @param int|WP_Term|object $term If integer, term data will be fetched from the database, or from the cache if
   842  * @param int|WP_Term|object $term     If integer, term data will be fetched from the database,
   804  *                                 available. If stdClass object (as in the results of a database query), will apply
   843  *                                     or from the cache if available.
   805  *                                 filters and return a `WP_Term` object corresponding to the `$term` data. If `WP_Term`,
   844  *                                     If stdClass object (as in the results of a database query),
   806  *                                 will return `$term`.
   845  *                                     will apply filters and return a `WP_Term` object with the `$term` data.
   807  * @param string     $taxonomy Optional. Taxonomy name that $term is part of.
   846  *                                     If `WP_Term`, will return `$term`.
   808  * @param string     $output   Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
   847  * @param string             $taxonomy Optional. Taxonomy name that `$term` is part of.
   809  *                             a WP_Term object, an associative array, or a numeric array, respectively. Default OBJECT.
   848  * @param string             $output   Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
   810  * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
   849  *                                     correspond to a WP_Term object, an associative array, or a numeric array,
   811  * @return array|WP_Term|WP_Error|null Object of the type specified by `$output` on success. When `$output` is 'OBJECT',
   850  *                                     respectively. Default OBJECT.
   812  *                                     a WP_Term instance is returned. If taxonomy does not exist, a WP_Error is
   851  * @param string             $filter   Optional. How to sanitize term fields. Default 'raw'.
   813  *                                     returned. Returns null for miscellaneous failure.
   852  * @return WP_Term|array|WP_Error|null WP_Term instance (or array) on success, depending on the `$output` value.
       
   853  *                                     WP_Error if `$taxonomy` does not exist. Null for miscellaneous failure.
   814  */
   854  */
   815 function get_term( $term, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
   855 function get_term( $term, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
   816 	if ( empty( $term ) ) {
   856 	if ( empty( $term ) ) {
   817 		return new WP_Error( 'invalid_term', __( 'Empty Term.' ) );
   857 		return new WP_Error( 'invalid_term', __( 'Empty Term.' ) );
   818 	}
   858 	}
   874 	}
   914 	}
   875 
   915 
   876 	// Sanitize term, according to the specified filter.
   916 	// Sanitize term, according to the specified filter.
   877 	$_term->filter( $filter );
   917 	$_term->filter( $filter );
   878 
   918 
   879 	if ( $output == ARRAY_A ) {
   919 	if ( ARRAY_A === $output ) {
   880 		return $_term->to_array();
   920 		return $_term->to_array();
   881 	} elseif ( $output == ARRAY_N ) {
   921 	} elseif ( ARRAY_N === $output ) {
   882 		return array_values( $_term->to_array() );
   922 		return array_values( $_term->to_array() );
   883 	}
   923 	}
   884 
   924 
   885 	return $_term;
   925 	return $_term;
   886 }
   926 }
   907  * @todo Better formatting for DocBlock.
   947  * @todo Better formatting for DocBlock.
   908  *
   948  *
   909  * @since 2.3.0
   949  * @since 2.3.0
   910  * @since 4.4.0 `$taxonomy` is optional if `$field` is 'term_taxonomy_id'. Converted to return
   950  * @since 4.4.0 `$taxonomy` is optional if `$field` is 'term_taxonomy_id'. Converted to return
   911  *              a WP_Term object if `$output` is `OBJECT`.
   951  *              a WP_Term object if `$output` is `OBJECT`.
       
   952  * @since 5.5.0 Added 'ID' as an alias of 'id' for the `$field` parameter.
   912  *
   953  *
   913  * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
   954  * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
   914  *
   955  *
   915  * @param string     $field    Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
   956  * @param string     $field    Either 'slug', 'name', 'id' or 'ID' (term_id), or 'term_taxonomy_id'.
   916  * @param string|int $value    Search for this term value
   957  * @param string|int $value    Search for this term value.
   917  * @param string     $taxonomy Taxonomy name. Optional, if `$field` is 'term_taxonomy_id'.
   958  * @param string     $taxonomy Taxonomy name. Optional, if `$field` is 'term_taxonomy_id'.
   918  * @param string     $output   Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
   959  * @param string     $output   Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
   919  *                             a WP_Term object, an associative array, or a numeric array, respectively. Default OBJECT.
   960  *                             correspond to a WP_Term object, an associative array, or a numeric array,
   920  * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
   961  *                             respectively. Default OBJECT.
   921  * @return WP_Term|array|false WP_Term instance (or array) on success. Will return false if `$taxonomy` does not exist
   962  * @param string     $filter   Optional. How to sanitize term fields. Default 'raw'.
   922  *                             or `$term` was not found.
   963  * @return WP_Term|array|false WP_Term instance (or array) on success, depending on the `$output` value.
       
   964  *                             False if `$taxonomy` does not exist or `$term` was not found.
   923  */
   965  */
   924 function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
   966 function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
   925 
   967 
   926 	// 'term_taxonomy_id' lookups don't require taxonomy checks.
   968 	// 'term_taxonomy_id' lookups don't require taxonomy checks.
   927 	if ( 'term_taxonomy_id' !== $field && ! taxonomy_exists( $taxonomy ) ) {
   969 	if ( 'term_taxonomy_id' !== $field && ! taxonomy_exists( $taxonomy ) ) {
   935 		if ( 0 === strlen( $value ) ) {
   977 		if ( 0 === strlen( $value ) ) {
   936 			return false;
   978 			return false;
   937 		}
   979 		}
   938 	}
   980 	}
   939 
   981 
   940 	if ( 'id' === $field || 'term_id' === $field ) {
   982 	if ( 'id' === $field || 'ID' === $field || 'term_id' === $field ) {
   941 		$term = get_term( (int) $value, $taxonomy, $output, $filter );
   983 		$term = get_term( (int) $value, $taxonomy, $output, $filter );
   942 		if ( is_wp_error( $term ) || null === $term ) {
   984 		if ( is_wp_error( $term ) || null === $term ) {
   943 			$term = false;
   985 			$term = false;
   944 		}
   986 		}
   945 		return $term;
   987 		return $term;
   974 		return false;
  1016 		return false;
   975 	}
  1017 	}
   976 
  1018 
   977 	$term = array_shift( $terms );
  1019 	$term = array_shift( $terms );
   978 
  1020 
   979 	// In the case of 'term_taxonomy_id', override the provided `$taxonomy` with whatever we find in the db.
  1021 	// In the case of 'term_taxonomy_id', override the provided `$taxonomy` with whatever we find in the DB.
   980 	if ( 'term_taxonomy_id' === $field ) {
  1022 	if ( 'term_taxonomy_id' === $field ) {
   981 		$taxonomy = $term->taxonomy;
  1023 		$taxonomy = $term->taxonomy;
   982 	}
  1024 	}
   983 
  1025 
   984 	return get_term( $term, $taxonomy, $output, $filter );
  1026 	return get_term( $term, $taxonomy, $output, $filter );
  1012 	}
  1054 	}
  1013 
  1055 
  1014 	$children = $terms[ $term_id ];
  1056 	$children = $terms[ $term_id ];
  1015 
  1057 
  1016 	foreach ( (array) $terms[ $term_id ] as $child ) {
  1058 	foreach ( (array) $terms[ $term_id ] as $child ) {
  1017 		if ( $term_id == $child ) {
  1059 		if ( $term_id === $child ) {
  1018 			continue;
  1060 			continue;
  1019 		}
  1061 		}
  1020 
  1062 
  1021 		if ( isset( $terms[ $child ] ) ) {
  1063 		if ( isset( $terms[ $child ] ) ) {
  1022 			$children = array_merge( $children, get_term_children( $child, $taxonomy ) );
  1064 			$children = array_merge( $children, get_term_children( $child, $taxonomy ) );
  1037  * @see sanitize_term_field()
  1079  * @see sanitize_term_field()
  1038  *
  1080  *
  1039  * @param string      $field    Term field to fetch.
  1081  * @param string      $field    Term field to fetch.
  1040  * @param int|WP_Term $term     Term ID or object.
  1082  * @param int|WP_Term $term     Term ID or object.
  1041  * @param string      $taxonomy Optional. Taxonomy Name. Default empty.
  1083  * @param string      $taxonomy Optional. Taxonomy Name. Default empty.
  1042  * @param string      $context  Optional, default is display. Look at sanitize_term_field() for available options.
  1084  * @param string      $context  Optional. How to sanitize term fields. Look at sanitize_term_field() for available options.
       
  1085  *                              Default 'display'.
  1043  * @return string|int|null|WP_Error Will return an empty string if $term is not an object or if $field is not set in $term.
  1086  * @return string|int|null|WP_Error Will return an empty string if $term is not an object or if $field is not set in $term.
  1044  */
  1087  */
  1045 function get_term_field( $field, $term, $taxonomy = '', $context = 'display' ) {
  1088 function get_term_field( $field, $term, $taxonomy = '', $context = 'display' ) {
  1046 	$term = get_term( $term, $taxonomy );
  1089 	$term = get_term( $term, $taxonomy );
  1047 	if ( is_wp_error( $term ) ) {
  1090 	if ( is_wp_error( $term ) ) {
  1124  *              Introduced 'meta_key' and 'meta_value' parameters. Introduced the ability to order results by metadata.
  1167  *              Introduced 'meta_key' and 'meta_value' parameters. Introduced the ability to order results by metadata.
  1125  * @since 4.8.0 Introduced 'suppress_filter' parameter.
  1168  * @since 4.8.0 Introduced 'suppress_filter' parameter.
  1126  *
  1169  *
  1127  * @internal The `$deprecated` parameter is parsed for backward compatibility only.
  1170  * @internal The `$deprecated` parameter is parsed for backward compatibility only.
  1128  *
  1171  *
  1129  * @param string|array $args       Optional. Array or string of arguments. See WP_Term_Query::__construct()
  1172  * @param array|string $args       Optional. Array or string of arguments. See WP_Term_Query::__construct()
  1130  *                                 for information on accepted arguments. Default empty.
  1173  *                                 for information on accepted arguments. Default empty.
  1131  * @param array        $deprecated Argument array, when using the legacy function parameter format. If present, this
  1174  * @param array|string $deprecated Argument array, when using the legacy function parameter format. If present,
  1132  *                                 parameter will be interpreted as `$args`, and the first function parameter will
  1175  *                                 this parameter will be interpreted as `$args`, and the first function parameter
  1133  *                                 be parsed as a taxonomy or array of taxonomies.
  1176  *                                 will be parsed as a taxonomy or array of taxonomies.
  1134  * @return array|int|WP_Error List of WP_Term instances and their children. Will return WP_Error, if any of $taxonomies
  1177  * @return WP_Term[]|int|WP_Error Array of WP_Term instances, a count thereof,
  1135  *                            do not exist.
  1178  *                                or WP_Error if any of the taxonomies do not exist.
  1136  */
  1179  */
  1137 function get_terms( $args = array(), $deprecated = '' ) {
  1180 function get_terms( $args = array(), $deprecated = '' ) {
  1138 	$term_query = new WP_Term_Query();
  1181 	$term_query = new WP_Term_Query();
  1139 
  1182 
  1140 	$defaults = array(
  1183 	$defaults = array(
  1205  *
  1248  *
  1206  * @since 4.4.0
  1249  * @since 4.4.0
  1207  *
  1250  *
  1208  * @param int    $term_id    Term ID.
  1251  * @param int    $term_id    Term ID.
  1209  * @param string $meta_key   Metadata name.
  1252  * @param string $meta_key   Metadata name.
  1210  * @param mixed  $meta_value Metadata value.
  1253  * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
  1211  * @param bool   $unique     Optional. Whether to bail if an entry with the same key is found for the term.
  1254  * @param bool   $unique     Optional. Whether the same key should not be added.
  1212  *                           Default false.
  1255  *                           Default false.
  1213  * @return int|WP_Error|bool Meta ID on success. WP_Error when term_id is ambiguous between taxonomies.
  1256  * @return int|false|WP_Error Meta ID on success, false on failure.
  1214  *                           False on failure.
  1257  *                            WP_Error when term_id is ambiguous between taxonomies.
  1215  */
  1258  */
  1216 function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
  1259 function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
  1217 	if ( wp_term_is_shared( $term_id ) ) {
  1260 	if ( wp_term_is_shared( $term_id ) ) {
  1218 		return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.' ), $term_id );
  1261 		return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.' ), $term_id );
  1219 	}
  1262 	}
  1226  *
  1269  *
  1227  * @since 4.4.0
  1270  * @since 4.4.0
  1228  *
  1271  *
  1229  * @param int    $term_id    Term ID.
  1272  * @param int    $term_id    Term ID.
  1230  * @param string $meta_key   Metadata name.
  1273  * @param string $meta_key   Metadata name.
  1231  * @param mixed  $meta_value Optional. Metadata value. If provided, rows will only be removed that match the value.
  1274  * @param mixed  $meta_value Optional. Metadata value. If provided,
       
  1275  *                           rows will only be removed that match the value.
       
  1276  *                           Must be serializable if non-scalar. Default empty.
  1232  * @return bool True on success, false on failure.
  1277  * @return bool True on success, false on failure.
  1233  */
  1278  */
  1234 function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
  1279 function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
  1235 	return delete_metadata( 'term', $term_id, $meta_key, $meta_value );
  1280 	return delete_metadata( 'term', $term_id, $meta_key, $meta_value );
  1236 }
  1281 }
  1239  * Retrieves metadata for a term.
  1284  * Retrieves metadata for a term.
  1240  *
  1285  *
  1241  * @since 4.4.0
  1286  * @since 4.4.0
  1242  *
  1287  *
  1243  * @param int    $term_id Term ID.
  1288  * @param int    $term_id Term ID.
  1244  * @param string $key     Optional. The meta key to retrieve. If no key is provided, fetches all metadata for the term.
  1289  * @param string $key     Optional. The meta key to retrieve. By default,
  1245  * @param bool   $single  Whether to return a single value. If false, an array of all values matching the
  1290  *                        returns data for all keys. Default empty.
  1246  *                        `$term_id`/`$key` pair will be returned. Default: false.
  1291  * @param bool   $single  Optional. Whether to return a single value.
  1247  * @return mixed If `$single` is false, an array of metadata values. If `$single` is true, a single metadata value.
  1292  *                        This parameter has no effect if $key is not specified.
       
  1293  *                        Default false.
       
  1294  * @return mixed An array if $single is false. The value of the meta field
       
  1295  *               if $single is true. False for an invalid $term_id.
  1248  */
  1296  */
  1249 function get_term_meta( $term_id, $key = '', $single = false ) {
  1297 function get_term_meta( $term_id, $key = '', $single = false ) {
  1250 	return get_metadata( 'term', $term_id, $key, $single );
  1298 	return get_metadata( 'term', $term_id, $key, $single );
  1251 }
  1299 }
  1252 
  1300 
  1259  *
  1307  *
  1260  * @since 4.4.0
  1308  * @since 4.4.0
  1261  *
  1309  *
  1262  * @param int    $term_id    Term ID.
  1310  * @param int    $term_id    Term ID.
  1263  * @param string $meta_key   Metadata key.
  1311  * @param string $meta_key   Metadata key.
  1264  * @param mixed  $meta_value Metadata value.
  1312  * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
  1265  * @param mixed  $prev_value Optional. Previous value to check before removing.
  1313  * @param mixed  $prev_value Optional. Previous value to check before updating.
  1266  * @return int|WP_Error|bool Meta ID if the key didn't previously exist. True on successful update.
  1314  *                           If specified, only update existing metadata entries with
  1267  *                           WP_Error when term_id is ambiguous between taxonomies. False on failure.
  1315  *                           this value. Otherwise, update all entries. Default empty.
       
  1316  * @return int|bool|WP_Error Meta ID if the key didn't exist. true on successful update,
       
  1317  *                           false on failure or if the value passed to the function
       
  1318  *                           is the same as the one that is already in the database.
       
  1319  *                           WP_Error when term_id is ambiguous between taxonomies.
  1268  */
  1320  */
  1269 function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
  1321 function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
  1270 	if ( wp_term_is_shared( $term_id ) ) {
  1322 	if ( wp_term_is_shared( $term_id ) ) {
  1271 		return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.' ), $term_id );
  1323 		return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.' ), $term_id );
  1272 	}
  1324 	}
  1281  * Subsequent calls to `get_term_meta()` will not need to query the database.
  1333  * Subsequent calls to `get_term_meta()` will not need to query the database.
  1282  *
  1334  *
  1283  * @since 4.4.0
  1335  * @since 4.4.0
  1284  *
  1336  *
  1285  * @param array $term_ids List of term IDs.
  1337  * @param array $term_ids List of term IDs.
  1286  * @return array|false Returns false if there is nothing to update. Returns an array of metadata on success.
  1338  * @return array|false An array of metadata on success, false if there is nothing to update.
  1287  */
  1339  */
  1288 function update_termmeta_cache( $term_ids ) {
  1340 function update_termmeta_cache( $term_ids ) {
  1289 	return update_meta_cache( 'term', $term_ids );
  1341 	return update_meta_cache( 'term', $term_ids );
  1290 }
  1342 }
  1291 
  1343 
  1342 function unregister_term_meta( $taxonomy, $meta_key ) {
  1394 function unregister_term_meta( $taxonomy, $meta_key ) {
  1343 	return unregister_meta_key( 'term', $meta_key, $taxonomy );
  1395 	return unregister_meta_key( 'term', $meta_key, $taxonomy );
  1344 }
  1396 }
  1345 
  1397 
  1346 /**
  1398 /**
  1347  * Determines whether a term exists.
  1399  * Determines whether a taxonomy term exists.
  1348  *
  1400  *
  1349  * Formerly is_term(), introduced in 2.3.0.
  1401  * Formerly is_term(), introduced in 2.3.0.
  1350  *
  1402  *
  1351  * For more information on this and similar theme functions, check out
  1403  * For more information on this and similar theme functions, check out
  1352  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
  1404  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
  1355  * @since 3.0.0
  1407  * @since 3.0.0
  1356  *
  1408  *
  1357  * @global wpdb $wpdb WordPress database abstraction object.
  1409  * @global wpdb $wpdb WordPress database abstraction object.
  1358  *
  1410  *
  1359  * @param int|string $term     The term to check. Accepts term ID, slug, or name.
  1411  * @param int|string $term     The term to check. Accepts term ID, slug, or name.
  1360  * @param string     $taxonomy The taxonomy name to use
  1412  * @param string     $taxonomy Optional. The taxonomy name to use.
  1361  * @param int        $parent   Optional. ID of parent term under which to confine the exists search.
  1413  * @param int        $parent   Optional. ID of parent term under which to confine the exists search.
  1362  * @return mixed Returns null if the term does not exist. Returns the term ID
  1414  * @return mixed Returns null if the term does not exist.
  1363  *               if no taxonomy is specified and the term ID exists. Returns
  1415  *               Returns the term ID if no taxonomy is specified and the term ID exists.
  1364  *               an array of the term ID and the term taxonomy ID if the taxonomy
  1416  *               Returns an array of the term ID and the term taxonomy ID if the taxonomy is specified and the pairing exists.
  1365  *               is specified and the pairing exists.
  1417  *               Returns 0 if term ID 0 is passed to the function.
  1366  */
  1418  */
  1367 function term_exists( $term, $taxonomy = '', $parent = null ) {
  1419 function term_exists( $term, $taxonomy = '', $parent = null ) {
  1368 	global $wpdb;
  1420 	global $wpdb;
  1369 
  1421 
  1370 	$select     = "SELECT term_id FROM $wpdb->terms as t WHERE ";
  1422 	$select     = "SELECT term_id FROM $wpdb->terms as t WHERE ";
  1371 	$tax_select = "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE ";
  1423 	$tax_select = "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE ";
  1372 
  1424 
  1373 	if ( is_int( $term ) ) {
  1425 	if ( is_int( $term ) ) {
  1374 		if ( 0 == $term ) {
  1426 		if ( 0 === $term ) {
  1375 			return 0;
  1427 			return 0;
  1376 		}
  1428 		}
  1377 		$where = 't.term_id = %d';
  1429 		$where = 't.term_id = %d';
  1378 		if ( ! empty( $taxonomy ) ) {
  1430 		if ( ! empty( $taxonomy ) ) {
       
  1431 			// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
  1379 			return $wpdb->get_row( $wpdb->prepare( $tax_select . $where . ' AND tt.taxonomy = %s', $term, $taxonomy ), ARRAY_A );
  1432 			return $wpdb->get_row( $wpdb->prepare( $tax_select . $where . ' AND tt.taxonomy = %s', $term, $taxonomy ), ARRAY_A );
  1380 		} else {
  1433 		} else {
  1381 			return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
  1434 			return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
  1382 		}
  1435 		}
  1383 	}
  1436 	}
  1401 		}
  1454 		}
  1402 
  1455 
  1403 		$where_fields[]      = $taxonomy;
  1456 		$where_fields[]      = $taxonomy;
  1404 		$else_where_fields[] = $taxonomy;
  1457 		$else_where_fields[] = $taxonomy;
  1405 
  1458 
  1406 		if ( $result = $wpdb->get_row( $wpdb->prepare( "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $where AND tt.taxonomy = %s $orderby $limit", $where_fields ), ARRAY_A ) ) {
  1459 		$result = $wpdb->get_row( $wpdb->prepare( "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $where AND tt.taxonomy = %s $orderby $limit", $where_fields ), ARRAY_A );
       
  1460 		if ( $result ) {
  1407 			return $result;
  1461 			return $result;
  1408 		}
  1462 		}
  1409 
  1463 
  1410 		return $wpdb->get_row( $wpdb->prepare( "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $else_where AND tt.taxonomy = %s $orderby $limit", $else_where_fields ), ARRAY_A );
  1464 		return $wpdb->get_row( $wpdb->prepare( "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $else_where AND tt.taxonomy = %s $orderby $limit", $else_where_fields ), ARRAY_A );
  1411 	}
  1465 	}
  1412 
  1466 
  1413 	if ( $result = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms as t WHERE $where $orderby $limit", $where_fields ) ) ) {
  1467 	// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
       
  1468 	$result = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms as t WHERE $where $orderby $limit", $where_fields ) );
       
  1469 	if ( $result ) {
  1414 		return $result;
  1470 		return $result;
  1415 	}
  1471 	}
  1416 
  1472 
       
  1473 	// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
  1417 	return $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms as t WHERE $else_where $orderby $limit", $else_where_fields ) );
  1474 	return $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms as t WHERE $else_where $orderby $limit", $else_where_fields ) );
  1418 }
  1475 }
  1419 
  1476 
  1420 /**
  1477 /**
  1421  * Check if a term is an ancestor of another term.
  1478  * Check if a term is an ancestor of another term.
  1422  *
  1479  *
  1423  * You can use either an id or the term object for both parameters.
  1480  * You can use either an ID or the term object for both parameters.
  1424  *
  1481  *
  1425  * @since 3.4.0
  1482  * @since 3.4.0
  1426  *
  1483  *
  1427  * @param int|object $term1    ID or object to check if this is the parent term.
  1484  * @param int|object $term1    ID or object to check if this is the parent term.
  1428  * @param int|object $term2    The child term.
  1485  * @param int|object $term2    The child term.
  1438 	}
  1495 	}
  1439 
  1496 
  1440 	if ( empty( $term1->term_id ) || empty( $term2->parent ) ) {
  1497 	if ( empty( $term1->term_id ) || empty( $term2->parent ) ) {
  1441 		return false;
  1498 		return false;
  1442 	}
  1499 	}
  1443 	if ( $term2->parent == $term1->term_id ) {
  1500 	if ( $term2->parent === $term1->term_id ) {
  1444 		return true;
  1501 		return true;
  1445 	}
  1502 	}
  1446 
  1503 
  1447 	return term_is_ancestor_of( $term1, get_term( $term2->parent, $taxonomy ), $taxonomy );
  1504 	return term_is_ancestor_of( $term1, get_term( $term2->parent, $taxonomy ), $taxonomy );
  1448 }
  1505 }
  1515  *                         'attribute', or 'js'.
  1572  *                         'attribute', or 'js'.
  1516  * @return mixed Sanitized field.
  1573  * @return mixed Sanitized field.
  1517  */
  1574  */
  1518 function sanitize_term_field( $field, $value, $term_id, $taxonomy, $context ) {
  1575 function sanitize_term_field( $field, $value, $term_id, $taxonomy, $context ) {
  1519 	$int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' );
  1576 	$int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' );
  1520 	if ( in_array( $field, $int_fields ) ) {
  1577 	if ( in_array( $field, $int_fields, true ) ) {
  1521 		$value = (int) $value;
  1578 		$value = (int) $value;
  1522 		if ( $value < 0 ) {
  1579 		if ( $value < 0 ) {
  1523 			$value = 0;
  1580 			$value = 0;
  1524 		}
  1581 		}
  1525 	}
  1582 	}
  1526 
  1583 
  1527 	if ( 'raw' == $context ) {
  1584 	$context = strtolower( $context );
       
  1585 
       
  1586 	if ( 'raw' === $context ) {
  1528 		return $value;
  1587 		return $value;
  1529 	}
  1588 	}
  1530 
  1589 
  1531 	if ( 'edit' == $context ) {
  1590 	if ( 'edit' === $context ) {
  1532 
  1591 
  1533 		/**
  1592 		/**
  1534 		 * Filters a term field to edit before it is sanitized.
  1593 		 * Filters a term field to edit before it is sanitized.
  1535 		 *
  1594 		 *
  1536 		 * The dynamic portion of the filter name, `$field`, refers to the term field.
  1595 		 * The dynamic portion of the filter name, `$field`, refers to the term field.
  1554 		 * @param mixed $value   Value of the taxonomy field to edit.
  1613 		 * @param mixed $value   Value of the taxonomy field to edit.
  1555 		 * @param int   $term_id Term ID.
  1614 		 * @param int   $term_id Term ID.
  1556 		 */
  1615 		 */
  1557 		$value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id );
  1616 		$value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id );
  1558 
  1617 
  1559 		if ( 'description' == $field ) {
  1618 		if ( 'description' === $field ) {
  1560 			$value = esc_html( $value ); // textarea_escaped
  1619 			$value = esc_html( $value ); // textarea_escaped
  1561 		} else {
  1620 		} else {
  1562 			$value = esc_attr( $value );
  1621 			$value = esc_attr( $value );
  1563 		}
  1622 		}
  1564 	} elseif ( 'db' == $context ) {
  1623 	} elseif ( 'db' === $context ) {
  1565 
  1624 
  1566 		/**
  1625 		/**
  1567 		 * Filters a term field value before it is sanitized.
  1626 		 * Filters a term field value before it is sanitized.
  1568 		 *
  1627 		 *
  1569 		 * The dynamic portion of the filter name, `$field`, refers to the term field.
  1628 		 * The dynamic portion of the filter name, `$field`, refers to the term field.
  1585 		 *
  1644 		 *
  1586 		 * @param mixed $value Value of the taxonomy field.
  1645 		 * @param mixed $value Value of the taxonomy field.
  1587 		 */
  1646 		 */
  1588 		$value = apply_filters( "pre_{$taxonomy}_{$field}", $value );
  1647 		$value = apply_filters( "pre_{$taxonomy}_{$field}", $value );
  1589 
  1648 
  1590 		// Back compat filters
  1649 		// Back compat filters.
  1591 		if ( 'slug' == $field ) {
  1650 		if ( 'slug' === $field ) {
  1592 			/**
  1651 			/**
  1593 			 * Filters the category nicename before it is sanitized.
  1652 			 * Filters the category nicename before it is sanitized.
  1594 			 *
  1653 			 *
  1595 			 * Use the {@see 'pre_$taxonomy_$field'} hook instead.
  1654 			 * Use the {@see 'pre_$taxonomy_$field'} hook instead.
  1596 			 *
  1655 			 *
  1598 			 *
  1657 			 *
  1599 			 * @param string $value The category nicename.
  1658 			 * @param string $value The category nicename.
  1600 			 */
  1659 			 */
  1601 			$value = apply_filters( 'pre_category_nicename', $value );
  1660 			$value = apply_filters( 'pre_category_nicename', $value );
  1602 		}
  1661 		}
  1603 	} elseif ( 'rss' == $context ) {
  1662 	} elseif ( 'rss' === $context ) {
  1604 
  1663 
  1605 		/**
  1664 		/**
  1606 		 * Filters the term field for use in RSS.
  1665 		 * Filters the term field for use in RSS.
  1607 		 *
  1666 		 *
  1608 		 * The dynamic portion of the filter name, `$field`, refers to the term field.
  1667 		 * The dynamic portion of the filter name, `$field`, refers to the term field.
  1655 		 * @param string $context Context to retrieve the taxonomy field value.
  1714 		 * @param string $context Context to retrieve the taxonomy field value.
  1656 		 */
  1715 		 */
  1657 		$value = apply_filters( "{$taxonomy}_{$field}", $value, $term_id, $context );
  1716 		$value = apply_filters( "{$taxonomy}_{$field}", $value, $term_id, $context );
  1658 	}
  1717 	}
  1659 
  1718 
  1660 	if ( 'attribute' == $context ) {
  1719 	if ( 'attribute' === $context ) {
  1661 		$value = esc_attr( $value );
  1720 		$value = esc_attr( $value );
  1662 	} elseif ( 'js' == $context ) {
  1721 	} elseif ( 'js' === $context ) {
  1663 		$value = esc_js( $value );
  1722 		$value = esc_js( $value );
  1664 	}
  1723 	}
  1665 	return $value;
  1724 	return $value;
  1666 }
  1725 }
  1667 
  1726 
  1676  * @param array|string $args     Optional. Array of arguments that get passed to get_terms().
  1735  * @param array|string $args     Optional. Array of arguments that get passed to get_terms().
  1677  *                               Default empty array.
  1736  *                               Default empty array.
  1678  * @return array|int|WP_Error Number of terms in that taxonomy or WP_Error if the taxonomy does not exist.
  1737  * @return array|int|WP_Error Number of terms in that taxonomy or WP_Error if the taxonomy does not exist.
  1679  */
  1738  */
  1680 function wp_count_terms( $taxonomy, $args = array() ) {
  1739 function wp_count_terms( $taxonomy, $args = array() ) {
  1681 	$defaults = array( 'hide_empty' => false );
  1740 	$defaults = array(
       
  1741 		'taxonomy'   => $taxonomy,
       
  1742 		'hide_empty' => false,
       
  1743 	);
  1682 	$args     = wp_parse_args( $args, $defaults );
  1744 	$args     = wp_parse_args( $args, $defaults );
  1683 
  1745 
  1684 	// backward compatibility
  1746 	// Backward compatibility.
  1685 	if ( isset( $args['ignore_empty'] ) ) {
  1747 	if ( isset( $args['ignore_empty'] ) ) {
  1686 		$args['hide_empty'] = $args['ignore_empty'];
  1748 		$args['hide_empty'] = $args['ignore_empty'];
  1687 		unset( $args['ignore_empty'] );
  1749 		unset( $args['ignore_empty'] );
  1688 	}
  1750 	}
  1689 
  1751 
  1690 	$args['fields'] = 'count';
  1752 	$args['fields'] = 'count';
  1691 
  1753 
  1692 	return get_terms( $taxonomy, $args );
  1754 	return get_terms( $args );
  1693 }
  1755 }
  1694 
  1756 
  1695 /**
  1757 /**
  1696  * Will unlink the object from the taxonomy or taxonomies.
  1758  * Will unlink the object from the taxonomy or taxonomies.
  1697  *
  1759  *
  1748 function wp_delete_term( $term, $taxonomy, $args = array() ) {
  1810 function wp_delete_term( $term, $taxonomy, $args = array() ) {
  1749 	global $wpdb;
  1811 	global $wpdb;
  1750 
  1812 
  1751 	$term = (int) $term;
  1813 	$term = (int) $term;
  1752 
  1814 
  1753 	if ( ! $ids = term_exists( $term, $taxonomy ) ) {
  1815 	$ids = term_exists( $term, $taxonomy );
       
  1816 	if ( ! $ids ) {
  1754 		return false;
  1817 		return false;
  1755 	}
  1818 	}
  1756 	if ( is_wp_error( $ids ) ) {
  1819 	if ( is_wp_error( $ids ) ) {
  1757 		return $ids;
  1820 		return $ids;
  1758 	}
  1821 	}
  1759 
  1822 
  1760 	$tt_id = $ids['term_taxonomy_id'];
  1823 	$tt_id = $ids['term_taxonomy_id'];
  1761 
  1824 
  1762 	$defaults = array();
  1825 	$defaults = array();
  1763 
  1826 
  1764 	if ( 'category' == $taxonomy ) {
  1827 	if ( 'category' === $taxonomy ) {
  1765 		$defaults['default'] = get_option( 'default_category' );
  1828 		$defaults['default'] = (int) get_option( 'default_category' );
  1766 		if ( $defaults['default'] == $term ) {
  1829 		if ( $defaults['default'] === $term ) {
  1767 			return 0; // Don't delete the default category
  1830 			return 0; // Don't delete the default category.
       
  1831 		}
       
  1832 	}
       
  1833 
       
  1834 	// Don't delete the default custom taxonomy term.
       
  1835 	$taxonomy_object = get_taxonomy( $taxonomy );
       
  1836 	if ( ! empty( $taxonomy_object->default_term ) ) {
       
  1837 		$defaults['default'] = (int) get_option( 'default_term_' . $taxonomy );
       
  1838 		if ( $defaults['default'] === $term ) {
       
  1839 			return 0;
  1768 		}
  1840 		}
  1769 	}
  1841 	}
  1770 
  1842 
  1771 	$args = wp_parse_args( $args, $defaults );
  1843 	$args = wp_parse_args( $args, $defaults );
  1772 
  1844 
  1789 	 * @param int    $term     Term ID.
  1861 	 * @param int    $term     Term ID.
  1790 	 * @param string $taxonomy Taxonomy Name.
  1862 	 * @param string $taxonomy Taxonomy Name.
  1791 	 */
  1863 	 */
  1792 	do_action( 'pre_delete_term', $term, $taxonomy );
  1864 	do_action( 'pre_delete_term', $term, $taxonomy );
  1793 
  1865 
  1794 	// Update children to point to new parent
  1866 	// Update children to point to new parent.
  1795 	if ( is_taxonomy_hierarchical( $taxonomy ) ) {
  1867 	if ( is_taxonomy_hierarchical( $taxonomy ) ) {
  1796 		$term_obj = get_term( $term, $taxonomy );
  1868 		$term_obj = get_term( $term, $taxonomy );
  1797 		if ( is_wp_error( $term_obj ) ) {
  1869 		if ( is_wp_error( $term_obj ) ) {
  1798 			return $term_obj;
  1870 			return $term_obj;
  1799 		}
  1871 		}
  1839 			array(
  1911 			array(
  1840 				'fields'  => 'ids',
  1912 				'fields'  => 'ids',
  1841 				'orderby' => 'none',
  1913 				'orderby' => 'none',
  1842 			)
  1914 			)
  1843 		);
  1915 		);
  1844 		if ( 1 == count( $terms ) && isset( $default ) ) {
  1916 		if ( 1 === count( $terms ) && isset( $default ) ) {
  1845 			$terms = array( $default );
  1917 			$terms = array( $default );
  1846 		} else {
  1918 		} else {
  1847 			$terms = array_diff( $terms, array( $term ) );
  1919 			$terms = array_diff( $terms, array( $term ) );
  1848 			if ( isset( $default ) && isset( $force_default ) && $force_default ) {
  1920 			if ( isset( $default ) && isset( $force_default ) && $force_default ) {
  1849 				$terms = array_merge( $terms, array( $default ) );
  1921 				$terms = array_merge( $terms, array( $default ) );
  1870 	 * @since 2.9.0
  1942 	 * @since 2.9.0
  1871 	 *
  1943 	 *
  1872 	 * @param int $tt_id Term taxonomy ID.
  1944 	 * @param int $tt_id Term taxonomy ID.
  1873 	 */
  1945 	 */
  1874 	do_action( 'delete_term_taxonomy', $tt_id );
  1946 	do_action( 'delete_term_taxonomy', $tt_id );
       
  1947 
  1875 	$wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
  1948 	$wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
  1876 
  1949 
  1877 	/**
  1950 	/**
  1878 	 * Fires immediately after a term taxonomy ID is deleted.
  1951 	 * Fires immediately after a term taxonomy ID is deleted.
  1879 	 *
  1952 	 *
  1946  *              Introduced `$parent` argument.
  2019  *              Introduced `$parent` argument.
  1947  * @since 4.4.0 Introduced `$meta_query` and `$update_term_meta_cache` arguments. When `$fields` is 'all' or
  2020  * @since 4.4.0 Introduced `$meta_query` and `$update_term_meta_cache` arguments. When `$fields` is 'all' or
  1948  *              'all_with_object_id', an array of `WP_Term` objects will be returned.
  2021  *              'all_with_object_id', an array of `WP_Term` objects will be returned.
  1949  * @since 4.7.0 Refactored to use WP_Term_Query, and to support any WP_Term_Query arguments.
  2022  * @since 4.7.0 Refactored to use WP_Term_Query, and to support any WP_Term_Query arguments.
  1950  *
  2023  *
  1951  * @param int|array    $object_ids The ID(s) of the object(s) to retrieve.
  2024  * @param int|int[]       $object_ids The ID(s) of the object(s) to retrieve.
  1952  * @param string|array $taxonomies The taxonomies to retrieve terms from.
  2025  * @param string|string[] $taxonomies The taxonomy names to retrieve terms from.
  1953  * @param array|string $args       See WP_Term_Query::__construct() for supported arguments.
  2026  * @param array|string    $args       See WP_Term_Query::__construct() for supported arguments.
  1954  * @return array|WP_Error The requested term data or empty array if no terms found.
  2027  * @return array|WP_Error The requested term data or empty array if no terms found.
  1955  *                        WP_Error if any of the $taxonomies don't exist.
  2028  *                        WP_Error if any of the taxonomies don't exist.
  1956  */
  2029  */
  1957 function wp_get_object_terms( $object_ids, $taxonomies, $args = array() ) {
  2030 function wp_get_object_terms( $object_ids, $taxonomies, $args = array() ) {
  1958 	if ( empty( $object_ids ) || empty( $taxonomies ) ) {
  2031 	if ( empty( $object_ids ) || empty( $taxonomies ) ) {
  1959 		return array();
  2032 		return array();
  1960 	}
  2033 	}
  1979 	/**
  2052 	/**
  1980 	 * Filter arguments for retrieving object terms.
  2053 	 * Filter arguments for retrieving object terms.
  1981 	 *
  2054 	 *
  1982 	 * @since 4.9.0
  2055 	 * @since 4.9.0
  1983 	 *
  2056 	 *
  1984 	 * @param array        $args       An array of arguments for retrieving terms for the given object(s).
  2057 	 * @param array    $args       An array of arguments for retrieving terms for the given object(s).
  1985 	 *                                 See {@see wp_get_object_terms()} for details.
  2058 	 *                             See {@see wp_get_object_terms()} for details.
  1986 	 * @param int|array    $object_ids Object ID or array of IDs.
  2059 	 * @param int[]    $object_ids Array of object IDs.
  1987 	 * @param string|array $taxonomies The taxonomies to retrieve terms from.
  2060 	 * @param string[] $taxonomies Array of taxonomy names to retrieve terms from.
  1988 	 */
  2061 	 */
  1989 	$args = apply_filters( 'wp_get_object_terms_args', $args, $object_ids, $taxonomies );
  2062 	$args = apply_filters( 'wp_get_object_terms_args', $args, $object_ids, $taxonomies );
  1990 
  2063 
  1991 	/*
  2064 	/*
  1992 	 * When one or more queried taxonomies is registered with an 'args' array,
  2065 	 * When one or more queried taxonomies is registered with an 'args' array,
  1994 	 */
  2067 	 */
  1995 	$terms = array();
  2068 	$terms = array();
  1996 	if ( count( $taxonomies ) > 1 ) {
  2069 	if ( count( $taxonomies ) > 1 ) {
  1997 		foreach ( $taxonomies as $index => $taxonomy ) {
  2070 		foreach ( $taxonomies as $index => $taxonomy ) {
  1998 			$t = get_taxonomy( $taxonomy );
  2071 			$t = get_taxonomy( $taxonomy );
  1999 			if ( isset( $t->args ) && is_array( $t->args ) && $args != array_merge( $args, $t->args ) ) {
  2072 			if ( isset( $t->args ) && is_array( $t->args ) && array_merge( $args, $t->args ) != $args ) {
  2000 				unset( $taxonomies[ $index ] );
  2073 				unset( $taxonomies[ $index ] );
  2001 				$terms = array_merge( $terms, wp_get_object_terms( $object_ids, $taxonomy, array_merge( $args, $t->args ) ) );
  2074 				$terms = array_merge( $terms, wp_get_object_terms( $object_ids, $taxonomy, array_merge( $args, $t->args ) ) );
  2002 			}
  2075 			}
  2003 		}
  2076 		}
  2004 	} else {
  2077 	} else {
  2026 	/**
  2099 	/**
  2027 	 * Filters the terms for a given object or objects.
  2100 	 * Filters the terms for a given object or objects.
  2028 	 *
  2101 	 *
  2029 	 * @since 4.2.0
  2102 	 * @since 4.2.0
  2030 	 *
  2103 	 *
  2031 	 * @param array $terms      An array of terms for the given object or objects.
  2104 	 * @param array    $terms      Array of terms for the given object or objects.
  2032 	 * @param array $object_ids Array of object IDs for which `$terms` were retrieved.
  2105 	 * @param int[]    $object_ids Array of object IDs for which terms were retrieved.
  2033 	 * @param array $taxonomies Array of taxonomies from which `$terms` were retrieved.
  2106 	 * @param string[] $taxonomies Array of taxonomy names from which terms were retrieved.
  2034 	 * @param array $args       An array of arguments for retrieving terms for the given
  2107 	 * @param array    $args       Array of arguments for retrieving terms for the given
  2035 	 *                          object(s). See wp_get_object_terms() for details.
  2108 	 *                             object(s). See wp_get_object_terms() for details.
  2036 	 */
  2109 	 */
  2037 	$terms = apply_filters( 'get_object_terms', $terms, $object_ids, $taxonomies, $args );
  2110 	$terms = apply_filters( 'get_object_terms', $terms, $object_ids, $taxonomies, $args );
  2038 
  2111 
  2039 	$object_ids = implode( ',', $object_ids );
  2112 	$object_ids = implode( ',', $object_ids );
  2040 	$taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'";
  2113 	$taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'";
  2045 	 * The `$taxonomies` parameter passed to this filter is formatted as a SQL fragment. The
  2118 	 * The `$taxonomies` parameter passed to this filter is formatted as a SQL fragment. The
  2046 	 * {@see 'get_object_terms'} filter is recommended as an alternative.
  2119 	 * {@see 'get_object_terms'} filter is recommended as an alternative.
  2047 	 *
  2120 	 *
  2048 	 * @since 2.8.0
  2121 	 * @since 2.8.0
  2049 	 *
  2122 	 *
  2050 	 * @param array     $terms      An array of terms for the given object or objects.
  2123 	 * @param array    $terms      Array of terms for the given object or objects.
  2051 	 * @param int|array $object_ids Object ID or array of IDs.
  2124 	 * @param int[]    $object_ids Array of object IDs for which terms were retrieved.
  2052 	 * @param string    $taxonomies SQL-formatted (comma-separated and quoted) list of taxonomy names.
  2125 	 * @param string[] $taxonomies Array of taxonomy names from which terms were retrieved.
  2053 	 * @param array     $args       An array of arguments for retrieving terms for the given object(s).
  2126 	 * @param array    $args       Array of arguments for retrieving terms for the given
  2054 	 *                              See wp_get_object_terms() for details.
  2127 	 *                             object(s). See wp_get_object_terms() for details.
  2055 	 */
  2128 	 */
  2056 	return apply_filters( 'wp_get_object_terms', $terms, $object_ids, $taxonomies, $args );
  2129 	return apply_filters( 'wp_get_object_terms', $terms, $object_ids, $taxonomies, $args );
  2057 }
  2130 }
  2058 
  2131 
  2059 /**
  2132 /**
  2063  * 1. The term is added to the term table, then related to the taxonomy.
  2136  * 1. The term is added to the term table, then related to the taxonomy.
  2064  * 2. If everything is correct, several actions are fired.
  2137  * 2. If everything is correct, several actions are fired.
  2065  * 3. The 'term_id_filter' is evaluated.
  2138  * 3. The 'term_id_filter' is evaluated.
  2066  * 4. The term cache is cleaned.
  2139  * 4. The term cache is cleaned.
  2067  * 5. Several more actions are fired.
  2140  * 5. Several more actions are fired.
  2068  * 6. An array is returned containing the term_id and term_taxonomy_id.
  2141  * 6. An array is returned containing the `term_id` and `term_taxonomy_id`.
  2069  *
  2142  *
  2070  * If the 'slug' argument is not empty, then it is checked to see if the term
  2143  * If the 'slug' argument is not empty, then it is checked to see if the term
  2071  * is invalid. If it is not a valid, existing term, it is added and the term_id
  2144  * is invalid. If it is not a valid, existing term, it is added and the term_id
  2072  * is given.
  2145  * is given.
  2073  *
  2146  *
  2074  * If the taxonomy is hierarchical, and the 'parent' argument is not empty,
  2147  * If the taxonomy is hierarchical, and the 'parent' argument is not empty,
  2075  * the term is inserted and the term_id will be given.
  2148  * the term is inserted and the term_id will be given.
  2076  *
  2149  *
  2077  * Error handling:
  2150  * Error handling:
  2078  * If $taxonomy does not exist or $term is empty,
  2151  * If `$taxonomy` does not exist or `$term` is empty,
  2079  * a WP_Error object will be returned.
  2152  * a WP_Error object will be returned.
  2080  *
  2153  *
  2081  * If the term already exists on the same hierarchical level,
  2154  * If the term already exists on the same hierarchical level,
  2082  * or the term slug and name are not unique, a WP_Error object will be returned.
  2155  * or the term slug and name are not unique, a WP_Error object will be returned.
  2083  *
  2156  *
  2084  * @global wpdb $wpdb WordPress database abstraction object.
  2157  * @global wpdb $wpdb WordPress database abstraction object.
  2085  *
  2158  *
  2086  * @since 2.3.0
  2159  * @since 2.3.0
  2087  *
  2160  *
  2088  * @param string       $term     The term to add or update.
  2161  * @param string       $term     The term name to add.
  2089  * @param string       $taxonomy The taxonomy to which to add the term.
  2162  * @param string       $taxonomy The taxonomy to which to add the term.
  2090  * @param array|string $args {
  2163  * @param array|string $args {
  2091  *     Optional. Array or string of arguments for inserting a term.
  2164  *     Optional. Array or string of arguments for inserting a term.
  2092  *
  2165  *
  2093  *     @type string $alias_of    Slug of the term to make this term an alias of.
  2166  *     @type string $alias_of    Slug of the term to make this term an alias of.
  2103 	global $wpdb;
  2176 	global $wpdb;
  2104 
  2177 
  2105 	if ( ! taxonomy_exists( $taxonomy ) ) {
  2178 	if ( ! taxonomy_exists( $taxonomy ) ) {
  2106 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  2179 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  2107 	}
  2180 	}
       
  2181 
  2108 	/**
  2182 	/**
  2109 	 * Filters a term before it is sanitized and inserted into the database.
  2183 	 * Filters a term before it is sanitized and inserted into the database.
  2110 	 *
  2184 	 *
  2111 	 * @since 3.0.0
  2185 	 * @since 3.0.0
  2112 	 *
  2186 	 *
  2113 	 * @param string $term     The term to add or update.
  2187 	 * @param string|WP_Error $term     The term name to add, or a WP_Error object if there's an error.
  2114 	 * @param string $taxonomy Taxonomy slug.
  2188 	 * @param string          $taxonomy Taxonomy slug.
  2115 	 */
  2189 	 */
  2116 	$term = apply_filters( 'pre_insert_term', $term, $taxonomy );
  2190 	$term = apply_filters( 'pre_insert_term', $term, $taxonomy );
       
  2191 
  2117 	if ( is_wp_error( $term ) ) {
  2192 	if ( is_wp_error( $term ) ) {
  2118 		return $term;
  2193 		return $term;
  2119 	}
  2194 	}
  2120 	if ( is_int( $term ) && 0 == $term ) {
  2195 
       
  2196 	if ( is_int( $term ) && 0 === $term ) {
  2121 		return new WP_Error( 'invalid_term_id', __( 'Invalid term ID.' ) );
  2197 		return new WP_Error( 'invalid_term_id', __( 'Invalid term ID.' ) );
  2122 	}
  2198 	}
  2123 	if ( '' == trim( $term ) ) {
  2199 
       
  2200 	if ( '' === trim( $term ) ) {
  2124 		return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) );
  2201 		return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) );
  2125 	}
  2202 	}
       
  2203 
  2126 	$defaults = array(
  2204 	$defaults = array(
  2127 		'alias_of'    => '',
  2205 		'alias_of'    => '',
  2128 		'description' => '',
  2206 		'description' => '',
  2129 		'parent'      => 0,
  2207 		'parent'      => 0,
  2130 		'slug'        => '',
  2208 		'slug'        => '',
  2181 	/*
  2259 	/*
  2182 	 * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy,
  2260 	 * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy,
  2183 	 * unless a unique slug has been explicitly provided.
  2261 	 * unless a unique slug has been explicitly provided.
  2184 	 */
  2262 	 */
  2185 	$name_matches = get_terms(
  2263 	$name_matches = get_terms(
  2186 		$taxonomy,
       
  2187 		array(
  2264 		array(
       
  2265 			'taxonomy'               => $taxonomy,
  2188 			'name'                   => $name,
  2266 			'name'                   => $name,
  2189 			'hide_empty'             => false,
  2267 			'hide_empty'             => false,
  2190 			'parent'                 => $args['parent'],
  2268 			'parent'                 => $args['parent'],
  2191 			'update_term_meta_cache' => false,
  2269 			'update_term_meta_cache' => false,
  2192 		)
  2270 		)
  2209 	if ( $name_match ) {
  2287 	if ( $name_match ) {
  2210 		$slug_match = get_term_by( 'slug', $slug, $taxonomy );
  2288 		$slug_match = get_term_by( 'slug', $slug, $taxonomy );
  2211 		if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) {
  2289 		if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) {
  2212 			if ( is_taxonomy_hierarchical( $taxonomy ) ) {
  2290 			if ( is_taxonomy_hierarchical( $taxonomy ) ) {
  2213 				$siblings = get_terms(
  2291 				$siblings = get_terms(
  2214 					$taxonomy,
       
  2215 					array(
  2292 					array(
       
  2293 						'taxonomy'               => $taxonomy,
  2216 						'get'                    => 'all',
  2294 						'get'                    => 'all',
  2217 						'parent'                 => $parent,
  2295 						'parent'                 => $parent,
  2218 						'update_term_meta_cache' => false,
  2296 						'update_term_meta_cache' => false,
  2219 					)
  2297 					)
  2220 				);
  2298 				);
  2221 
  2299 
  2222 				$existing_term = null;
  2300 				$existing_term = null;
  2223 				if ( ( ! $slug_provided || $name_match->slug === $slug ) && in_array( $name, wp_list_pluck( $siblings, 'name' ) ) ) {
  2301 				$sibling_names = wp_list_pluck( $siblings, 'name' );
       
  2302 				$sibling_slugs = wp_list_pluck( $siblings, 'slug' );
       
  2303 
       
  2304 				if ( ( ! $slug_provided || $name_match->slug === $slug ) && in_array( $name, $sibling_names, true ) ) {
  2224 					$existing_term = $name_match;
  2305 					$existing_term = $name_match;
  2225 				} elseif ( $slug_match && in_array( $slug, wp_list_pluck( $siblings, 'slug' ) ) ) {
  2306 				} elseif ( $slug_match && in_array( $slug, $sibling_slugs, true ) ) {
  2226 					$existing_term = $slug_match;
  2307 					$existing_term = $slug_match;
  2227 				}
  2308 				}
  2228 
  2309 
  2229 				if ( $existing_term ) {
  2310 				if ( $existing_term ) {
  2230 					return new WP_Error( 'term_exists', __( 'A term with the name provided already exists with this parent.' ), $existing_term->term_id );
  2311 					return new WP_Error( 'term_exists', __( 'A term with the name provided already exists with this parent.' ), $existing_term->term_id );
  2254 		return new WP_Error( 'db_insert_error', __( 'Could not insert term into the database.' ), $wpdb->last_error );
  2335 		return new WP_Error( 'db_insert_error', __( 'Could not insert term into the database.' ), $wpdb->last_error );
  2255 	}
  2336 	}
  2256 
  2337 
  2257 	$term_id = (int) $wpdb->insert_id;
  2338 	$term_id = (int) $wpdb->insert_id;
  2258 
  2339 
  2259 	// Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string.
  2340 	// Seems unreachable. However, is used in the case that a term name is provided, which sanitizes to an empty string.
  2260 	if ( empty( $slug ) ) {
  2341 	if ( empty( $slug ) ) {
  2261 		$slug = sanitize_title( $slug, $term_id );
  2342 		$slug = sanitize_title( $slug, $term_id );
  2262 
  2343 
  2263 		/** This action is documented in wp-includes/taxonomy.php */
  2344 		/** This action is documented in wp-includes/taxonomy.php */
  2264 		do_action( 'edit_terms', $term_id, $taxonomy );
  2345 		do_action( 'edit_terms', $term_id, $taxonomy );
  2274 		return array(
  2355 		return array(
  2275 			'term_id'          => $term_id,
  2356 			'term_id'          => $term_id,
  2276 			'term_taxonomy_id' => $tt_id,
  2357 			'term_taxonomy_id' => $tt_id,
  2277 		);
  2358 		);
  2278 	}
  2359 	}
  2279 	$wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ) + array( 'count' => 0 ) );
  2360 
       
  2361 	if ( false === $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ) + array( 'count' => 0 ) ) ) {
       
  2362 		return new WP_Error( 'db_insert_error', __( 'Could not insert term taxonomy into the database.' ), $wpdb->last_error );
       
  2363 	}
       
  2364 
  2280 	$tt_id = (int) $wpdb->insert_id;
  2365 	$tt_id = (int) $wpdb->insert_id;
  2281 
  2366 
  2282 	/*
  2367 	/*
  2283 	 * Sanity check: if we just created a term with the same parent + taxonomy + slug but a higher term_id than
  2368 	 * Sanity check: if we just created a term with the same parent + taxonomy + slug but a higher term_id than
  2284 	 * an existing term, then we have unwittingly created a duplicate term. Delete the dupe, and use the term_id
  2369 	 * an existing term, then we have unwittingly created a duplicate term. Delete the dupe, and use the term_id
  2347 	 * Filters the term ID after a new term is created.
  2432 	 * Filters the term ID after a new term is created.
  2348 	 *
  2433 	 *
  2349 	 * @since 2.3.0
  2434 	 * @since 2.3.0
  2350 	 *
  2435 	 *
  2351 	 * @param int $term_id Term ID.
  2436 	 * @param int $term_id Term ID.
  2352 	 * @param int $tt_id   Taxonomy term ID.
  2437 	 * @param int $tt_id   Term taxonomy ID.
  2353 	 */
  2438 	 */
  2354 	$term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
  2439 	$term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
  2355 
  2440 
  2356 	clean_term_cache( $term_id, $taxonomy );
  2441 	clean_term_cache( $term_id, $taxonomy );
  2357 
  2442 
  2376 	 *
  2461 	 *
  2377 	 * @param int $term_id Term ID.
  2462 	 * @param int $term_id Term ID.
  2378 	 * @param int $tt_id   Term taxonomy ID.
  2463 	 * @param int $tt_id   Term taxonomy ID.
  2379 	 */
  2464 	 */
  2380 	do_action( "created_{$taxonomy}", $term_id, $tt_id );
  2465 	do_action( "created_{$taxonomy}", $term_id, $tt_id );
       
  2466 
       
  2467 	/**
       
  2468 	 * Fires after a term has been saved, and the term cache has been cleared.
       
  2469 	 *
       
  2470 	 * @since 5.5.0
       
  2471 	 *
       
  2472 	 * @param int    $term_id  Term ID.
       
  2473 	 * @param int    $tt_id    Term taxonomy ID.
       
  2474 	 * @param string $taxonomy Taxonomy slug.
       
  2475 	 * @param bool   $update   Whether this is an existing term being updated.
       
  2476 	 */
       
  2477 	do_action( 'saved_term', $term_id, $tt_id, $taxonomy, false );
       
  2478 
       
  2479 	/**
       
  2480 	 * Fires after a term in a specific taxonomy has been saved, and the term
       
  2481 	 * cache has been cleared.
       
  2482 	 *
       
  2483 	 * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
       
  2484 	 *
       
  2485 	 * @since 5.5.0
       
  2486 	 *
       
  2487 	 * @param int  $term_id Term ID.
       
  2488 	 * @param int  $tt_id   Term taxonomy ID.
       
  2489 	 * @param bool $update  Whether this is an existing term being updated.
       
  2490 	 */
       
  2491 	do_action( "saved_{$taxonomy}", $term_id, $tt_id, false );
  2381 
  2492 
  2382 	return array(
  2493 	return array(
  2383 		'term_id'          => $term_id,
  2494 		'term_id'          => $term_id,
  2384 		'term_taxonomy_id' => $tt_id,
  2495 		'term_taxonomy_id' => $tt_id,
  2385 	);
  2496 	);
  2396  * A term has no meaning until it is given context by defining which taxonomy it
  2507  * A term has no meaning until it is given context by defining which taxonomy it
  2397  * exists under.
  2508  * exists under.
  2398  *
  2509  *
  2399  * @since 2.3.0
  2510  * @since 2.3.0
  2400  *
  2511  *
  2401  * @global wpdb $wpdb The WordPress database abstraction object.
  2512  * @global wpdb $wpdb WordPress database abstraction object.
  2402  *
  2513  *
  2403  * @param int              $object_id The object to relate to.
  2514  * @param int              $object_id The object to relate to.
  2404  * @param string|int|array $terms     A single term slug, single term id, or array of either term slugs or ids.
  2515  * @param string|int|array $terms     A single term slug, single term ID, or array of either term slugs or IDs.
  2405  *                                    Will replace all existing related terms in this taxonomy. Passing an
  2516  *                                    Will replace all existing related terms in this taxonomy. Passing an
  2406  *                                    empty value will remove all related terms.
  2517  *                                    empty value will remove all related terms.
  2407  * @param string           $taxonomy  The context in which to relate the term to the object.
  2518  * @param string           $taxonomy  The context in which to relate the term to the object.
  2408  * @param bool             $append    Optional. If false will delete difference of terms. Default false.
  2519  * @param bool             $append    Optional. If false will delete difference of terms. Default false.
  2409  * @return array|WP_Error Term taxonomy IDs of the affected terms.
  2520  * @return array|WP_Error Term taxonomy IDs of the affected terms or WP_Error on failure.
  2410  */
  2521  */
  2411 function wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false ) {
  2522 function wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false ) {
  2412 	global $wpdb;
  2523 	global $wpdb;
  2413 
  2524 
  2414 	$object_id = (int) $object_id;
  2525 	$object_id = (int) $object_id;
  2438 	$tt_ids     = array();
  2549 	$tt_ids     = array();
  2439 	$term_ids   = array();
  2550 	$term_ids   = array();
  2440 	$new_tt_ids = array();
  2551 	$new_tt_ids = array();
  2441 
  2552 
  2442 	foreach ( (array) $terms as $term ) {
  2553 	foreach ( (array) $terms as $term ) {
  2443 		if ( ! strlen( trim( $term ) ) ) {
  2554 		if ( '' === trim( $term ) ) {
  2444 			continue;
  2555 			continue;
  2445 		}
  2556 		}
  2446 
  2557 
  2447 		if ( ! $term_info = term_exists( $term, $taxonomy ) ) {
  2558 		$term_info = term_exists( $term, $taxonomy );
       
  2559 
       
  2560 		if ( ! $term_info ) {
  2448 			// Skip if a non-existent term ID is passed.
  2561 			// Skip if a non-existent term ID is passed.
  2449 			if ( is_int( $term ) ) {
  2562 			if ( is_int( $term ) ) {
  2450 				continue;
  2563 				continue;
  2451 			}
  2564 			}
       
  2565 
  2452 			$term_info = wp_insert_term( $term, $taxonomy );
  2566 			$term_info = wp_insert_term( $term, $taxonomy );
  2453 		}
  2567 		}
       
  2568 
  2454 		if ( is_wp_error( $term_info ) ) {
  2569 		if ( is_wp_error( $term_info ) ) {
  2455 			return $term_info;
  2570 			return $term_info;
  2456 		}
  2571 		}
       
  2572 
  2457 		$term_ids[] = $term_info['term_id'];
  2573 		$term_ids[] = $term_info['term_id'];
  2458 		$tt_id      = $term_info['term_taxonomy_id'];
  2574 		$tt_id      = $term_info['term_taxonomy_id'];
  2459 		$tt_ids[]   = $tt_id;
  2575 		$tt_ids[]   = $tt_id;
  2460 
  2576 
  2461 		if ( $wpdb->get_var( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id = %d", $object_id, $tt_id ) ) ) {
  2577 		if ( $wpdb->get_var( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id = %d", $object_id, $tt_id ) ) ) {
  2471 		 * @param int    $object_id Object ID.
  2587 		 * @param int    $object_id Object ID.
  2472 		 * @param int    $tt_id     Term taxonomy ID.
  2588 		 * @param int    $tt_id     Term taxonomy ID.
  2473 		 * @param string $taxonomy  Taxonomy slug.
  2589 		 * @param string $taxonomy  Taxonomy slug.
  2474 		 */
  2590 		 */
  2475 		do_action( 'add_term_relationship', $object_id, $tt_id, $taxonomy );
  2591 		do_action( 'add_term_relationship', $object_id, $tt_id, $taxonomy );
       
  2592 
  2476 		$wpdb->insert(
  2593 		$wpdb->insert(
  2477 			$wpdb->term_relationships,
  2594 			$wpdb->term_relationships,
  2478 			array(
  2595 			array(
  2479 				'object_id'        => $object_id,
  2596 				'object_id'        => $object_id,
  2480 				'term_taxonomy_id' => $tt_id,
  2597 				'term_taxonomy_id' => $tt_id,
  2490 		 * @param int    $object_id Object ID.
  2607 		 * @param int    $object_id Object ID.
  2491 		 * @param int    $tt_id     Term taxonomy ID.
  2608 		 * @param int    $tt_id     Term taxonomy ID.
  2492 		 * @param string $taxonomy  Taxonomy slug.
  2609 		 * @param string $taxonomy  Taxonomy slug.
  2493 		 */
  2610 		 */
  2494 		do_action( 'added_term_relationship', $object_id, $tt_id, $taxonomy );
  2611 		do_action( 'added_term_relationship', $object_id, $tt_id, $taxonomy );
       
  2612 
  2495 		$new_tt_ids[] = $tt_id;
  2613 		$new_tt_ids[] = $tt_id;
  2496 	}
  2614 	}
  2497 
  2615 
  2498 	if ( $new_tt_ids ) {
  2616 	if ( $new_tt_ids ) {
  2499 		wp_update_term_count( $new_tt_ids, $taxonomy );
  2617 		wp_update_term_count( $new_tt_ids, $taxonomy );
  2513 			}
  2631 			}
  2514 		}
  2632 		}
  2515 	}
  2633 	}
  2516 
  2634 
  2517 	$t = get_taxonomy( $taxonomy );
  2635 	$t = get_taxonomy( $taxonomy );
       
  2636 
  2518 	if ( ! $append && isset( $t->sort ) && $t->sort ) {
  2637 	if ( ! $append && isset( $t->sort ) && $t->sort ) {
  2519 		$values       = array();
  2638 		$values     = array();
  2520 		$term_order   = 0;
  2639 		$term_order = 0;
       
  2640 
  2521 		$final_tt_ids = wp_get_object_terms(
  2641 		$final_tt_ids = wp_get_object_terms(
  2522 			$object_id,
  2642 			$object_id,
  2523 			$taxonomy,
  2643 			$taxonomy,
  2524 			array(
  2644 			array(
  2525 				'fields'                 => 'tt_ids',
  2645 				'fields'                 => 'tt_ids',
  2526 				'update_term_meta_cache' => false,
  2646 				'update_term_meta_cache' => false,
  2527 			)
  2647 			)
  2528 		);
  2648 		);
       
  2649 
  2529 		foreach ( $tt_ids as $tt_id ) {
  2650 		foreach ( $tt_ids as $tt_id ) {
  2530 			if ( in_array( $tt_id, $final_tt_ids ) ) {
  2651 			if ( in_array( (int) $tt_id, $final_tt_ids, true ) ) {
  2531 				$values[] = $wpdb->prepare( '(%d, %d, %d)', $object_id, $tt_id, ++$term_order );
  2652 				$values[] = $wpdb->prepare( '(%d, %d, %d)', $object_id, $tt_id, ++$term_order );
  2532 			}
  2653 			}
  2533 		}
  2654 		}
       
  2655 
  2534 		if ( $values ) {
  2656 		if ( $values ) {
  2535 			if ( false === $wpdb->query( "INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id, term_order) VALUES " . join( ',', $values ) . ' ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)' ) ) {
  2657 			if ( false === $wpdb->query( "INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id, term_order) VALUES " . join( ',', $values ) . ' ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)' ) ) {
  2536 				return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database.' ), $wpdb->last_error );
  2658 				return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database.' ), $wpdb->last_error );
  2537 			}
  2659 			}
  2538 		}
  2660 		}
  2552 	 * @param string $taxonomy   Taxonomy slug.
  2674 	 * @param string $taxonomy   Taxonomy slug.
  2553 	 * @param bool   $append     Whether to append new terms to the old terms.
  2675 	 * @param bool   $append     Whether to append new terms to the old terms.
  2554 	 * @param array  $old_tt_ids Old array of term taxonomy IDs.
  2676 	 * @param array  $old_tt_ids Old array of term taxonomy IDs.
  2555 	 */
  2677 	 */
  2556 	do_action( 'set_object_terms', $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids );
  2678 	do_action( 'set_object_terms', $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids );
       
  2679 
  2557 	return $tt_ids;
  2680 	return $tt_ids;
  2558 }
  2681 }
  2559 
  2682 
  2560 /**
  2683 /**
  2561  * Add term(s) associated with a given object.
  2684  * Add term(s) associated with a given object.
  2597 	}
  2720 	}
  2598 
  2721 
  2599 	$tt_ids = array();
  2722 	$tt_ids = array();
  2600 
  2723 
  2601 	foreach ( (array) $terms as $term ) {
  2724 	foreach ( (array) $terms as $term ) {
  2602 		if ( ! strlen( trim( $term ) ) ) {
  2725 		if ( '' === trim( $term ) ) {
  2603 			continue;
  2726 			continue;
  2604 		}
  2727 		}
  2605 
  2728 
  2606 		if ( ! $term_info = term_exists( $term, $taxonomy ) ) {
  2729 		$term_info = term_exists( $term, $taxonomy );
       
  2730 		if ( ! $term_info ) {
  2607 			// Skip if a non-existent term ID is passed.
  2731 			// Skip if a non-existent term ID is passed.
  2608 			if ( is_int( $term ) ) {
  2732 			if ( is_int( $term ) ) {
  2609 				continue;
  2733 				continue;
  2610 			}
  2734 			}
  2611 		}
  2735 		}
  2629 		 * @param int   $object_id Object ID.
  2753 		 * @param int   $object_id Object ID.
  2630 		 * @param array $tt_ids    An array of term taxonomy IDs.
  2754 		 * @param array $tt_ids    An array of term taxonomy IDs.
  2631 		 * @param string $taxonomy  Taxonomy slug.
  2755 		 * @param string $taxonomy  Taxonomy slug.
  2632 		 */
  2756 		 */
  2633 		do_action( 'delete_term_relationships', $object_id, $tt_ids, $taxonomy );
  2757 		do_action( 'delete_term_relationships', $object_id, $tt_ids, $taxonomy );
       
  2758 
  2634 		$deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
  2759 		$deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
  2635 
  2760 
  2636 		wp_cache_delete( $object_id, $taxonomy . '_relationships' );
  2761 		wp_cache_delete( $object_id, $taxonomy . '_relationships' );
  2637 		wp_cache_delete( 'last_changed', 'terms' );
  2762 		wp_cache_delete( 'last_changed', 'terms' );
  2638 
  2763 
  2726 	 * @param object $term         Term object.
  2851 	 * @param object $term         Term object.
  2727 	 */
  2852 	 */
  2728 	if ( apply_filters( 'wp_unique_term_slug_is_bad_slug', $needs_suffix, $slug, $term ) ) {
  2853 	if ( apply_filters( 'wp_unique_term_slug_is_bad_slug', $needs_suffix, $slug, $term ) ) {
  2729 		if ( $parent_suffix ) {
  2854 		if ( $parent_suffix ) {
  2730 			$slug .= $parent_suffix;
  2855 			$slug .= $parent_suffix;
       
  2856 		}
       
  2857 
       
  2858 		if ( ! empty( $term->term_id ) ) {
       
  2859 			$query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id );
  2731 		} else {
  2860 		} else {
  2732 			if ( ! empty( $term->term_id ) ) {
  2861 			$query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug );
  2733 				$query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id );
  2862 		}
  2734 			} else {
  2863 
  2735 				$query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug );
  2864 		if ( $wpdb->get_var( $query ) ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
  2736 			}
  2865 			$num = 2;
  2737 
  2866 			do {
  2738 			if ( $wpdb->get_var( $query ) ) {
  2867 				$alt_slug = $slug . "-$num";
  2739 				$num = 2;
  2868 				$num++;
  2740 				do {
  2869 				$slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) );
  2741 					$alt_slug = $slug . "-$num";
  2870 			} while ( $slug_check );
  2742 					$num++;
  2871 			$slug = $alt_slug;
  2743 					$slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) );
       
  2744 				} while ( $slug_check );
       
  2745 				$slug = $alt_slug;
       
  2746 			}
       
  2747 		}
  2872 		}
  2748 	}
  2873 	}
  2749 
  2874 
  2750 	/**
  2875 	/**
  2751 	 * Filters the unique term slug.
  2876 	 * Filters the unique term slug.
  2760 }
  2885 }
  2761 
  2886 
  2762 /**
  2887 /**
  2763  * Update term based on arguments provided.
  2888  * Update term based on arguments provided.
  2764  *
  2889  *
  2765  * The $args will indiscriminately override all values with the same field name.
  2890  * The `$args` will indiscriminately override all values with the same field name.
  2766  * Care must be taken to not override important information need to update or
  2891  * Care must be taken to not override important information need to update or
  2767  * update will fail (or perhaps create a new term, neither would be acceptable).
  2892  * update will fail (or perhaps create a new term, neither would be acceptable).
  2768  *
  2893  *
  2769  * Defaults will set 'alias_of', 'description', 'parent', and 'slug' if not
  2894  * Defaults will set 'alias_of', 'description', 'parent', and 'slug' if not
  2770  * defined in $args already.
  2895  * defined in `$args` already.
  2771  *
  2896  *
  2772  * 'alias_of' will create a term group, if it doesn't already exist, and update
  2897  * 'alias_of' will create a term group, if it doesn't already exist, and
  2773  * it for the $term.
  2898  * update it for the `$term`.
  2774  *
  2899  *
  2775  * If the 'slug' argument in $args is missing, then the 'name' in $args will be
  2900  * If the 'slug' argument in `$args` is missing, then the 'name' will be used.
  2776  * used. It should also be noted that if you set 'slug' and it isn't unique then
  2901  * If you set 'slug' and it isn't unique, then a WP_Error is returned.
  2777  * a WP_Error will be passed back. If you don't pass any slug, then a unique one
  2902  * If you don't pass any slug, then a unique one will be created.
  2778  * will be created for you.
       
  2779  *
       
  2780  * For what can be overrode in `$args`, check the term scheme can contain and stay
       
  2781  * away from the term keys.
       
  2782  *
  2903  *
  2783  * @since 2.3.0
  2904  * @since 2.3.0
  2784  *
  2905  *
  2785  * @global wpdb $wpdb WordPress database abstraction object.
  2906  * @global wpdb $wpdb WordPress database abstraction object.
  2786  *
  2907  *
  2787  * @param int          $term_id  The ID of the term
  2908  * @param int          $term_id  The ID of the term.
  2788  * @param string       $taxonomy The context in which to relate the term to the object.
  2909  * @param string       $taxonomy The taxonomy of the term.
  2789  * @param array|string $args     Optional. Array of get_terms() arguments. Default empty array.
  2910  * @param array|string $args {
  2790  * @return array|WP_Error Returns Term ID and Taxonomy Term ID
  2911  *     Optional. Array or string of arguments for updating a term.
       
  2912  *
       
  2913  *     @type string $alias_of    Slug of the term to make this term an alias of.
       
  2914  *                               Default empty string. Accepts a term slug.
       
  2915  *     @type string $description The term description. Default empty string.
       
  2916  *     @type int    $parent      The id of the parent term. Default 0.
       
  2917  *     @type string $slug        The term slug to use. Default empty string.
       
  2918  * }
       
  2919  * @return array|WP_Error An array containing the `term_id` and `term_taxonomy_id`,
       
  2920  *                        WP_Error otherwise.
  2791  */
  2921  */
  2792 function wp_update_term( $term_id, $taxonomy, $args = array() ) {
  2922 function wp_update_term( $term_id, $taxonomy, $args = array() ) {
  2793 	global $wpdb;
  2923 	global $wpdb;
  2794 
  2924 
  2795 	if ( ! taxonomy_exists( $taxonomy ) ) {
  2925 	if ( ! taxonomy_exists( $taxonomy ) ) {
  2796 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  2926 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  2797 	}
  2927 	}
  2798 
  2928 
  2799 	$term_id = (int) $term_id;
  2929 	$term_id = (int) $term_id;
  2800 
  2930 
  2801 	// First, get all of the original args
  2931 	// First, get all of the original args.
  2802 	$term = get_term( $term_id, $taxonomy );
  2932 	$term = get_term( $term_id, $taxonomy );
  2803 
  2933 
  2804 	if ( is_wp_error( $term ) ) {
  2934 	if ( is_wp_error( $term ) ) {
  2805 		return $term;
  2935 		return $term;
  2806 	}
  2936 	}
  2832 	$description = wp_unslash( $args['description'] );
  2962 	$description = wp_unslash( $args['description'] );
  2833 
  2963 
  2834 	$parsed_args['name']        = $name;
  2964 	$parsed_args['name']        = $name;
  2835 	$parsed_args['description'] = $description;
  2965 	$parsed_args['description'] = $description;
  2836 
  2966 
  2837 	if ( '' == trim( $name ) ) {
  2967 	if ( '' === trim( $name ) ) {
  2838 		return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) );
  2968 		return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) );
  2839 	}
  2969 	}
  2840 
  2970 
  2841 	if ( $parsed_args['parent'] > 0 && ! term_exists( (int) $parsed_args['parent'] ) ) {
  2971 	if ( $parsed_args['parent'] > 0 && ! term_exists( (int) $parsed_args['parent'] ) ) {
  2842 		return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
  2972 		return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
  2888 	 * @param int    $term_id     Term ID.
  3018 	 * @param int    $term_id     Term ID.
  2889 	 * @param string $taxonomy    Taxonomy slug.
  3019 	 * @param string $taxonomy    Taxonomy slug.
  2890 	 * @param array  $parsed_args An array of potentially altered update arguments for the given term.
  3020 	 * @param array  $parsed_args An array of potentially altered update arguments for the given term.
  2891 	 * @param array  $args        An array of update arguments for the given term.
  3021 	 * @param array  $args        An array of update arguments for the given term.
  2892 	 */
  3022 	 */
  2893 	$parent = apply_filters( 'wp_update_term_parent', $args['parent'], $term_id, $taxonomy, $parsed_args, $args );
  3023 	$parent = (int) apply_filters( 'wp_update_term_parent', $args['parent'], $term_id, $taxonomy, $parsed_args, $args );
  2894 
  3024 
  2895 	// Check for duplicate slug
  3025 	// Check for duplicate slug.
  2896 	$duplicate = get_term_by( 'slug', $slug, $taxonomy );
  3026 	$duplicate = get_term_by( 'slug', $slug, $taxonomy );
  2897 	if ( $duplicate && $duplicate->term_id != $term_id ) {
  3027 	if ( $duplicate && $duplicate->term_id !== $term_id ) {
  2898 		// If an empty slug was passed or the parent changed, reset the slug to something unique.
  3028 		// If an empty slug was passed or the parent changed, reset the slug to something unique.
  2899 		// Otherwise, bail.
  3029 		// Otherwise, bail.
  2900 		if ( $empty_slug || ( $parent != $term['parent'] ) ) {
  3030 		if ( $empty_slug || ( $parent !== (int) $term['parent'] ) ) {
  2901 			$slug = wp_unique_term_slug( $slug, (object) $args );
  3031 			$slug = wp_unique_term_slug( $slug, (object) $args );
  2902 		} else {
  3032 		} else {
  2903 			/* translators: %s: taxonomy term slug */
  3033 			/* translators: %s: Taxonomy term slug. */
  2904 			return new WP_Error( 'duplicate_term_slug', sprintf( __( 'The slug &#8220;%s&#8221; is already in use by another term.' ), $slug ) );
  3034 			return new WP_Error( 'duplicate_term_slug', sprintf( __( 'The slug &#8220;%s&#8221; is already in use by another term.' ), $slug ) );
  2905 		}
  3035 		}
  2906 	}
  3036 	}
  2907 
  3037 
  2908 	$tt_id = (int) $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 ) );
  3038 	$tt_id = (int) $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 ) );
  2936 	 * @param array  $args     Arguments passed to wp_update_term().
  3066 	 * @param array  $args     Arguments passed to wp_update_term().
  2937 	 */
  3067 	 */
  2938 	$data = apply_filters( 'wp_update_term_data', $data, $term_id, $taxonomy, $args );
  3068 	$data = apply_filters( 'wp_update_term_data', $data, $term_id, $taxonomy, $args );
  2939 
  3069 
  2940 	$wpdb->update( $wpdb->terms, $data, compact( 'term_id' ) );
  3070 	$wpdb->update( $wpdb->terms, $data, compact( 'term_id' ) );
       
  3071 
  2941 	if ( empty( $slug ) ) {
  3072 	if ( empty( $slug ) ) {
  2942 		$slug = sanitize_title( $name, $term_id );
  3073 		$slug = sanitize_title( $name, $term_id );
  2943 		$wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
  3074 		$wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
  2944 	}
  3075 	}
  2945 
  3076 
  3025 	 *
  3156 	 *
  3026 	 * @param int $term_id Term ID.
  3157 	 * @param int $term_id Term ID.
  3027 	 * @param int $tt_id   Term taxonomy ID.
  3158 	 * @param int $tt_id   Term taxonomy ID.
  3028 	 */
  3159 	 */
  3029 	do_action( "edited_{$taxonomy}", $term_id, $tt_id );
  3160 	do_action( "edited_{$taxonomy}", $term_id, $tt_id );
       
  3161 
       
  3162 	/** This action is documented in wp-includes/taxonomy.php */
       
  3163 	do_action( 'saved_term', $term_id, $tt_id, $taxonomy, true );
       
  3164 
       
  3165 	/** This action is documented in wp-includes/taxonomy.php */
       
  3166 	do_action( "saved_{$taxonomy}", $term_id, $tt_id, true );
  3030 
  3167 
  3031 	return array(
  3168 	return array(
  3032 		'term_id'          => $term_id,
  3169 		'term_id'          => $term_id,
  3033 		'term_taxonomy_id' => $tt_id,
  3170 		'term_taxonomy_id' => $tt_id,
  3034 	);
  3171 	);
  3037 /**
  3174 /**
  3038  * Enable or disable term counting.
  3175  * Enable or disable term counting.
  3039  *
  3176  *
  3040  * @since 2.5.0
  3177  * @since 2.5.0
  3041  *
  3178  *
  3042  * @staticvar bool $_defer
       
  3043  *
       
  3044  * @param bool $defer Optional. Enable if true, disable if false.
  3179  * @param bool $defer Optional. Enable if true, disable if false.
  3045  * @return bool Whether term counting is enabled or disabled.
  3180  * @return bool Whether term counting is enabled or disabled.
  3046  */
  3181  */
  3047 function wp_defer_term_counting( $defer = null ) {
  3182 function wp_defer_term_counting( $defer = null ) {
  3048 	static $_defer = false;
  3183 	static $_defer = false;
  3049 
  3184 
  3050 	if ( is_bool( $defer ) ) {
  3185 	if ( is_bool( $defer ) ) {
  3051 		$_defer = $defer;
  3186 		$_defer = $defer;
  3052 		// flush any deferred counts
  3187 		// Flush any deferred counts.
  3053 		if ( ! $defer ) {
  3188 		if ( ! $defer ) {
  3054 			wp_update_term_count( null, null, true );
  3189 			wp_update_term_count( null, null, true );
  3055 		}
  3190 		}
  3056 	}
  3191 	}
  3057 
  3192 
  3066  *
  3201  *
  3067  * The default action is to count what the amount of terms have the relationship
  3202  * The default action is to count what the amount of terms have the relationship
  3068  * of term ID. Once that is done, then update the database.
  3203  * of term ID. Once that is done, then update the database.
  3069  *
  3204  *
  3070  * @since 2.3.0
  3205  * @since 2.3.0
  3071  *
       
  3072  * @staticvar array $_deferred
       
  3073  *
  3206  *
  3074  * @param int|array $terms       The term_taxonomy_id of the terms.
  3207  * @param int|array $terms       The term_taxonomy_id of the terms.
  3075  * @param string    $taxonomy    The context of the term.
  3208  * @param string    $taxonomy    The context of the term.
  3076  * @param bool      $do_deferred Whether to flush the deferred term counts too. Default false.
  3209  * @param bool      $do_deferred Whether to flush the deferred term counts too. Default false.
  3077  * @return bool If no terms will return false, and if successful will return true.
  3210  * @return bool If no terms will return false, and if successful will return true.
  3126 			if ( 0 === strpos( $object_type, 'attachment:' ) ) {
  3259 			if ( 0 === strpos( $object_type, 'attachment:' ) ) {
  3127 				list( $object_type ) = explode( ':', $object_type );
  3260 				list( $object_type ) = explode( ':', $object_type );
  3128 			}
  3261 			}
  3129 		}
  3262 		}
  3130 
  3263 
  3131 		if ( $object_types == array_filter( $object_types, 'post_type_exists' ) ) {
  3264 		if ( array_filter( $object_types, 'post_type_exists' ) == $object_types ) {
  3132 			// Only post types are attached to this taxonomy
  3265 			// Only post types are attached to this taxonomy.
  3133 			_update_post_term_count( $terms, $taxonomy );
  3266 			_update_post_term_count( $terms, $taxonomy );
  3134 		} else {
  3267 		} else {
  3135 			// Default count updater
  3268 			// Default count updater.
  3136 			_update_generic_term_count( $terms, $taxonomy );
  3269 			_update_generic_term_count( $terms, $taxonomy );
  3137 		}
  3270 		}
  3138 	}
  3271 	}
  3139 
  3272 
  3140 	clean_term_cache( $terms, '', false );
  3273 	clean_term_cache( $terms, '', false );
  3141 
  3274 
  3142 	return true;
  3275 	return true;
  3143 }
  3276 }
  3144 
  3277 
  3145 //
  3278 //
  3146 // Cache
  3279 // Cache.
  3147 //
  3280 //
  3148 
  3281 
  3149 /**
  3282 /**
  3150  * Removes the taxonomy relationship to terms from the cache.
  3283  * Removes the taxonomy relationship to terms from the cache.
  3151  *
  3284  *
  3191 	 */
  3324 	 */
  3192 	do_action( 'clean_object_term_cache', $object_ids, $object_type );
  3325 	do_action( 'clean_object_term_cache', $object_ids, $object_type );
  3193 }
  3326 }
  3194 
  3327 
  3195 /**
  3328 /**
  3196  * Will remove all of the term ids from the cache.
  3329  * Will remove all of the term IDs from the cache.
  3197  *
  3330  *
  3198  * @since 2.3.0
  3331  * @since 2.3.0
  3199  *
  3332  *
  3200  * @global wpdb $wpdb WordPress database abstraction object.
  3333  * @global wpdb $wpdb                           WordPress database abstraction object.
  3201  * @global bool $_wp_suspend_cache_invalidation
  3334  * @global bool $_wp_suspend_cache_invalidation
  3202  *
  3335  *
  3203  * @param int|array $ids            Single or list of Term IDs.
  3336  * @param int|int[] $ids            Single or array of term IDs.
  3204  * @param string    $taxonomy       Optional. Can be empty and will assume `tt_ids`, else will use for context.
  3337  * @param string    $taxonomy       Optional. Taxonomy slug. Can be empty, in which case the taxonomies of the passed
  3205  *                                  Default empty.
  3338  *                                  term IDs will be used. Default empty.
  3206  * @param bool      $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual
  3339  * @param bool      $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual
  3207  *                                  term object caches (false). Default true.
  3340  *                                  term object caches (false). Default true.
  3208  */
  3341  */
  3209 function clean_term_cache( $ids, $taxonomy = '', $clean_taxonomy = true ) {
  3342 function clean_term_cache( $ids, $taxonomy = '', $clean_taxonomy = true ) {
  3210 	global $wpdb, $_wp_suspend_cache_invalidation;
  3343 	global $wpdb, $_wp_suspend_cache_invalidation;
  3222 	if ( empty( $taxonomy ) ) {
  3355 	if ( empty( $taxonomy ) ) {
  3223 		$tt_ids = array_map( 'intval', $ids );
  3356 		$tt_ids = array_map( 'intval', $ids );
  3224 		$tt_ids = implode( ', ', $tt_ids );
  3357 		$tt_ids = implode( ', ', $tt_ids );
  3225 		$terms  = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)" );
  3358 		$terms  = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)" );
  3226 		$ids    = array();
  3359 		$ids    = array();
       
  3360 
  3227 		foreach ( (array) $terms as $term ) {
  3361 		foreach ( (array) $terms as $term ) {
  3228 			$taxonomies[] = $term->taxonomy;
  3362 			$taxonomies[] = $term->taxonomy;
  3229 			$ids[]        = $term->term_id;
  3363 			$ids[]        = $term->term_id;
  3230 			wp_cache_delete( $term->term_id, 'terms' );
  3364 			wp_cache_delete( $term->term_id, 'terms' );
  3231 		}
  3365 		}
       
  3366 
  3232 		$taxonomies = array_unique( $taxonomies );
  3367 		$taxonomies = array_unique( $taxonomies );
  3233 	} else {
  3368 	} else {
  3234 		$taxonomies = array( $taxonomy );
  3369 		$taxonomies = array( $taxonomy );
       
  3370 
  3235 		foreach ( $taxonomies as $taxonomy ) {
  3371 		foreach ( $taxonomies as $taxonomy ) {
  3236 			foreach ( $ids as $id ) {
  3372 			foreach ( $ids as $id ) {
  3237 				wp_cache_delete( $id, 'terms' );
  3373 				wp_cache_delete( $id, 'terms' );
  3238 			}
  3374 			}
  3239 		}
  3375 		}
  3284 	 */
  3420 	 */
  3285 	do_action( 'clean_taxonomy_cache', $taxonomy );
  3421 	do_action( 'clean_taxonomy_cache', $taxonomy );
  3286 }
  3422 }
  3287 
  3423 
  3288 /**
  3424 /**
  3289  * Retrieves the taxonomy relationship to the term object id.
  3425  * Retrieves the cached term objects for the given object ID.
  3290  *
  3426  *
  3291  * Upstream functions (like get_the_terms() and is_object_in_term()) are
  3427  * Upstream functions (like get_the_terms() and is_object_in_term()) are
  3292  * responsible for populating the object-term relationship cache. The current
  3428  * responsible for populating the object-term relationship cache. The current
  3293  * function only fetches relationship data that is already in the cache.
  3429  * function only fetches relationship data that is already in the cache.
  3294  *
  3430  *
  3295  * @since 2.3.0
  3431  * @since 2.3.0
  3296  * @since 4.7.0 Returns a `WP_Error` object if `get_term()` returns an error for
  3432  * @since 4.7.0 Returns a `WP_Error` object if there's an error with
  3297  *              any of the matched terms.
  3433  *              any of the matched terms.
  3298  *
  3434  *
  3299  * @param int    $id       Term object ID.
  3435  * @param int    $id       Term object ID, for example a post, comment, or user ID.
  3300  * @param string $taxonomy Taxonomy name.
  3436  * @param string $taxonomy Taxonomy name.
  3301  * @return bool|array|WP_Error Array of `WP_Term` objects, if cached.
  3437  * @return bool|WP_Term[]|WP_Error Array of `WP_Term` objects, if cached.
  3302  *                             False if cache is empty for `$taxonomy` and `$id`.
  3438  *                                 False if cache is empty for `$taxonomy` and `$id`.
  3303  *                             WP_Error if get_term() returns an error object for any term.
  3439  *                                 WP_Error if get_term() returns an error object for any term.
  3304  */
  3440  */
  3305 function get_object_term_cache( $id, $taxonomy ) {
  3441 function get_object_term_cache( $id, $taxonomy ) {
  3306 	$_term_ids = wp_cache_get( $id, "{$taxonomy}_relationships" );
  3442 	$_term_ids = wp_cache_get( $id, "{$taxonomy}_relationships" );
  3307 
  3443 
  3308 	// We leave the priming of relationship caches to upstream functions.
  3444 	// We leave the priming of relationship caches to upstream functions.
  3346  *
  3482  *
  3347  * Caches will only be updated for terms not already cached.
  3483  * Caches will only be updated for terms not already cached.
  3348  *
  3484  *
  3349  * @since 2.3.0
  3485  * @since 2.3.0
  3350  *
  3486  *
  3351  * @param string|array $object_ids  Comma-separated list or array of term object IDs.
  3487  * @param string|int[]    $object_ids  Comma-separated list or array of term object IDs.
  3352  * @param array|string $object_type The taxonomy object type.
  3488  * @param string|string[] $object_type The taxonomy object type or array of the same.
  3353  * @return void|false False if all of the terms in `$object_ids` are already cached.
  3489  * @return void|false False if all of the terms in `$object_ids` are already cached.
  3354  */
  3490  */
  3355 function update_object_term_cache( $object_ids, $object_type ) {
  3491 function update_object_term_cache( $object_ids, $object_type ) {
  3356 	if ( empty( $object_ids ) ) {
  3492 	if ( empty( $object_ids ) ) {
  3357 		return;
  3493 		return;
  3359 
  3495 
  3360 	if ( ! is_array( $object_ids ) ) {
  3496 	if ( ! is_array( $object_ids ) ) {
  3361 		$object_ids = explode( ',', $object_ids );
  3497 		$object_ids = explode( ',', $object_ids );
  3362 	}
  3498 	}
  3363 
  3499 
  3364 	$object_ids = array_map( 'intval', $object_ids );
  3500 	$object_ids     = array_map( 'intval', $object_ids );
       
  3501 	$non_cached_ids = array();
  3365 
  3502 
  3366 	$taxonomies = get_object_taxonomies( $object_type );
  3503 	$taxonomies = get_object_taxonomies( $object_type );
  3367 
  3504 
  3368 	$ids = array();
  3505 	foreach ( $taxonomies as $taxonomy ) {
  3369 	foreach ( (array) $object_ids as $id ) {
  3506 		$cache_values = wp_cache_get_multiple( (array) $object_ids, "{$taxonomy}_relationships" );
  3370 		foreach ( $taxonomies as $taxonomy ) {
  3507 
  3371 			if ( false === wp_cache_get( $id, "{$taxonomy}_relationships" ) ) {
  3508 		foreach ( $cache_values as $id => $value ) {
  3372 				$ids[] = $id;
  3509 			if ( false === $value ) {
  3373 				break;
  3510 				$non_cached_ids[] = $id;
  3374 			}
  3511 			}
  3375 		}
  3512 		}
  3376 	}
  3513 	}
  3377 
  3514 
  3378 	if ( empty( $ids ) ) {
  3515 	if ( empty( $non_cached_ids ) ) {
  3379 		return false;
  3516 		return false;
  3380 	}
  3517 	}
  3381 
  3518 
       
  3519 	$non_cached_ids = array_unique( $non_cached_ids );
       
  3520 
  3382 	$terms = wp_get_object_terms(
  3521 	$terms = wp_get_object_terms(
  3383 		$ids,
  3522 		$non_cached_ids,
  3384 		$taxonomies,
  3523 		$taxonomies,
  3385 		array(
  3524 		array(
  3386 			'fields'                 => 'all_with_object_id',
  3525 			'fields'                 => 'all_with_object_id',
  3387 			'orderby'                => 'name',
  3526 			'orderby'                => 'name',
  3388 			'update_term_meta_cache' => false,
  3527 			'update_term_meta_cache' => false,
  3392 	$object_terms = array();
  3531 	$object_terms = array();
  3393 	foreach ( (array) $terms as $term ) {
  3532 	foreach ( (array) $terms as $term ) {
  3394 		$object_terms[ $term->object_id ][ $term->taxonomy ][] = $term->term_id;
  3533 		$object_terms[ $term->object_id ][ $term->taxonomy ][] = $term->term_id;
  3395 	}
  3534 	}
  3396 
  3535 
  3397 	foreach ( $ids as $id ) {
  3536 	foreach ( $non_cached_ids as $id ) {
  3398 		foreach ( $taxonomies as $taxonomy ) {
  3537 		foreach ( $taxonomies as $taxonomy ) {
  3399 			if ( ! isset( $object_terms[ $id ][ $taxonomy ] ) ) {
  3538 			if ( ! isset( $object_terms[ $id ][ $taxonomy ] ) ) {
  3400 				if ( ! isset( $object_terms[ $id ] ) ) {
  3539 				if ( ! isset( $object_terms[ $id ] ) ) {
  3401 					$object_terms[ $id ] = array();
  3540 					$object_terms[ $id ] = array();
  3402 				}
  3541 				}
  3415 /**
  3554 /**
  3416  * Updates Terms to Taxonomy in cache.
  3555  * Updates Terms to Taxonomy in cache.
  3417  *
  3556  *
  3418  * @since 2.3.0
  3557  * @since 2.3.0
  3419  *
  3558  *
  3420  * @param array  $terms    List of term objects to change.
  3559  * @param WP_Term[] $terms    Array of term objects to change.
  3421  * @param string $taxonomy Optional. Update Term to this taxonomy in cache. Default empty.
  3560  * @param string    $taxonomy Not used.
  3422  */
  3561  */
  3423 function update_term_cache( $terms, $taxonomy = '' ) {
  3562 function update_term_cache( $terms, $taxonomy = '' ) {
  3424 	foreach ( (array) $terms as $term ) {
  3563 	foreach ( (array) $terms as $term ) {
  3425 		// Create a copy in case the array was passed by reference.
  3564 		// Create a copy in case the array was passed by reference.
  3426 		$_term = clone $term;
  3565 		$_term = clone $term;
  3431 		wp_cache_add( $term->term_id, $_term, 'terms' );
  3570 		wp_cache_add( $term->term_id, $_term, 'terms' );
  3432 	}
  3571 	}
  3433 }
  3572 }
  3434 
  3573 
  3435 //
  3574 //
  3436 // Private
  3575 // Private.
  3437 //
  3576 //
  3438 
  3577 
  3439 /**
  3578 /**
  3440  * Retrieves children of taxonomy as Term IDs.
  3579  * Retrieves children of taxonomy as Term IDs.
  3441  *
  3580  *
  3454 	if ( is_array( $children ) ) {
  3593 	if ( is_array( $children ) ) {
  3455 		return $children;
  3594 		return $children;
  3456 	}
  3595 	}
  3457 	$children = array();
  3596 	$children = array();
  3458 	$terms    = get_terms(
  3597 	$terms    = get_terms(
  3459 		$taxonomy,
       
  3460 		array(
  3598 		array(
       
  3599 			'taxonomy'               => $taxonomy,
  3461 			'get'                    => 'all',
  3600 			'get'                    => 'all',
  3462 			'orderby'                => 'id',
  3601 			'orderby'                => 'id',
  3463 			'fields'                 => 'id=>parent',
  3602 			'fields'                 => 'id=>parent',
  3464 			'update_term_meta_cache' => false,
  3603 			'update_term_meta_cache' => false,
  3465 		)
  3604 		)
  3497 	$empty_array = array();
  3636 	$empty_array = array();
  3498 	if ( empty( $terms ) ) {
  3637 	if ( empty( $terms ) ) {
  3499 		return $empty_array;
  3638 		return $empty_array;
  3500 	}
  3639 	}
  3501 
  3640 
       
  3641 	$term_id      = (int) $term_id;
  3502 	$term_list    = array();
  3642 	$term_list    = array();
  3503 	$has_children = _get_term_hierarchy( $taxonomy );
  3643 	$has_children = _get_term_hierarchy( $taxonomy );
  3504 
  3644 
  3505 	if ( ( 0 != $term_id ) && ! isset( $has_children[ $term_id ] ) ) {
  3645 	if ( $term_id && ! isset( $has_children[ $term_id ] ) ) {
  3506 		return $empty_array;
  3646 		return $empty_array;
  3507 	}
  3647 	}
  3508 
  3648 
  3509 	// Include the term itself in the ancestors array, so we can properly detect when a loop has occurred.
  3649 	// Include the term itself in the ancestors array, so we can properly detect when a loop has occurred.
  3510 	if ( empty( $ancestors ) ) {
  3650 	if ( empty( $ancestors ) ) {
  3524 		// Don't recurse if we've already identified the term as a child - this indicates a loop.
  3664 		// Don't recurse if we've already identified the term as a child - this indicates a loop.
  3525 		if ( isset( $ancestors[ $term->term_id ] ) ) {
  3665 		if ( isset( $ancestors[ $term->term_id ] ) ) {
  3526 			continue;
  3666 			continue;
  3527 		}
  3667 		}
  3528 
  3668 
  3529 		if ( $term->parent == $term_id ) {
  3669 		if ( (int) $term->parent === $term_id ) {
  3530 			if ( $use_id ) {
  3670 			if ( $use_id ) {
  3531 				$term_list[] = $term->term_id;
  3671 				$term_list[] = $term->term_id;
  3532 			} else {
  3672 			} else {
  3533 				$term_list[] = $term;
  3673 				$term_list[] = $term;
  3534 			}
  3674 			}
  3537 				continue;
  3677 				continue;
  3538 			}
  3678 			}
  3539 
  3679 
  3540 			$ancestors[ $term->term_id ] = 1;
  3680 			$ancestors[ $term->term_id ] = 1;
  3541 
  3681 
  3542 			if ( $children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors ) ) {
  3682 			$children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors );
       
  3683 			if ( $children ) {
  3543 				$term_list = array_merge( $term_list, $children );
  3684 				$term_list = array_merge( $term_list, $children );
  3544 			}
  3685 			}
  3545 		}
  3686 		}
  3546 	}
  3687 	}
  3547 
  3688 
  3583 	foreach ( (array) $terms as $key => $term ) {
  3724 	foreach ( (array) $terms as $key => $term ) {
  3584 		$terms_by_id[ $term->term_id ]       = & $terms[ $key ];
  3725 		$terms_by_id[ $term->term_id ]       = & $terms[ $key ];
  3585 		$term_ids[ $term->term_taxonomy_id ] = $term->term_id;
  3726 		$term_ids[ $term->term_taxonomy_id ] = $term->term_id;
  3586 	}
  3727 	}
  3587 
  3728 
  3588 	// Get the object and term ids and stick them in a lookup table.
  3729 	// Get the object and term IDs and stick them in a lookup table.
  3589 	$tax_obj      = get_taxonomy( $taxonomy );
  3730 	$tax_obj      = get_taxonomy( $taxonomy );
  3590 	$object_types = esc_sql( $tax_obj->object_type );
  3731 	$object_types = esc_sql( $tax_obj->object_type );
  3591 	$results      = $wpdb->get_results( "SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode( ',', array_keys( $term_ids ) ) . ") AND post_type IN ('" . implode( "', '", $object_types ) . "') AND post_status = 'publish'" );
  3732 	$results      = $wpdb->get_results( "SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode( ',', array_keys( $term_ids ) ) . ") AND post_type IN ('" . implode( "', '", $object_types ) . "') AND post_status = 'publish'" );
       
  3733 
  3592 	foreach ( $results as $row ) {
  3734 	foreach ( $results as $row ) {
  3593 		$id                                   = $term_ids[ $row->term_taxonomy_id ];
  3735 		$id = $term_ids[ $row->term_taxonomy_id ];
       
  3736 
  3594 		$term_items[ $id ][ $row->object_id ] = isset( $term_items[ $id ][ $row->object_id ] ) ? ++$term_items[ $id ][ $row->object_id ] : 1;
  3737 		$term_items[ $id ][ $row->object_id ] = isset( $term_items[ $id ][ $row->object_id ] ) ? ++$term_items[ $id ][ $row->object_id ] : 1;
  3595 	}
  3738 	}
  3596 
  3739 
  3597 	// Touch every ancestor's lookup row for each post in each term.
  3740 	// Touch every ancestor's lookup row for each post in each term.
  3598 	foreach ( $term_ids as $term_id ) {
  3741 	foreach ( $term_ids as $term_id ) {
  3599 		$child     = $term_id;
  3742 		$child     = $term_id;
  3600 		$ancestors = array();
  3743 		$ancestors = array();
  3601 		while ( ! empty( $terms_by_id[ $child ] ) && $parent = $terms_by_id[ $child ]->parent ) {
  3744 		while ( ! empty( $terms_by_id[ $child ] ) && $parent = $terms_by_id[ $child ]->parent ) {
  3602 			$ancestors[] = $child;
  3745 			$ancestors[] = $child;
       
  3746 
  3603 			if ( ! empty( $term_items[ $term_id ] ) ) {
  3747 			if ( ! empty( $term_items[ $term_id ] ) ) {
  3604 				foreach ( $term_items[ $term_id ] as $item_id => $touches ) {
  3748 				foreach ( $term_items[ $term_id ] as $item_id => $touches ) {
  3605 					$term_items[ $parent ][ $item_id ] = isset( $term_items[ $parent ][ $item_id ] ) ? ++$term_items[ $parent ][ $item_id ] : 1;
  3749 					$term_items[ $parent ][ $item_id ] = isset( $term_items[ $parent ][ $item_id ] ) ? ++$term_items[ $parent ][ $item_id ] : 1;
  3606 				}
  3750 				}
  3607 			}
  3751 			}
       
  3752 
  3608 			$child = $parent;
  3753 			$child = $parent;
  3609 
  3754 
  3610 			if ( in_array( $parent, $ancestors ) ) {
  3755 			if ( in_array( $parent, $ancestors, true ) ) {
  3611 				break;
  3756 				break;
  3612 			}
  3757 			}
  3613 		}
  3758 		}
  3614 	}
  3759 	}
  3615 
  3760 
  3646 		}
  3791 		}
  3647 	}
  3792 	}
  3648 }
  3793 }
  3649 
  3794 
  3650 //
  3795 //
  3651 // Default callbacks
  3796 // Default callbacks.
  3652 //
  3797 //
  3653 
  3798 
  3654 /**
  3799 /**
  3655  * Will update term count based on object types of the current taxonomy.
  3800  * Will update term count based on object types of the current taxonomy.
  3656  *
  3801  *
  3660  * @access private
  3805  * @access private
  3661  * @since 2.3.0
  3806  * @since 2.3.0
  3662  *
  3807  *
  3663  * @global wpdb $wpdb WordPress database abstraction object.
  3808  * @global wpdb $wpdb WordPress database abstraction object.
  3664  *
  3809  *
  3665  * @param array  $terms    List of Term taxonomy IDs.
  3810  * @param int[]       $terms    List of Term taxonomy IDs.
  3666  * @param object $taxonomy Current taxonomy object of terms.
  3811  * @param WP_Taxonomy $taxonomy Current taxonomy object of terms.
  3667  */
  3812  */
  3668 function _update_post_term_count( $terms, $taxonomy ) {
  3813 function _update_post_term_count( $terms, $taxonomy ) {
  3669 	global $wpdb;
  3814 	global $wpdb;
  3670 
  3815 
  3671 	$object_types = (array) $taxonomy->object_type;
  3816 	$object_types = (array) $taxonomy->object_type;
  3674 		list( $object_type ) = explode( ':', $object_type );
  3819 		list( $object_type ) = explode( ':', $object_type );
  3675 	}
  3820 	}
  3676 
  3821 
  3677 	$object_types = array_unique( $object_types );
  3822 	$object_types = array_unique( $object_types );
  3678 
  3823 
  3679 	if ( false !== ( $check_attachments = array_search( 'attachment', $object_types ) ) ) {
  3824 	$check_attachments = array_search( 'attachment', $object_types, true );
       
  3825 	if ( false !== $check_attachments ) {
  3680 		unset( $object_types[ $check_attachments ] );
  3826 		unset( $object_types[ $check_attachments ] );
  3681 		$check_attachments = true;
  3827 		$check_attachments = true;
  3682 	}
  3828 	}
  3683 
  3829 
  3684 	if ( $object_types ) {
  3830 	if ( $object_types ) {
  3692 		if ( $check_attachments ) {
  3838 		if ( $check_attachments ) {
  3693 			$count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) );
  3839 			$count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) );
  3694 		}
  3840 		}
  3695 
  3841 
  3696 		if ( $object_types ) {
  3842 		if ( $object_types ) {
       
  3843 			// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedDynamicPlaceholderGeneration
  3697 			$count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode( "', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) );
  3844 			$count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode( "', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) );
  3698 		}
  3845 		}
  3699 
  3846 
  3700 		/** This action is documented in wp-includes/taxonomy.php */
  3847 		/** This action is documented in wp-includes/taxonomy.php */
  3701 		do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
  3848 		do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
  3713  *
  3860  *
  3714  * @since 3.3.0
  3861  * @since 3.3.0
  3715  *
  3862  *
  3716  * @global wpdb $wpdb WordPress database abstraction object.
  3863  * @global wpdb $wpdb WordPress database abstraction object.
  3717  *
  3864  *
  3718  * @param array  $terms    List of term taxonomy IDs.
  3865  * @param int[]       $terms    List of term taxonomy IDs.
  3719  * @param object $taxonomy Current taxonomy object of terms.
  3866  * @param WP_Taxonomy $taxonomy Current taxonomy object of terms.
  3720  */
  3867  */
  3721 function _update_generic_term_count( $terms, $taxonomy ) {
  3868 function _update_generic_term_count( $terms, $taxonomy ) {
  3722 	global $wpdb;
  3869 	global $wpdb;
  3723 
  3870 
  3724 	foreach ( (array) $terms as $term ) {
  3871 	foreach ( (array) $terms as $term ) {
  3768 		$term_taxonomy    = $term_taxonomy_id;
  3915 		$term_taxonomy    = $term_taxonomy_id;
  3769 		$term_taxonomy_id = intval( $term_taxonomy->term_taxonomy_id );
  3916 		$term_taxonomy_id = intval( $term_taxonomy->term_taxonomy_id );
  3770 	}
  3917 	}
  3771 
  3918 
  3772 	// If there are no shared term_taxonomy rows, there's nothing to do here.
  3919 	// If there are no shared term_taxonomy rows, there's nothing to do here.
  3773 	$shared_tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy tt WHERE tt.term_id = %d AND tt.term_taxonomy_id != %d", $term_id, $term_taxonomy_id ) );
  3920 	$shared_tt_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy tt WHERE tt.term_id = %d AND tt.term_taxonomy_id != %d", $term_id, $term_taxonomy_id ) );
  3774 
  3921 
  3775 	if ( ! $shared_tt_count ) {
  3922 	if ( ! $shared_tt_count ) {
  3776 		return $term_id;
  3923 		return $term_id;
  3777 	}
  3924 	}
  3778 
  3925 
  3779 	/*
  3926 	/*
  3780 	 * Verify that the term_taxonomy_id passed to the function is actually associated with the term_id.
  3927 	 * Verify that the term_taxonomy_id passed to the function is actually associated with the term_id.
  3781 	 * If there's a mismatch, it may mean that the term is already split. Return the actual term_id from the db.
  3928 	 * If there's a mismatch, it may mean that the term is already split. Return the actual term_id from the db.
  3782 	 */
  3929 	 */
  3783 	$check_term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) );
  3930 	$check_term_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) );
  3784 	if ( $check_term_id != $term_id ) {
  3931 	if ( $check_term_id !== $term_id ) {
  3785 		return $check_term_id;
  3932 		return $check_term_id;
  3786 	}
  3933 	}
  3787 
  3934 
  3788 	// Pull up data about the currently shared slug, which we'll use to populate the new one.
  3935 	// Pull up data about the currently shared slug, which we'll use to populate the new one.
  3789 	if ( empty( $shared_term ) ) {
  3936 	if ( empty( $shared_term ) ) {
  3942 	$shared_term_ids = implode( ',', array_keys( $shared_terms ) );
  4089 	$shared_term_ids = implode( ',', array_keys( $shared_terms ) );
  3943 	$shared_tts      = $wpdb->get_results( "SELECT * FROM {$wpdb->term_taxonomy} WHERE `term_id` IN ({$shared_term_ids})" );
  4090 	$shared_tts      = $wpdb->get_results( "SELECT * FROM {$wpdb->term_taxonomy} WHERE `term_id` IN ({$shared_term_ids})" );
  3944 
  4091 
  3945 	// Split term data recording is slow, so we do it just once, outside the loop.
  4092 	// Split term data recording is slow, so we do it just once, outside the loop.
  3946 	$split_term_data    = get_option( '_split_terms', array() );
  4093 	$split_term_data    = get_option( '_split_terms', array() );
  3947 	$skipped_first_term = $taxonomies = array();
  4094 	$skipped_first_term = array();
       
  4095 	$taxonomies         = array();
  3948 	foreach ( $shared_tts as $shared_tt ) {
  4096 	foreach ( $shared_tts as $shared_tt ) {
  3949 		$term_id = intval( $shared_tt->term_id );
  4097 		$term_id = intval( $shared_tt->term_id );
  3950 
  4098 
  3951 		// Don't split the first tt belonging to a given term_id.
  4099 		// Don't split the first tt belonging to a given term_id.
  3952 		if ( ! isset( $skipped_first_term[ $term_id ] ) ) {
  4100 		if ( ! isset( $skipped_first_term[ $term_id ] ) ) {
  4001  * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
  4149  * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
  4002  * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
  4150  * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
  4003  * @param string $taxonomy         Taxonomy for the split term.
  4151  * @param string $taxonomy         Taxonomy for the split term.
  4004  */
  4152  */
  4005 function _wp_check_split_default_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
  4153 function _wp_check_split_default_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
  4006 	if ( 'category' != $taxonomy ) {
  4154 	if ( 'category' !== $taxonomy ) {
  4007 		return;
  4155 		return;
  4008 	}
  4156 	}
  4009 
  4157 
  4010 	foreach ( array( 'default_category', 'default_link_category', 'default_email_category' ) as $option ) {
  4158 	foreach ( array( 'default_category', 'default_link_category', 'default_email_category' ) as $option ) {
  4011 		if ( $term_id == get_option( $option, -1 ) ) {
  4159 		if ( (int) get_option( $option, -1 ) === $term_id ) {
  4012 			update_option( $option, $new_term_id );
  4160 			update_option( $option, $new_term_id );
  4013 		}
  4161 		}
  4014 	}
  4162 	}
  4015 }
  4163 }
  4016 
  4164 
  4067 	}
  4215 	}
  4068 
  4216 
  4069 	// Update menu locations.
  4217 	// Update menu locations.
  4070 	$locations = get_nav_menu_locations();
  4218 	$locations = get_nav_menu_locations();
  4071 	foreach ( $locations as $location => $menu_id ) {
  4219 	foreach ( $locations as $location => $menu_id ) {
  4072 		if ( $term_id == $menu_id ) {
  4220 		if ( $term_id === $menu_id ) {
  4073 			$locations[ $location ] = $new_term_id;
  4221 			$locations[ $location ] = $new_term_id;
  4074 		}
  4222 		}
  4075 	}
  4223 	}
  4076 	set_theme_mod( 'nav_menu_locations', $locations );
  4224 	set_theme_mod( 'nav_menu_locations', $locations );
  4077 }
  4225 }
  4144 /**
  4292 /**
  4145  * Generate a permalink for a taxonomy term archive.
  4293  * Generate a permalink for a taxonomy term archive.
  4146  *
  4294  *
  4147  * @since 2.5.0
  4295  * @since 2.5.0
  4148  *
  4296  *
  4149  * @global WP_Rewrite $wp_rewrite
  4297  * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
  4150  *
  4298  *
  4151  * @param object|int|string $term     The term object, ID, or slug whose link will be retrieved.
  4299  * @param WP_Term|int|string $term     The term object, ID, or slug whose link will be retrieved.
  4152  * @param string            $taxonomy Optional. Taxonomy. Default empty.
  4300  * @param string             $taxonomy Optional. Taxonomy. Default empty.
  4153  * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
  4301  * @return string|WP_Error URL of the taxonomy term archive on success, WP_Error if term does not exist.
  4154  */
  4302  */
  4155 function get_term_link( $term, $taxonomy = '' ) {
  4303 function get_term_link( $term, $taxonomy = '' ) {
  4156 	global $wp_rewrite;
  4304 	global $wp_rewrite;
  4157 
  4305 
  4158 	if ( ! is_object( $term ) ) {
  4306 	if ( ! is_object( $term ) ) {
  4187 
  4335 
  4188 	$slug = $term->slug;
  4336 	$slug = $term->slug;
  4189 	$t    = get_taxonomy( $taxonomy );
  4337 	$t    = get_taxonomy( $taxonomy );
  4190 
  4338 
  4191 	if ( empty( $termlink ) ) {
  4339 	if ( empty( $termlink ) ) {
  4192 		if ( 'category' == $taxonomy ) {
  4340 		if ( 'category' === $taxonomy ) {
  4193 			$termlink = '?cat=' . $term->term_id;
  4341 			$termlink = '?cat=' . $term->term_id;
  4194 		} elseif ( $t->query_var ) {
  4342 		} elseif ( $t->query_var ) {
  4195 			$termlink = "?$t->query_var=$slug";
  4343 			$termlink = "?$t->query_var=$slug";
  4196 		} else {
  4344 		} else {
  4197 			$termlink = "?taxonomy=$taxonomy&term=$slug";
  4345 			$termlink = "?taxonomy=$taxonomy&term=$slug";
  4211 		} else {
  4359 		} else {
  4212 			$termlink = str_replace( "%$taxonomy%", $slug, $termlink );
  4360 			$termlink = str_replace( "%$taxonomy%", $slug, $termlink );
  4213 		}
  4361 		}
  4214 		$termlink = home_url( user_trailingslashit( $termlink, 'category' ) );
  4362 		$termlink = home_url( user_trailingslashit( $termlink, 'category' ) );
  4215 	}
  4363 	}
  4216 	// Back Compat filters.
  4364 
  4217 	if ( 'post_tag' == $taxonomy ) {
  4365 	// Back compat filters.
       
  4366 	if ( 'post_tag' === $taxonomy ) {
  4218 
  4367 
  4219 		/**
  4368 		/**
  4220 		 * Filters the tag link.
  4369 		 * Filters the tag link.
  4221 		 *
  4370 		 *
  4222 		 * @since 2.3.0
  4371 		 * @since 2.3.0
  4223 		 * @deprecated 2.5.0 Use 'term_link' instead.
  4372 		 * @since 2.5.0 Deprecated in favor of {@see 'term_link'} filter.
       
  4373 		 * @since 5.4.1 Restored (un-deprecated).
  4224 		 *
  4374 		 *
  4225 		 * @param string $termlink Tag link URL.
  4375 		 * @param string $termlink Tag link URL.
  4226 		 * @param int    $term_id  Term ID.
  4376 		 * @param int    $term_id  Term ID.
  4227 		 */
  4377 		 */
  4228 		$termlink = apply_filters( 'tag_link', $termlink, $term->term_id );
  4378 		$termlink = apply_filters( 'tag_link', $termlink, $term->term_id );
  4229 	} elseif ( 'category' == $taxonomy ) {
  4379 	} elseif ( 'category' === $taxonomy ) {
  4230 
  4380 
  4231 		/**
  4381 		/**
  4232 		 * Filters the category link.
  4382 		 * Filters the category link.
  4233 		 *
  4383 		 *
  4234 		 * @since 1.5.0
  4384 		 * @since 1.5.0
  4235 		 * @deprecated 2.5.0 Use 'term_link' instead.
  4385 		 * @since 2.5.0 Deprecated in favor of {@see 'term_link'} filter.
       
  4386 		 * @since 5.4.1 Restored (un-deprecated).
  4236 		 *
  4387 		 *
  4237 		 * @param string $termlink Category link URL.
  4388 		 * @param string $termlink Category link URL.
  4238 		 * @param int    $term_id  Term ID.
  4389 		 * @param int    $term_id  Term ID.
  4239 		 */
  4390 		 */
  4240 		$termlink = apply_filters( 'category_link', $termlink, $term->term_id );
  4391 		$termlink = apply_filters( 'category_link', $termlink, $term->term_id );
  4243 	/**
  4394 	/**
  4244 	 * Filters the term link.
  4395 	 * Filters the term link.
  4245 	 *
  4396 	 *
  4246 	 * @since 2.5.0
  4397 	 * @since 2.5.0
  4247 	 *
  4398 	 *
  4248 	 * @param string $termlink Term link URL.
  4399 	 * @param string  $termlink Term link URL.
  4249 	 * @param object $term     Term object.
  4400 	 * @param WP_Term $term     Term object.
  4250 	 * @param string $taxonomy Taxonomy slug.
  4401 	 * @param string  $taxonomy Taxonomy slug.
  4251 	 */
  4402 	 */
  4252 	return apply_filters( 'term_link', $termlink, $term, $taxonomy );
  4403 	return apply_filters( 'term_link', $termlink, $term, $taxonomy );
  4253 }
  4404 }
  4254 
  4405 
  4255 /**
  4406 /**
  4277 		'before' => '',
  4428 		'before' => '',
  4278 		'sep'    => ' ',
  4429 		'sep'    => ' ',
  4279 		'after'  => '',
  4430 		'after'  => '',
  4280 	);
  4431 	);
  4281 
  4432 
  4282 	$r = wp_parse_args( $args, $defaults );
  4433 	$parsed_args = wp_parse_args( $args, $defaults );
  4283 
  4434 
  4284 	echo $r['before'] . join( $r['sep'], get_the_taxonomies( $r['post'], $r ) ) . $r['after'];
  4435 	echo $parsed_args['before'] . join( $parsed_args['sep'], get_the_taxonomies( $parsed_args['post'], $parsed_args ) ) . $parsed_args['after'];
  4285 }
  4436 }
  4286 
  4437 
  4287 /**
  4438 /**
  4288  * Retrieve all taxonomies associated with a post.
  4439  * Retrieve all taxonomies associated with a post.
  4289  *
  4440  *
  4291  * the taxonomies with links to the taxonomy and name.
  4442  * the taxonomies with links to the taxonomy and name.
  4292  *
  4443  *
  4293  * @since 2.5.0
  4444  * @since 2.5.0
  4294  *
  4445  *
  4295  * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
  4446  * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
  4296  * @param array $args {
  4447  * @param array       $args {
  4297  *     Optional. Arguments about how to format the list of taxonomies. Default empty array.
  4448  *           Optional. Arguments about how to format the list of taxonomies. Default empty array.
  4298  *
  4449  *
  4299  *     @type string $template      Template for displaying a taxonomy label and list of terms.
  4450  *     @type string $template      Template for displaying a taxonomy label and list of terms.
  4300  *                                 Default is "Label: Terms."
  4451  *                                 Default is "Label: Terms."
  4301  *     @type string $term_template Template for displaying a single term in the list. Default is the term name
  4452  *     @type string $term_template Template for displaying a single term in the list. Default is the term name
  4302  *                                 linked to its archive.
  4453  *                                 linked to its archive.
  4307 	$post = get_post( $post );
  4458 	$post = get_post( $post );
  4308 
  4459 
  4309 	$args = wp_parse_args(
  4460 	$args = wp_parse_args(
  4310 		$args,
  4461 		$args,
  4311 		array(
  4462 		array(
  4312 			/* translators: %s: taxonomy label, %l: list of terms formatted as per $term_template */
  4463 			/* translators: %s: Taxonomy label, %l: List of terms formatted as per $term_template. */
  4313 			'template'      => __( '%s: %l.' ),
  4464 			'template'      => __( '%s: %l.' ),
  4314 			'term_template' => '<a href="%1$s">%2$s</a>',
  4465 			'term_template' => '<a href="%1$s">%2$s</a>',
  4315 		)
  4466 		)
  4316 	);
  4467 	);
  4317 
  4468 
  4351 	}
  4502 	}
  4352 	return $taxonomies;
  4503 	return $taxonomies;
  4353 }
  4504 }
  4354 
  4505 
  4355 /**
  4506 /**
  4356  * Retrieve all taxonomies of a post with just the names.
  4507  * Retrieve all taxonomy names for the given post.
  4357  *
  4508  *
  4358  * @since 2.5.0
  4509  * @since 2.5.0
  4359  *
  4510  *
  4360  * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
  4511  * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
  4361  * @return array An array of all taxonomy names for the given post.
  4512  * @return string[] An array of all taxonomy names for the given post.
  4362  */
  4513  */
  4363 function get_post_taxonomies( $post = 0 ) {
  4514 function get_post_taxonomies( $post = 0 ) {
  4364 	$post = get_post( $post );
  4515 	$post = get_post( $post );
  4365 
  4516 
  4366 	return get_object_taxonomies( $post );
  4517 	return get_object_taxonomies( $post );
  4379  * @param string           $taxonomy  Single taxonomy name.
  4530  * @param string           $taxonomy  Single taxonomy name.
  4380  * @param int|string|array $terms     Optional. Term term_id, name, slug or array of said. Default null.
  4531  * @param int|string|array $terms     Optional. Term term_id, name, slug or array of said. Default null.
  4381  * @return bool|WP_Error WP_Error on input error.
  4532  * @return bool|WP_Error WP_Error on input error.
  4382  */
  4533  */
  4383 function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
  4534 function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
  4384 	if ( ! $object_id = (int) $object_id ) {
  4535 	$object_id = (int) $object_id;
       
  4536 	if ( ! $object_id ) {
  4385 		return new WP_Error( 'invalid_object', __( 'Invalid object ID.' ) );
  4537 		return new WP_Error( 'invalid_object', __( 'Invalid object ID.' ) );
  4386 	}
  4538 	}
  4387 
  4539 
  4388 	$object_terms = get_object_term_cache( $object_id, $taxonomy );
  4540 	$object_terms = get_object_term_cache( $object_id, $taxonomy );
  4389 	if ( false === $object_terms ) {
  4541 	if ( false === $object_terms ) {
  4405 		return ( ! empty( $object_terms ) );
  4557 		return ( ! empty( $object_terms ) );
  4406 	}
  4558 	}
  4407 
  4559 
  4408 	$terms = (array) $terms;
  4560 	$terms = (array) $terms;
  4409 
  4561 
  4410 	if ( $ints = array_filter( $terms, 'is_int' ) ) {
  4562 	$ints = array_filter( $terms, 'is_int' );
       
  4563 	if ( $ints ) {
  4411 		$strs = array_diff( $terms, $ints );
  4564 		$strs = array_diff( $terms, $ints );
  4412 	} else {
  4565 	} else {
  4413 		$strs =& $terms;
  4566 		$strs =& $terms;
  4414 	}
  4567 	}
  4415 
  4568 
  4416 	foreach ( $object_terms as $object_term ) {
  4569 	foreach ( $object_terms as $object_term ) {
  4417 		// If term is an int, check against term_ids only.
  4570 		// If term is an int, check against term_ids only.
  4418 		if ( $ints && in_array( $object_term->term_id, $ints ) ) {
  4571 		if ( $ints && in_array( $object_term->term_id, $ints, true ) ) {
  4419 			return true;
  4572 			return true;
  4420 		}
  4573 		}
  4421 
  4574 
  4422 		if ( $strs ) {
  4575 		if ( $strs ) {
  4423 			// Only check numeric strings against term_id, to avoid false matches due to type juggling.
  4576 			// Only check numeric strings against term_id, to avoid false matches due to type juggling.
  4424 			$numeric_strs = array_map( 'intval', array_filter( $strs, 'is_numeric' ) );
  4577 			$numeric_strs = array_map( 'intval', array_filter( $strs, 'is_numeric' ) );
  4425 			if ( in_array( $object_term->term_id, $numeric_strs, true ) ) {
  4578 			if ( in_array( $object_term->term_id, $numeric_strs, true ) ) {
  4426 				return true;
  4579 				return true;
  4427 			}
  4580 			}
  4428 
  4581 
  4429 			if ( in_array( $object_term->name, $strs ) ) {
  4582 			if ( in_array( $object_term->name, $strs, true ) ) {
  4430 				return true;
  4583 				return true;
  4431 			}
  4584 			}
  4432 			if ( in_array( $object_term->slug, $strs ) ) {
  4585 			if ( in_array( $object_term->slug, $strs, true ) ) {
  4433 				return true;
  4586 				return true;
  4434 			}
  4587 			}
  4435 		}
  4588 		}
  4436 	}
  4589 	}
  4437 
  4590 
  4450 function is_object_in_taxonomy( $object_type, $taxonomy ) {
  4603 function is_object_in_taxonomy( $object_type, $taxonomy ) {
  4451 	$taxonomies = get_object_taxonomies( $object_type );
  4604 	$taxonomies = get_object_taxonomies( $object_type );
  4452 	if ( empty( $taxonomies ) ) {
  4605 	if ( empty( $taxonomies ) ) {
  4453 		return false;
  4606 		return false;
  4454 	}
  4607 	}
  4455 	return in_array( $taxonomy, $taxonomies );
  4608 	return in_array( $taxonomy, $taxonomies, true );
  4456 }
  4609 }
  4457 
  4610 
  4458 /**
  4611 /**
  4459  * Get an array of ancestor IDs for a given object.
  4612  * Get an array of ancestor IDs for a given object.
  4460  *
  4613  *
  4464  * @param int    $object_id     Optional. The ID of the object. Default 0.
  4617  * @param int    $object_id     Optional. The ID of the object. Default 0.
  4465  * @param string $object_type   Optional. The type of object for which we'll be retrieving
  4618  * @param string $object_type   Optional. The type of object for which we'll be retrieving
  4466  *                              ancestors. Accepts a post type or a taxonomy name. Default empty.
  4619  *                              ancestors. Accepts a post type or a taxonomy name. Default empty.
  4467  * @param string $resource_type Optional. Type of resource $object_type is. Accepts 'post_type'
  4620  * @param string $resource_type Optional. Type of resource $object_type is. Accepts 'post_type'
  4468  *                              or 'taxonomy'. Default empty.
  4621  *                              or 'taxonomy'. Default empty.
  4469  * @return array An array of ancestors from lowest to highest in the hierarchy.
  4622  * @return int[] An array of IDs of ancestors from lowest to highest in the hierarchy.
  4470  */
  4623  */
  4471 function get_ancestors( $object_id = 0, $object_type = '', $resource_type = '' ) {
  4624 function get_ancestors( $object_id = 0, $object_type = '', $resource_type = '' ) {
  4472 	$object_id = (int) $object_id;
  4625 	$object_id = (int) $object_id;
  4473 
  4626 
  4474 	$ancestors = array();
  4627 	$ancestors = array();
  4487 		}
  4640 		}
  4488 	}
  4641 	}
  4489 
  4642 
  4490 	if ( 'taxonomy' === $resource_type ) {
  4643 	if ( 'taxonomy' === $resource_type ) {
  4491 		$term = get_term( $object_id, $object_type );
  4644 		$term = get_term( $object_id, $object_type );
  4492 		while ( ! is_wp_error( $term ) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors ) ) {
  4645 		while ( ! is_wp_error( $term ) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors, true ) ) {
  4493 			$ancestors[] = (int) $term->parent;
  4646 			$ancestors[] = (int) $term->parent;
  4494 			$term        = get_term( $term->parent, $object_type );
  4647 			$term        = get_term( $term->parent, $object_type );
  4495 		}
  4648 		}
  4496 	} elseif ( 'post_type' === $resource_type ) {
  4649 	} elseif ( 'post_type' === $resource_type ) {
  4497 		$ancestors = get_post_ancestors( $object_id );
  4650 		$ancestors = get_post_ancestors( $object_id );
  4501 	 * Filters a given object's ancestors.
  4654 	 * Filters a given object's ancestors.
  4502 	 *
  4655 	 *
  4503 	 * @since 3.1.0
  4656 	 * @since 3.1.0
  4504 	 * @since 4.1.1 Introduced the `$resource_type` parameter.
  4657 	 * @since 4.1.1 Introduced the `$resource_type` parameter.
  4505 	 *
  4658 	 *
  4506 	 * @param array  $ancestors     An array of object ancestors.
  4659 	 * @param int[]  $ancestors     An array of IDs of object ancestors.
  4507 	 * @param int    $object_id     Object ID.
  4660 	 * @param int    $object_id     Object ID.
  4508 	 * @param string $object_type   Type of object.
  4661 	 * @param string $object_type   Type of object.
  4509 	 * @param string $resource_type Type of resource $object_type is.
  4662 	 * @param string $resource_type Type of resource $object_type is.
  4510 	 */
  4663 	 */
  4511 	return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type );
  4664 	return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type );
  4537  * @since 3.1.0
  4690  * @since 3.1.0
  4538  *
  4691  *
  4539  * @param int    $parent   `term_id` of the parent for the term we're checking.
  4692  * @param int    $parent   `term_id` of the parent for the term we're checking.
  4540  * @param int    $term_id  The term we're checking.
  4693  * @param int    $term_id  The term we're checking.
  4541  * @param string $taxonomy The taxonomy of the term we're checking.
  4694  * @param string $taxonomy The taxonomy of the term we're checking.
  4542  *
       
  4543  * @return int The new parent for the term.
  4695  * @return int The new parent for the term.
  4544  */
  4696  */
  4545 function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) {
  4697 function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) {
  4546 	// Nothing fancy here - bail
  4698 	// Nothing fancy here - bail.
  4547 	if ( ! $parent ) {
  4699 	if ( ! $parent ) {
  4548 		return 0;
  4700 		return 0;
  4549 	}
  4701 	}
  4550 
  4702 
  4551 	// Can't be its own parent.
  4703 	// Can't be its own parent.
  4552 	if ( $parent == $term_id ) {
  4704 	if ( $parent === $term_id ) {
  4553 		return 0;
  4705 		return 0;
  4554 	}
  4706 	}
  4555 
  4707 
  4556 	// Now look for larger loops.
  4708 	// Now look for larger loops.
  4557 	if ( ! $loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ) ) {
  4709 	$loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) );
  4558 		return $parent; // No loop
  4710 	if ( ! $loop ) {
       
  4711 		return $parent; // No loop.
  4559 	}
  4712 	}
  4560 
  4713 
  4561 	// Setting $parent to the given value causes a loop.
  4714 	// Setting $parent to the given value causes a loop.
  4562 	if ( isset( $loop[ $term_id ] ) ) {
  4715 	if ( isset( $loop[ $term_id ] ) ) {
  4563 		return 0;
  4716 		return 0;