wp/wp-includes/taxonomy.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
    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' ) ) {
    28 		$rewrite = array( 'category' => false, 'post_tag' => false, 'post_format' => false );
    28 		$rewrite = array(
       
    29 			'category'    => false,
       
    30 			'post_tag'    => false,
       
    31 			'post_format' => false,
       
    32 		);
    29 	} else {
    33 	} else {
    30 
    34 
    31 		/**
    35 		/**
    32 		 * Filters the post formats rewrite base.
    36 		 * Filters the post formats rewrite base.
    33 		 *
    37 		 *
    34 		 * @since 3.1.0
    38 		 * @since 3.1.0
    35 		 *
    39 		 *
    36 		 * @param string $context Context of the rewrite base. Default 'type'.
    40 		 * @param string $context Context of the rewrite base. Default 'type'.
    37 		 */
    41 		 */
    38 		$post_format_base = apply_filters( 'post_format_rewrite_base', 'type' );
    42 		$post_format_base = apply_filters( 'post_format_rewrite_base', 'type' );
    39 		$rewrite = array(
    43 		$rewrite          = array(
    40 			'category' => array(
    44 			'category'    => array(
    41 				'hierarchical' => true,
    45 				'hierarchical' => true,
    42 				'slug' => get_option('category_base') ? get_option('category_base') : 'category',
    46 				'slug'         => get_option( 'category_base' ) ? get_option( 'category_base' ) : 'category',
    43 				'with_front' => ! get_option('category_base') || $wp_rewrite->using_index_permalinks(),
    47 				'with_front'   => ! get_option( 'category_base' ) || $wp_rewrite->using_index_permalinks(),
    44 				'ep_mask' => EP_CATEGORIES,
    48 				'ep_mask'      => EP_CATEGORIES,
    45 			),
    49 			),
    46 			'post_tag' => array(
    50 			'post_tag'    => array(
    47 				'hierarchical' => false,
    51 				'hierarchical' => false,
    48 				'slug' => get_option('tag_base') ? get_option('tag_base') : 'tag',
    52 				'slug'         => get_option( 'tag_base' ) ? get_option( 'tag_base' ) : 'tag',
    49 				'with_front' => ! get_option('tag_base') || $wp_rewrite->using_index_permalinks(),
    53 				'with_front'   => ! get_option( 'tag_base' ) || $wp_rewrite->using_index_permalinks(),
    50 				'ep_mask' => EP_TAGS,
    54 				'ep_mask'      => EP_TAGS,
    51 			),
    55 			),
    52 			'post_format' => $post_format_base ? array( 'slug' => $post_format_base ) : false,
    56 			'post_format' => $post_format_base ? array( 'slug' => $post_format_base ) : false,
    53 		);
    57 		);
    54 	}
    58 	}
    55 
    59 
    56 	register_taxonomy( 'category', 'post', array(
    60 	register_taxonomy(
    57 		'hierarchical' => true,
    61 		'category',
    58 		'query_var' => 'category_name',
    62 		'post',
    59 		'rewrite' => $rewrite['category'],
    63 		array(
    60 		'public' => true,
    64 			'hierarchical'          => true,
    61 		'show_ui' => true,
    65 			'query_var'             => 'category_name',
    62 		'show_admin_column' => true,
    66 			'rewrite'               => $rewrite['category'],
    63 		'_builtin' => true,
    67 			'public'                => true,
    64 		'capabilities' => array(
    68 			'show_ui'               => true,
    65 			'manage_terms' => 'manage_categories',
    69 			'show_admin_column'     => true,
    66 			'edit_terms'   => 'edit_categories',
    70 			'_builtin'              => true,
    67 			'delete_terms' => 'delete_categories',
    71 			'capabilities'          => array(
    68 			'assign_terms' => 'assign_categories',
    72 				'manage_terms' => 'manage_categories',
    69 		),
    73 				'edit_terms'   => 'edit_categories',
    70 		'show_in_rest' => true,
    74 				'delete_terms' => 'delete_categories',
    71 		'rest_base' => 'categories',
    75 				'assign_terms' => 'assign_categories',
    72 		'rest_controller_class' => 'WP_REST_Terms_Controller',
    76 			),
    73 	) );
    77 			'show_in_rest'          => true,
    74 
    78 			'rest_base'             => 'categories',
    75 	register_taxonomy( 'post_tag', 'post', array(
    79 			'rest_controller_class' => 'WP_REST_Terms_Controller',
    76 	 	'hierarchical' => false,
    80 		)
    77 		'query_var' => 'tag',
    81 	);
    78 		'rewrite' => $rewrite['post_tag'],
    82 
    79 		'public' => true,
    83 	register_taxonomy(
    80 		'show_ui' => true,
    84 		'post_tag',
    81 		'show_admin_column' => true,
    85 		'post',
    82 		'_builtin' => true,
    86 		array(
    83 		'capabilities' => array(
    87 			'hierarchical'          => false,
    84 			'manage_terms' => 'manage_post_tags',
    88 			'query_var'             => 'tag',
    85 			'edit_terms'   => 'edit_post_tags',
    89 			'rewrite'               => $rewrite['post_tag'],
    86 			'delete_terms' => 'delete_post_tags',
    90 			'public'                => true,
    87 			'assign_terms' => 'assign_post_tags',
    91 			'show_ui'               => true,
    88 		),
    92 			'show_admin_column'     => true,
    89 		'show_in_rest' => true,
    93 			'_builtin'              => true,
    90 		'rest_base' => 'tags',
    94 			'capabilities'          => array(
    91 		'rest_controller_class' => 'WP_REST_Terms_Controller',
    95 				'manage_terms' => 'manage_post_tags',
    92 	) );
    96 				'edit_terms'   => 'edit_post_tags',
    93 
    97 				'delete_terms' => 'delete_post_tags',
    94 	register_taxonomy( 'nav_menu', 'nav_menu_item', array(
    98 				'assign_terms' => 'assign_post_tags',
    95 		'public' => false,
    99 			),
    96 		'hierarchical' => false,
   100 			'show_in_rest'          => true,
    97 		'labels' => array(
   101 			'rest_base'             => 'tags',
    98 			'name' => __( 'Navigation Menus' ),
   102 			'rest_controller_class' => 'WP_REST_Terms_Controller',
    99 			'singular_name' => __( 'Navigation Menu' ),
   103 		)
   100 		),
   104 	);
   101 		'query_var' => false,
   105 
   102 		'rewrite' => false,
   106 	register_taxonomy(
   103 		'show_ui' => false,
   107 		'nav_menu',
   104 		'_builtin' => true,
   108 		'nav_menu_item',
   105 		'show_in_nav_menus' => false,
   109 		array(
   106 	) );
   110 			'public'            => false,
   107 
   111 			'hierarchical'      => false,
   108 	register_taxonomy( 'link_category', 'link', array(
   112 			'labels'            => array(
   109 		'hierarchical' => false,
   113 				'name'          => __( 'Navigation Menus' ),
   110 		'labels' => array(
   114 				'singular_name' => __( 'Navigation Menu' ),
   111 			'name' => __( 'Link Categories' ),
   115 			),
   112 			'singular_name' => __( 'Link Category' ),
   116 			'query_var'         => false,
   113 			'search_items' => __( 'Search Link Categories' ),
   117 			'rewrite'           => false,
   114 			'popular_items' => null,
   118 			'show_ui'           => false,
   115 			'all_items' => __( 'All Link Categories' ),
   119 			'_builtin'          => true,
   116 			'edit_item' => __( 'Edit Link Category' ),
   120 			'show_in_nav_menus' => false,
   117 			'update_item' => __( 'Update Link Category' ),
   121 		)
   118 			'add_new_item' => __( 'Add New Link Category' ),
   122 	);
   119 			'new_item_name' => __( 'New Link Category Name' ),
   123 
   120 			'separate_items_with_commas' => null,
   124 	register_taxonomy(
   121 			'add_or_remove_items' => null,
   125 		'link_category',
   122 			'choose_from_most_used' => null,
   126 		'link',
   123 			'back_to_items' => __( '← Back to Link Categories' ),
   127 		array(
   124 		),
   128 			'hierarchical' => false,
   125 		'capabilities' => array(
   129 			'labels'       => array(
   126 			'manage_terms' => 'manage_links',
   130 				'name'                       => __( 'Link Categories' ),
   127 			'edit_terms'   => 'manage_links',
   131 				'singular_name'              => __( 'Link Category' ),
   128 			'delete_terms' => 'manage_links',
   132 				'search_items'               => __( 'Search Link Categories' ),
   129 			'assign_terms' => 'manage_links',
   133 				'popular_items'              => null,
   130 		),
   134 				'all_items'                  => __( 'All Link Categories' ),
   131 		'query_var' => false,
   135 				'edit_item'                  => __( 'Edit Link Category' ),
   132 		'rewrite' => false,
   136 				'update_item'                => __( 'Update Link Category' ),
   133 		'public' => false,
   137 				'add_new_item'               => __( 'Add New Link Category' ),
   134 		'show_ui' => true,
   138 				'new_item_name'              => __( 'New Link Category Name' ),
   135 		'_builtin' => true,
   139 				'separate_items_with_commas' => null,
   136 	) );
   140 				'add_or_remove_items'        => null,
   137 
   141 				'choose_from_most_used'      => null,
   138 	register_taxonomy( 'post_format', 'post', array(
   142 				'back_to_items'              => __( '← Back to Link Categories' ),
   139 		'public' => true,
   143 			),
   140 		'hierarchical' => false,
   144 			'capabilities' => array(
   141 		'labels' => array(
   145 				'manage_terms' => 'manage_links',
   142 			'name' => _x( 'Format', 'post format' ),
   146 				'edit_terms'   => 'manage_links',
   143 			'singular_name' => _x( 'Format', 'post format' ),
   147 				'delete_terms' => 'manage_links',
   144 		),
   148 				'assign_terms' => 'manage_links',
   145 		'query_var' => true,
   149 			),
   146 		'rewrite' => $rewrite['post_format'],
   150 			'query_var'    => false,
   147 		'show_ui' => false,
   151 			'rewrite'      => false,
   148 		'_builtin' => true,
   152 			'public'       => false,
   149 		'show_in_nav_menus' => current_theme_supports( 'post-formats' ),
   153 			'show_ui'      => true,
   150 	) );
   154 			'_builtin'     => true,
       
   155 		)
       
   156 	);
       
   157 
       
   158 	register_taxonomy(
       
   159 		'post_format',
       
   160 		'post',
       
   161 		array(
       
   162 			'public'            => true,
       
   163 			'hierarchical'      => false,
       
   164 			'labels'            => array(
       
   165 				'name'          => _x( 'Formats', 'post format' ),
       
   166 				'singular_name' => _x( 'Format', 'post format' ),
       
   167 			),
       
   168 			'query_var'         => true,
       
   169 			'rewrite'           => $rewrite['post_format'],
       
   170 			'show_ui'           => false,
       
   171 			'_builtin'          => true,
       
   172 			'show_in_nav_menus' => current_theme_supports( 'post-formats' ),
       
   173 		)
       
   174 	);
   151 }
   175 }
   152 
   176 
   153 /**
   177 /**
   154  * Retrieves a list of registered taxonomy names or objects.
   178  * Retrieves a list of registered taxonomy names or objects.
   155  *
   179  *
   162  * @param string $output   Optional. The type of output to return in the array. Accepts either taxonomy 'names'
   186  * @param string $output   Optional. The type of output to return in the array. Accepts either taxonomy 'names'
   163  *                         or 'objects'. Default 'names'.
   187  *                         or 'objects'. Default 'names'.
   164  * @param string $operator Optional. The logical operation to perform. Accepts 'and' or 'or'. 'or' means only
   188  * @param string $operator Optional. The logical operation to perform. Accepts 'and' or 'or'. 'or' means only
   165  *                         one element from the array needs to match; 'and' means all elements must match.
   189  *                         one element from the array needs to match; 'and' means all elements must match.
   166  *                         Default 'and'.
   190  *                         Default 'and'.
   167  * @return array A list of taxonomy names or objects.
   191  * @return string[]|WP_Taxonomy[] An array of taxonomy names or objects.
   168  */
   192  */
   169 function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
   193 function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
   170 	global $wp_taxonomies;
   194 	global $wp_taxonomies;
   171 
   195 
   172 	$field = ('names' == $output) ? 'name' : false;
   196 	$field = ( 'names' == $output ) ? 'name' : false;
   173 
   197 
   174 	return wp_filter_object_list($wp_taxonomies, $args, $operator, $field);
   198 	return wp_filter_object_list( $wp_taxonomies, $args, $operator, $field );
   175 }
   199 }
   176 
   200 
   177 /**
   201 /**
   178  * Return the names or objects of the taxonomies which are registered for the requested object or object type, such as
   202  * Return the names or objects of the taxonomies which are registered for the requested object or object type, such as
   179  * a post object or post type name.
   203  * a post object or post type name.
   196  * @return array The names of all taxonomy of $object_type.
   220  * @return array The names of all taxonomy of $object_type.
   197  */
   221  */
   198 function get_object_taxonomies( $object, $output = 'names' ) {
   222 function get_object_taxonomies( $object, $output = 'names' ) {
   199 	global $wp_taxonomies;
   223 	global $wp_taxonomies;
   200 
   224 
   201 	if ( is_object($object) ) {
   225 	if ( is_object( $object ) ) {
   202 		if ( $object->post_type == 'attachment' )
   226 		if ( $object->post_type == 'attachment' ) {
   203 			return get_attachment_taxonomies( $object, $output );
   227 			return get_attachment_taxonomies( $object, $output );
       
   228 		}
   204 		$object = $object->post_type;
   229 		$object = $object->post_type;
   205 	}
   230 	}
   206 
   231 
   207 	$object = (array) $object;
   232 	$object = (array) $object;
   208 
   233 
   209 	$taxonomies = array();
   234 	$taxonomies = array();
   210 	foreach ( (array) $wp_taxonomies as $tax_name => $tax_obj ) {
   235 	foreach ( (array) $wp_taxonomies as $tax_name => $tax_obj ) {
   211 		if ( array_intersect($object, (array) $tax_obj->object_type) ) {
   236 		if ( array_intersect( $object, (array) $tax_obj->object_type ) ) {
   212 			if ( 'names' == $output )
   237 			if ( 'names' == $output ) {
   213 				$taxonomies[] = $tax_name;
   238 				$taxonomies[] = $tax_name;
   214 			else
   239 			} else {
   215 				$taxonomies[ $tax_name ] = $tax_obj;
   240 				$taxonomies[ $tax_name ] = $tax_obj;
       
   241 			}
   216 		}
   242 		}
   217 	}
   243 	}
   218 
   244 
   219 	return $taxonomies;
   245 	return $taxonomies;
   220 }
   246 }
   233  * @return WP_Taxonomy|false The Taxonomy Object or false if $taxonomy doesn't exist.
   259  * @return WP_Taxonomy|false The Taxonomy Object or false if $taxonomy doesn't exist.
   234  */
   260  */
   235 function get_taxonomy( $taxonomy ) {
   261 function get_taxonomy( $taxonomy ) {
   236 	global $wp_taxonomies;
   262 	global $wp_taxonomies;
   237 
   263 
   238 	if ( ! taxonomy_exists( $taxonomy ) )
   264 	if ( ! taxonomy_exists( $taxonomy ) ) {
   239 		return false;
   265 		return false;
   240 
   266 	}
   241 	return $wp_taxonomies[$taxonomy];
   267 
   242 }
   268 	return $wp_taxonomies[ $taxonomy ];
   243 
   269 }
   244 /**
   270 
   245  * Checks that the taxonomy name exists.
   271 /**
       
   272  * Determines whether the taxonomy name exists.
   246  *
   273  *
   247  * Formerly is_taxonomy(), introduced in 2.3.0.
   274  * Formerly is_taxonomy(), introduced in 2.3.0.
       
   275  *
       
   276  * For more information on this and similar theme functions, check out
       
   277  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
       
   278  * Conditional Tags} article in the Theme Developer Handbook.
   248  *
   279  *
   249  * @since 3.0.0
   280  * @since 3.0.0
   250  *
   281  *
   251  * @global array $wp_taxonomies The registered taxonomies.
   282  * @global array $wp_taxonomies The registered taxonomies.
   252  *
   283  *
   254  * @return bool Whether the taxonomy exists.
   285  * @return bool Whether the taxonomy exists.
   255  */
   286  */
   256 function taxonomy_exists( $taxonomy ) {
   287 function taxonomy_exists( $taxonomy ) {
   257 	global $wp_taxonomies;
   288 	global $wp_taxonomies;
   258 
   289 
   259 	return isset( $wp_taxonomies[$taxonomy] );
   290 	return isset( $wp_taxonomies[ $taxonomy ] );
   260 }
   291 }
   261 
   292 
   262 /**
   293 /**
   263  * Whether the taxonomy object is hierarchical.
   294  * Determines whether the taxonomy object is hierarchical.
   264  *
   295  *
   265  * Checks to make sure that the taxonomy is an object first. Then Gets the
   296  * Checks to make sure that the taxonomy is an object first. Then Gets the
   266  * object, and finally returns the hierarchical value in the object.
   297  * object, and finally returns the hierarchical value in the object.
   267  *
   298  *
   268  * A false return value might also mean that the taxonomy does not exist.
   299  * A false return value might also mean that the taxonomy does not exist.
   269  *
   300  *
       
   301  * For more information on this and similar theme functions, check out
       
   302  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
       
   303  * Conditional Tags} article in the Theme Developer Handbook.
       
   304  *
   270  * @since 2.3.0
   305  * @since 2.3.0
   271  *
   306  *
   272  * @param string $taxonomy Name of taxonomy object.
   307  * @param string $taxonomy Name of taxonomy object.
   273  * @return bool Whether the taxonomy is hierarchical.
   308  * @return bool Whether the taxonomy is hierarchical.
   274  */
   309  */
   275 function is_taxonomy_hierarchical($taxonomy) {
   310 function is_taxonomy_hierarchical( $taxonomy ) {
   276 	if ( ! taxonomy_exists($taxonomy) )
   311 	if ( ! taxonomy_exists( $taxonomy ) ) {
   277 		return false;
   312 		return false;
   278 
   313 	}
   279 	$taxonomy = get_taxonomy($taxonomy);
   314 
       
   315 	$taxonomy = get_taxonomy( $taxonomy );
   280 	return $taxonomy->hierarchical;
   316 	return $taxonomy->hierarchical;
   281 }
   317 }
   282 
   318 
   283 /**
   319 /**
   284  * Creates or modifies a taxonomy object.
   320  * Creates or modifies a taxonomy object.
   295  * @since 4.4.0 The `show_ui` argument is now enforced on the term editing screen.
   331  * @since 4.4.0 The `show_ui` argument is now enforced on the term editing screen.
   296  * @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.
   297  * @since 4.5.0 Introduced `publicly_queryable` argument.
   333  * @since 4.5.0 Introduced `publicly_queryable` argument.
   298  * @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'
   299  *              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.
   300  *
   337  *
   301  * @global array $wp_taxonomies Registered taxonomies.
   338  * @global array $wp_taxonomies Registered taxonomies.
   302  *
   339  *
   303  * @param string       $taxonomy    Taxonomy key, must not exceed 32 characters.
   340  * @param string       $taxonomy    Taxonomy key, must not exceed 32 characters.
   304  * @param array|string $object_type Object type or array of object types with which the taxonomy should be associated.
   341  * @param array|string $object_type Object type or array of object types with which the taxonomy should be associated.
   337  *                                                screens. Default false.
   374  *                                                screens. Default false.
   338  *     @type bool|callable $meta_box_cb           Provide a callback function for the meta box display. If not set,
   375  *     @type bool|callable $meta_box_cb           Provide a callback function for the meta box display. If not set,
   339  *                                                post_categories_meta_box() is used for hierarchical taxonomies, and
   376  *                                                post_categories_meta_box() is used for hierarchical taxonomies, and
   340  *                                                post_tags_meta_box() is used for non-hierarchical. If false, no meta
   377  *                                                post_tags_meta_box() is used for non-hierarchical. If false, no meta
   341  *                                                box is shown.
   378  *                                                box is shown.
       
   379  *     @type callable      $meta_box_sanitize_cb  Callback function for sanitizing taxonomy data saved from a meta
       
   380  *                                                box. If no callback is defined, an appropriate one is determined
       
   381  *                                                based on the value of `$meta_box_cb`.
   342  *     @type array         $capabilities {
   382  *     @type array         $capabilities {
   343  *         Array of capabilities for this taxonomy.
   383  *         Array of capabilities for this taxonomy.
   344  *
   384  *
   345  *         @type string $manage_terms Default 'manage_categories'.
   385  *         @type string $manage_terms Default 'manage_categories'.
   346  *         @type string $edit_terms   Default 'manage_categories'.
   386  *         @type string $edit_terms   Default 'manage_categories'.
   370  * @return WP_Error|void WP_Error, if errors.
   410  * @return WP_Error|void WP_Error, if errors.
   371  */
   411  */
   372 function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
   412 function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
   373 	global $wp_taxonomies;
   413 	global $wp_taxonomies;
   374 
   414 
   375 	if ( ! is_array( $wp_taxonomies ) )
   415 	if ( ! is_array( $wp_taxonomies ) ) {
   376 		$wp_taxonomies = array();
   416 		$wp_taxonomies = array();
       
   417 	}
   377 
   418 
   378 	$args = wp_parse_args( $args );
   419 	$args = wp_parse_args( $args );
   379 
   420 
   380 	if ( empty( $taxonomy ) || strlen( $taxonomy ) > 32 ) {
   421 	if ( empty( $taxonomy ) || strlen( $taxonomy ) > 32 ) {
   381 		_doing_it_wrong( __FUNCTION__, __( 'Taxonomy names must be between 1 and 32 characters in length.' ), '4.2.0' );
   422 		_doing_it_wrong( __FUNCTION__, __( 'Taxonomy names must be between 1 and 32 characters in length.' ), '4.2.0' );
   386 	$taxonomy_object->add_rewrite_rules();
   427 	$taxonomy_object->add_rewrite_rules();
   387 
   428 
   388 	$wp_taxonomies[ $taxonomy ] = $taxonomy_object;
   429 	$wp_taxonomies[ $taxonomy ] = $taxonomy_object;
   389 
   430 
   390 	$taxonomy_object->add_hooks();
   431 	$taxonomy_object->add_hooks();
   391 
       
   392 
   432 
   393 	/**
   433 	/**
   394 	 * Fires after a taxonomy is registered.
   434 	 * Fires after a taxonomy is registered.
   395 	 *
   435 	 *
   396 	 * @since 3.3.0
   436 	 * @since 3.3.0
   493  * }
   533  * }
   494  */
   534  */
   495 function get_taxonomy_labels( $tax ) {
   535 function get_taxonomy_labels( $tax ) {
   496 	$tax->labels = (array) $tax->labels;
   536 	$tax->labels = (array) $tax->labels;
   497 
   537 
   498 	if ( isset( $tax->helps ) && empty( $tax->labels['separate_items_with_commas'] ) )
   538 	if ( isset( $tax->helps ) && empty( $tax->labels['separate_items_with_commas'] ) ) {
   499 		$tax->labels['separate_items_with_commas'] = $tax->helps;
   539 		$tax->labels['separate_items_with_commas'] = $tax->helps;
   500 
   540 	}
   501 	if ( isset( $tax->no_tagcloud ) && empty( $tax->labels['not_found'] ) )
   541 
       
   542 	if ( isset( $tax->no_tagcloud ) && empty( $tax->labels['not_found'] ) ) {
   502 		$tax->labels['not_found'] = $tax->no_tagcloud;
   543 		$tax->labels['not_found'] = $tax->no_tagcloud;
       
   544 	}
   503 
   545 
   504 	$nohier_vs_hier_defaults = array(
   546 	$nohier_vs_hier_defaults = array(
   505 		'name' => array( _x( 'Tags', 'taxonomy general name' ), _x( 'Categories', 'taxonomy general name' ) ),
   547 		'name'                       => array( _x( 'Tags', 'taxonomy general name' ), _x( 'Categories', 'taxonomy general name' ) ),
   506 		'singular_name' => array( _x( 'Tag', 'taxonomy singular name' ), _x( 'Category', 'taxonomy singular name' ) ),
   548 		'singular_name'              => array( _x( 'Tag', 'taxonomy singular name' ), _x( 'Category', 'taxonomy singular name' ) ),
   507 		'search_items' => array( __( 'Search Tags' ), __( 'Search Categories' ) ),
   549 		'search_items'               => array( __( 'Search Tags' ), __( 'Search Categories' ) ),
   508 		'popular_items' => array( __( 'Popular Tags' ), null ),
   550 		'popular_items'              => array( __( 'Popular Tags' ), null ),
   509 		'all_items' => array( __( 'All Tags' ), __( 'All Categories' ) ),
   551 		'all_items'                  => array( __( 'All Tags' ), __( 'All Categories' ) ),
   510 		'parent_item' => array( null, __( 'Parent Category' ) ),
   552 		'parent_item'                => array( null, __( 'Parent Category' ) ),
   511 		'parent_item_colon' => array( null, __( 'Parent Category:' ) ),
   553 		'parent_item_colon'          => array( null, __( 'Parent Category:' ) ),
   512 		'edit_item' => array( __( 'Edit Tag' ), __( 'Edit Category' ) ),
   554 		'edit_item'                  => array( __( 'Edit Tag' ), __( 'Edit Category' ) ),
   513 		'view_item' => array( __( 'View Tag' ), __( 'View Category' ) ),
   555 		'view_item'                  => array( __( 'View Tag' ), __( 'View Category' ) ),
   514 		'update_item' => array( __( 'Update Tag' ), __( 'Update Category' ) ),
   556 		'update_item'                => array( __( 'Update Tag' ), __( 'Update Category' ) ),
   515 		'add_new_item' => array( __( 'Add New Tag' ), __( 'Add New Category' ) ),
   557 		'add_new_item'               => array( __( 'Add New Tag' ), __( 'Add New Category' ) ),
   516 		'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ),
   558 		'new_item_name'              => array( __( 'New Tag Name' ), __( 'New Category Name' ) ),
   517 		'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ),
   559 		'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ),
   518 		'add_or_remove_items' => array( __( 'Add or remove tags' ), null ),
   560 		'add_or_remove_items'        => array( __( 'Add or remove tags' ), null ),
   519 		'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ),
   561 		'choose_from_most_used'      => array( __( 'Choose from the most used tags' ), null ),
   520 		'not_found' => array( __( 'No tags found.' ), __( 'No categories found.' ) ),
   562 		'not_found'                  => array( __( 'No tags found.' ), __( 'No categories found.' ) ),
   521 		'no_terms' => array( __( 'No tags' ), __( 'No categories' ) ),
   563 		'no_terms'                   => array( __( 'No tags' ), __( 'No categories' ) ),
   522 		'items_list_navigation' => array( __( 'Tags list navigation' ), __( 'Categories list navigation' ) ),
   564 		'items_list_navigation'      => array( __( 'Tags list navigation' ), __( 'Categories list navigation' ) ),
   523 		'items_list' => array( __( 'Tags list' ), __( 'Categories list' ) ),
   565 		'items_list'                 => array( __( 'Tags list' ), __( 'Categories list' ) ),
   524 		/* translators: Tab heading when selecting from the most used terms */
   566 		/* translators: Tab heading when selecting from the most used terms */
   525 		'most_used' => array( _x( 'Most Used', 'tags' ), _x( 'Most Used', 'categories' ) ),
   567 		'most_used'                  => array( _x( 'Most Used', 'tags' ), _x( 'Most Used', 'categories' ) ),
   526 		'back_to_items' => array( __( '← Back to Tags' ), __( '← Back to Categories' ) ),
   568 		'back_to_items'              => array( __( '← Back to Tags' ), __( '← Back to Categories' ) ),
   527 	);
   569 	);
   528 	$nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
   570 	$nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
   529 
   571 
   530 	$labels = _get_custom_object_labels( $tax, $nohier_vs_hier_defaults );
   572 	$labels = _get_custom_object_labels( $tax, $nohier_vs_hier_defaults );
   531 
   573 
   561  *
   603  *
   562  * @param string $taxonomy    Name of taxonomy object.
   604  * @param string $taxonomy    Name of taxonomy object.
   563  * @param string $object_type Name of the object type.
   605  * @param string $object_type Name of the object type.
   564  * @return bool True if successful, false if not.
   606  * @return bool True if successful, false if not.
   565  */
   607  */
   566 function register_taxonomy_for_object_type( $taxonomy, $object_type) {
   608 function register_taxonomy_for_object_type( $taxonomy, $object_type ) {
   567 	global $wp_taxonomies;
   609 	global $wp_taxonomies;
   568 
   610 
   569 	if ( !isset($wp_taxonomies[$taxonomy]) )
   611 	if ( ! isset( $wp_taxonomies[ $taxonomy ] ) ) {
   570 		return false;
   612 		return false;
   571 
   613 	}
   572 	if ( ! get_post_type_object($object_type) )
   614 
       
   615 	if ( ! get_post_type_object( $object_type ) ) {
   573 		return false;
   616 		return false;
   574 
   617 	}
   575 	if ( ! in_array( $object_type, $wp_taxonomies[$taxonomy]->object_type ) )
   618 
   576 		$wp_taxonomies[$taxonomy]->object_type[] = $object_type;
   619 	if ( ! in_array( $object_type, $wp_taxonomies[ $taxonomy ]->object_type ) ) {
       
   620 		$wp_taxonomies[ $taxonomy ]->object_type[] = $object_type;
       
   621 	}
   577 
   622 
   578 	// Filter out empties.
   623 	// Filter out empties.
   579 	$wp_taxonomies[ $taxonomy ]->object_type = array_filter( $wp_taxonomies[ $taxonomy ]->object_type );
   624 	$wp_taxonomies[ $taxonomy ]->object_type = array_filter( $wp_taxonomies[ $taxonomy ]->object_type );
       
   625 
       
   626 	/**
       
   627 	 * Fires after a taxonomy is registered for an object type.
       
   628 	 *
       
   629 	 * @since 5.1.0
       
   630 	 *
       
   631 	 * @param string $taxonomy    Taxonomy name.
       
   632 	 * @param string $object_type Name of the object type.
       
   633 	 */
       
   634 	do_action( 'registered_taxonomy_for_object_type', $taxonomy, $object_type );
   580 
   635 
   581 	return true;
   636 	return true;
   582 }
   637 }
   583 
   638 
   584 /**
   639 /**
   593  * @return bool True if successful, false if not.
   648  * @return bool True if successful, false if not.
   594  */
   649  */
   595 function unregister_taxonomy_for_object_type( $taxonomy, $object_type ) {
   650 function unregister_taxonomy_for_object_type( $taxonomy, $object_type ) {
   596 	global $wp_taxonomies;
   651 	global $wp_taxonomies;
   597 
   652 
   598 	if ( ! isset( $wp_taxonomies[ $taxonomy ] ) )
   653 	if ( ! isset( $wp_taxonomies[ $taxonomy ] ) ) {
   599 		return false;
   654 		return false;
   600 
   655 	}
   601 	if ( ! get_post_type_object( $object_type ) )
   656 
       
   657 	if ( ! get_post_type_object( $object_type ) ) {
   602 		return false;
   658 		return false;
       
   659 	}
   603 
   660 
   604 	$key = array_search( $object_type, $wp_taxonomies[ $taxonomy ]->object_type, true );
   661 	$key = array_search( $object_type, $wp_taxonomies[ $taxonomy ]->object_type, true );
   605 	if ( false === $key )
   662 	if ( false === $key ) {
   606 		return false;
   663 		return false;
       
   664 	}
   607 
   665 
   608 	unset( $wp_taxonomies[ $taxonomy ]->object_type[ $key ] );
   666 	unset( $wp_taxonomies[ $taxonomy ]->object_type[ $key ] );
       
   667 
       
   668 	/**
       
   669 	 * Fires after a taxonomy is unregistered for an object type.
       
   670 	 *
       
   671 	 * @since 5.1.0
       
   672 	 *
       
   673 	 * @param string $taxonomy    Taxonomy name.
       
   674 	 * @param string $object_type Name of the object type.
       
   675 	 */
       
   676 	do_action( 'unregistered_taxonomy_for_object_type', $taxonomy, $object_type );
       
   677 
   609 	return true;
   678 	return true;
   610 }
   679 }
   611 
   680 
   612 //
   681 //
   613 // Term API
   682 // Term API
   634  *
   703  *
   635  * @param int|array    $term_ids   Term id or array of term ids of terms that will be used.
   704  * @param int|array    $term_ids   Term id or array of term ids of terms that will be used.
   636  * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names.
   705  * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names.
   637  * @param array|string $args       Change the order of the object_ids, either ASC or DESC.
   706  * @param array|string $args       Change the order of the object_ids, either ASC or DESC.
   638  * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success.
   707  * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success.
   639  *	the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
   708  *  the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
   640  */
   709  */
   641 function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
   710 function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
   642 	global $wpdb;
   711 	global $wpdb;
   643 
   712 
   644 	if ( ! is_array( $term_ids ) ) {
   713 	if ( ! is_array( $term_ids ) ) {
   652 			return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
   721 			return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
   653 		}
   722 		}
   654 	}
   723 	}
   655 
   724 
   656 	$defaults = array( 'order' => 'ASC' );
   725 	$defaults = array( 'order' => 'ASC' );
   657 	$args = wp_parse_args( $args, $defaults );
   726 	$args     = wp_parse_args( $args, $defaults );
   658 
   727 
   659 	$order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC';
   728 	$order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC';
   660 
   729 
   661 	$term_ids = array_map('intval', $term_ids );
   730 	$term_ids = array_map( 'intval', $term_ids );
   662 
   731 
   663 	$taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'";
   732 	$taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'";
   664 	$term_ids = "'" . implode( "', '", $term_ids ) . "'";
   733 	$term_ids   = "'" . implode( "', '", $term_ids ) . "'";
   665 
   734 
   666 	$sql = "SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order";
   735 	$sql = "SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order";
   667 
   736 
   668 	$last_changed = wp_cache_get_last_changed( 'terms' );
   737 	$last_changed = wp_cache_get_last_changed( 'terms' );
   669 	$cache_key = 'get_objects_in_term:' . md5( $sql ) . ":$last_changed";
   738 	$cache_key    = 'get_objects_in_term:' . md5( $sql ) . ":$last_changed";
   670 	$cache = wp_cache_get( $cache_key, 'terms' );
   739 	$cache        = wp_cache_get( $cache_key, 'terms' );
   671 	if ( false === $cache ) {
   740 	if ( false === $cache ) {
   672 		$object_ids = $wpdb->get_col( $sql );
   741 		$object_ids = $wpdb->get_col( $sql );
   673 		wp_cache_set( $cache_key, $object_ids, 'terms' );
   742 		wp_cache_set( $cache_key, $object_ids, 'terms' );
   674 	} else {
   743 	} else {
   675 		$object_ids = (array) $cache;
   744 		$object_ids = (array) $cache;
   676 	}
   745 	}
   677 
   746 
   678 	if ( ! $object_ids ){
   747 	if ( ! $object_ids ) {
   679 		return array();
   748 		return array();
   680 	}
   749 	}
   681 	return $object_ids;
   750 	return $object_ids;
   682 }
   751 }
   683 
   752 
   769 		return $_term;
   838 		return $_term;
   770 	} elseif ( ! $_term ) {
   839 	} elseif ( ! $_term ) {
   771 		return null;
   840 		return null;
   772 	}
   841 	}
   773 
   842 
       
   843 	// Ensure for filters that this is not empty.
       
   844 	$taxonomy = $_term->taxonomy;
       
   845 
   774 	/**
   846 	/**
   775 	 * Filters a term.
   847 	 * Filters a taxonomy term object.
   776 	 *
   848 	 *
   777 	 * @since 2.3.0
   849 	 * @since 2.3.0
   778 	 * @since 4.4.0 `$_term` can now also be a WP_Term object.
   850 	 * @since 4.4.0 `$_term` is now a `WP_Term` object.
   779 	 *
   851 	 *
   780 	 * @param int|WP_Term $_term    Term object or ID.
   852 	 * @param WP_Term $_term    Term object.
   781 	 * @param string      $taxonomy The taxonomy slug.
   853 	 * @param string  $taxonomy The taxonomy slug.
   782 	 */
   854 	 */
   783 	$_term = apply_filters( 'get_term', $_term, $taxonomy );
   855 	$_term = apply_filters( 'get_term', $_term, $taxonomy );
   784 
   856 
   785 	/**
   857 	/**
   786 	 * Filters a taxonomy.
   858 	 * Filters a taxonomy term object.
   787 	 *
   859 	 *
   788 	 * The dynamic portion of the filter name, `$taxonomy`, refers
   860 	 * The dynamic portion of the filter name, `$taxonomy`, refers
   789 	 * to the taxonomy slug.
   861 	 * to the slug of the term's taxonomy.
   790 	 *
   862 	 *
   791 	 * @since 2.3.0
   863 	 * @since 2.3.0
   792 	 * @since 4.4.0 `$_term` can now also be a WP_Term object.
   864 	 * @since 4.4.0 `$_term` is now a `WP_Term` object.
   793 	 *
   865 	 *
   794 	 * @param int|WP_Term $_term    Term object or ID.
   866 	 * @param WP_Term $_term    Term object.
   795 	 * @param string      $taxonomy The taxonomy slug.
   867 	 * @param string  $taxonomy The taxonomy slug.
   796 	 */
   868 	 */
   797 	$_term = apply_filters( "get_{$taxonomy}", $_term, $taxonomy );
   869 	$_term = apply_filters( "get_{$taxonomy}", $_term, $taxonomy );
   798 
   870 
   799 	// Bail if a filter callback has changed the type of the `$_term` object.
   871 	// Bail if a filter callback has changed the type of the `$_term` object.
   800 	if ( ! ( $_term instanceof WP_Term ) ) {
   872 	if ( ! ( $_term instanceof WP_Term ) ) {
   881 		'orderby'                => 'none',
   953 		'orderby'                => 'none',
   882 		'suppress_filter'        => true,
   954 		'suppress_filter'        => true,
   883 	);
   955 	);
   884 
   956 
   885 	switch ( $field ) {
   957 	switch ( $field ) {
   886 		case 'slug' :
   958 		case 'slug':
   887 			$args['slug'] = $value;
   959 			$args['slug'] = $value;
   888 			break;
   960 			break;
   889 		case 'name' :
   961 		case 'name':
   890 			$args['name'] = $value;
   962 			$args['name'] = $value;
   891 			break;
   963 			break;
   892 		case 'term_taxonomy_id' :
   964 		case 'term_taxonomy_id':
   893 			$args['term_taxonomy_id'] = $value;
   965 			$args['term_taxonomy_id'] = $value;
   894 			unset( $args[ 'taxonomy' ] );
   966 			unset( $args['taxonomy'] );
   895 			break;
   967 			break;
   896 		default :
   968 		default:
   897 			return false;
   969 			return false;
   898 	}
   970 	}
   899 
   971 
   900 	$terms = get_terms( $args );
   972 	$terms = get_terms( $args );
   901 	if ( is_wp_error( $terms ) || empty( $terms ) ) {
   973 	if ( is_wp_error( $terms ) || empty( $terms ) ) {
   931 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  1003 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
   932 	}
  1004 	}
   933 
  1005 
   934 	$term_id = intval( $term_id );
  1006 	$term_id = intval( $term_id );
   935 
  1007 
   936 	$terms = _get_term_hierarchy($taxonomy);
  1008 	$terms = _get_term_hierarchy( $taxonomy );
   937 
  1009 
   938 	if ( ! isset($terms[$term_id]) )
  1010 	if ( ! isset( $terms[ $term_id ] ) ) {
   939 		return array();
  1011 		return array();
   940 
  1012 	}
   941 	$children = $terms[$term_id];
  1013 
   942 
  1014 	$children = $terms[ $term_id ];
   943 	foreach ( (array) $terms[$term_id] as $child ) {
  1015 
       
  1016 	foreach ( (array) $terms[ $term_id ] as $child ) {
   944 		if ( $term_id == $child ) {
  1017 		if ( $term_id == $child ) {
   945 			continue;
  1018 			continue;
   946 		}
  1019 		}
   947 
  1020 
   948 		if ( isset($terms[$child]) )
  1021 		if ( isset( $terms[ $child ] ) ) {
   949 			$children = array_merge($children, get_term_children($child, $taxonomy));
  1022 			$children = array_merge( $children, get_term_children( $child, $taxonomy ) );
       
  1023 		}
   950 	}
  1024 	}
   951 
  1025 
   952 	return $children;
  1026 	return $children;
   953 }
  1027 }
   954 
  1028 
   968  * @param string      $context  Optional, default is display. Look at sanitize_term_field() for available options.
  1042  * @param string      $context  Optional, default is display. Look at sanitize_term_field() for available options.
   969  * @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.
  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.
   970  */
  1044  */
   971 function get_term_field( $field, $term, $taxonomy = '', $context = 'display' ) {
  1045 function get_term_field( $field, $term, $taxonomy = '', $context = 'display' ) {
   972 	$term = get_term( $term, $taxonomy );
  1046 	$term = get_term( $term, $taxonomy );
   973 	if ( is_wp_error($term) )
  1047 	if ( is_wp_error( $term ) ) {
   974 		return $term;
  1048 		return $term;
   975 
  1049 	}
   976 	if ( !is_object($term) )
  1050 
       
  1051 	if ( ! is_object( $term ) ) {
   977 		return '';
  1052 		return '';
   978 
  1053 	}
   979 	if ( !isset($term->$field) )
  1054 
       
  1055 	if ( ! isset( $term->$field ) ) {
   980 		return '';
  1056 		return '';
       
  1057 	}
   981 
  1058 
   982 	return sanitize_term_field( $field, $term->$field, $term->term_id, $term->taxonomy, $context );
  1059 	return sanitize_term_field( $field, $term->$field, $term->term_id, $term->taxonomy, $context );
   983 }
  1060 }
   984 
  1061 
   985 /**
  1062 /**
   995  * @return string|int|null|WP_Error Will return empty string if $term is not an object.
  1072  * @return string|int|null|WP_Error Will return empty string if $term is not an object.
   996  */
  1073  */
   997 function get_term_to_edit( $id, $taxonomy ) {
  1074 function get_term_to_edit( $id, $taxonomy ) {
   998 	$term = get_term( $id, $taxonomy );
  1075 	$term = get_term( $id, $taxonomy );
   999 
  1076 
  1000 	if ( is_wp_error($term) )
  1077 	if ( is_wp_error( $term ) ) {
  1001 		return $term;
  1078 		return $term;
  1002 
  1079 	}
  1003 	if ( !is_object($term) )
  1080 
       
  1081 	if ( ! is_object( $term ) ) {
  1004 		return '';
  1082 		return '';
  1005 
  1083 	}
  1006 	return sanitize_term($term, $taxonomy, 'edit');
  1084 
       
  1085 	return sanitize_term( $term, $taxonomy, 'edit' );
  1007 }
  1086 }
  1008 
  1087 
  1009 /**
  1088 /**
  1010  * Retrieve the terms in a given taxonomy or list of taxonomies.
  1089  * Retrieve the terms in a given taxonomy or list of taxonomies.
  1011  *
  1090  *
  1067 	 *
  1146 	 *
  1068 	 * We detect legacy argument format by checking if
  1147 	 * We detect legacy argument format by checking if
  1069 	 * (a) a second non-empty parameter is passed, or
  1148 	 * (a) a second non-empty parameter is passed, or
  1070 	 * (b) the first parameter shares no keys with the default array (ie, it's a list of taxonomies)
  1149 	 * (b) the first parameter shares no keys with the default array (ie, it's a list of taxonomies)
  1071 	 */
  1150 	 */
  1072 	$_args = wp_parse_args( $args );
  1151 	$_args          = wp_parse_args( $args );
  1073 	$key_intersect  = array_intersect_key( $term_query->query_var_defaults, (array) $_args );
  1152 	$key_intersect  = array_intersect_key( $term_query->query_var_defaults, (array) $_args );
  1074 	$do_legacy_args = $deprecated || empty( $key_intersect );
  1153 	$do_legacy_args = $deprecated || empty( $key_intersect );
  1075 
  1154 
  1076 	if ( $do_legacy_args ) {
  1155 	if ( $do_legacy_args ) {
  1077 		$taxonomies = (array) $args;
  1156 		$taxonomies       = (array) $args;
  1078 		$args = wp_parse_args( $deprecated, $defaults );
  1157 		$args             = wp_parse_args( $deprecated, $defaults );
  1079 		$args['taxonomy'] = $taxonomies;
  1158 		$args['taxonomy'] = $taxonomies;
  1080 	} else {
  1159 	} else {
  1081 		$args = wp_parse_args( $args, $defaults );
  1160 		$args = wp_parse_args( $args, $defaults );
  1082 		if ( isset( $args['taxonomy'] ) && null !== $args['taxonomy'] ) {
  1161 		if ( isset( $args['taxonomy'] ) && null !== $args['taxonomy'] ) {
  1083 			$args['taxonomy'] = (array) $args['taxonomy'];
  1162 			$args['taxonomy'] = (array) $args['taxonomy'];
  1133  *                           Default false.
  1212  *                           Default false.
  1134  * @return int|WP_Error|bool Meta ID on success. WP_Error when term_id is ambiguous between taxonomies.
  1213  * @return int|WP_Error|bool Meta ID on success. WP_Error when term_id is ambiguous between taxonomies.
  1135  *                           False on failure.
  1214  *                           False on failure.
  1136  */
  1215  */
  1137 function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
  1216 function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
  1138 	// Bail if term meta table is not installed.
       
  1139 	if ( get_option( 'db_version' ) < 34370 ) {
       
  1140 		return false;
       
  1141 	}
       
  1142 
       
  1143 	if ( wp_term_is_shared( $term_id ) ) {
  1217 	if ( wp_term_is_shared( $term_id ) ) {
  1144 		return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.'), $term_id );
  1218 		return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.' ), $term_id );
  1145 	}
  1219 	}
  1146 
  1220 
  1147 	$added = add_metadata( 'term', $term_id, $meta_key, $meta_value, $unique );
  1221 	return add_metadata( 'term', $term_id, $meta_key, $meta_value, $unique );
  1148 
       
  1149 	// Bust term query cache.
       
  1150 	if ( $added ) {
       
  1151 		wp_cache_set( 'last_changed', microtime(), 'terms' );
       
  1152 	}
       
  1153 
       
  1154 	return $added;
       
  1155 }
  1222 }
  1156 
  1223 
  1157 /**
  1224 /**
  1158  * Removes metadata matching criteria from a term.
  1225  * Removes metadata matching criteria from a term.
  1159  *
  1226  *
  1163  * @param string $meta_key   Metadata name.
  1230  * @param string $meta_key   Metadata name.
  1164  * @param mixed  $meta_value Optional. Metadata value. If provided, rows will only be removed that match the value.
  1231  * @param mixed  $meta_value Optional. Metadata value. If provided, rows will only be removed that match the value.
  1165  * @return bool True on success, false on failure.
  1232  * @return bool True on success, false on failure.
  1166  */
  1233  */
  1167 function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
  1234 function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
  1168 	// Bail if term meta table is not installed.
  1235 	return delete_metadata( 'term', $term_id, $meta_key, $meta_value );
  1169 	if ( get_option( 'db_version' ) < 34370 ) {
       
  1170 		return false;
       
  1171 	}
       
  1172 
       
  1173 	$deleted = delete_metadata( 'term', $term_id, $meta_key, $meta_value );
       
  1174 
       
  1175 	// Bust term query cache.
       
  1176 	if ( $deleted ) {
       
  1177 		wp_cache_set( 'last_changed', microtime(), 'terms' );
       
  1178 	}
       
  1179 
       
  1180 	return $deleted;
       
  1181 }
  1236 }
  1182 
  1237 
  1183 /**
  1238 /**
  1184  * Retrieves metadata for a term.
  1239  * Retrieves metadata for a term.
  1185  *
  1240  *
  1190  * @param bool   $single  Whether to return a single value. If false, an array of all values matching the
  1245  * @param bool   $single  Whether to return a single value. If false, an array of all values matching the
  1191  *                        `$term_id`/`$key` pair will be returned. Default: false.
  1246  *                        `$term_id`/`$key` pair will be returned. Default: false.
  1192  * @return mixed If `$single` is false, an array of metadata values. If `$single` is true, a single metadata value.
  1247  * @return mixed If `$single` is false, an array of metadata values. If `$single` is true, a single metadata value.
  1193  */
  1248  */
  1194 function get_term_meta( $term_id, $key = '', $single = false ) {
  1249 function get_term_meta( $term_id, $key = '', $single = false ) {
  1195 	// Bail if term meta table is not installed.
       
  1196 	if ( get_option( 'db_version' ) < 34370 ) {
       
  1197 		return false;
       
  1198 	}
       
  1199 
       
  1200 	return get_metadata( 'term', $term_id, $key, $single );
  1250 	return get_metadata( 'term', $term_id, $key, $single );
  1201 }
  1251 }
  1202 
  1252 
  1203 /**
  1253 /**
  1204  * Updates term metadata.
  1254  * Updates term metadata.
  1215  * @param mixed  $prev_value Optional. Previous value to check before removing.
  1265  * @param mixed  $prev_value Optional. Previous value to check before removing.
  1216  * @return int|WP_Error|bool Meta ID if the key didn't previously exist. True on successful update.
  1266  * @return int|WP_Error|bool Meta ID if the key didn't previously exist. True on successful update.
  1217  *                           WP_Error when term_id is ambiguous between taxonomies. False on failure.
  1267  *                           WP_Error when term_id is ambiguous between taxonomies. False on failure.
  1218  */
  1268  */
  1219 function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
  1269 function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
  1220 	// Bail if term meta table is not installed.
       
  1221 	if ( get_option( 'db_version' ) < 34370 ) {
       
  1222 		return false;
       
  1223 	}
       
  1224 
       
  1225 	if ( wp_term_is_shared( $term_id ) ) {
  1270 	if ( wp_term_is_shared( $term_id ) ) {
  1226 		return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.'), $term_id );
  1271 		return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.' ), $term_id );
  1227 	}
  1272 	}
  1228 
  1273 
  1229 	$updated = update_metadata( 'term', $term_id, $meta_key, $meta_value, $prev_value );
  1274 	return update_metadata( 'term', $term_id, $meta_key, $meta_value, $prev_value );
  1230 
       
  1231 	// Bust term query cache.
       
  1232 	if ( $updated ) {
       
  1233 		wp_cache_set( 'last_changed', microtime(), 'terms' );
       
  1234 	}
       
  1235 
       
  1236 	return $updated;
       
  1237 }
  1275 }
  1238 
  1276 
  1239 /**
  1277 /**
  1240  * Updates metadata cache for list of term IDs.
  1278  * Updates metadata cache for list of term IDs.
  1241  *
  1279  *
  1246  *
  1284  *
  1247  * @param array $term_ids List of term IDs.
  1285  * @param array $term_ids List of term IDs.
  1248  * @return array|false Returns false if there is nothing to update. Returns an array of metadata on success.
  1286  * @return array|false Returns false if there is nothing to update. Returns an array of metadata on success.
  1249  */
  1287  */
  1250 function update_termmeta_cache( $term_ids ) {
  1288 function update_termmeta_cache( $term_ids ) {
  1251 	// Bail if term meta table is not installed.
       
  1252 	if ( get_option( 'db_version' ) < 34370 ) {
       
  1253 		return;
       
  1254 	}
       
  1255 
       
  1256 	return update_meta_cache( 'term', $term_ids );
  1289 	return update_meta_cache( 'term', $term_ids );
  1257 }
  1290 }
  1258 
  1291 
  1259 /**
  1292 /**
  1260  * Get all meta data, including meta IDs, for the given term ID.
  1293  * Get all meta data, including meta IDs, for the given term ID.
  1265  *
  1298  *
  1266  * @param int $term_id Term ID.
  1299  * @param int $term_id Term ID.
  1267  * @return array|false Array with meta data, or false when the meta table is not installed.
  1300  * @return array|false Array with meta data, or false when the meta table is not installed.
  1268  */
  1301  */
  1269 function has_term_meta( $term_id ) {
  1302 function has_term_meta( $term_id ) {
  1270 	// Bail if term meta table is not installed.
  1303 	$check = wp_check_term_meta_support_prefilter( null );
  1271 	if ( get_option( 'db_version' ) < 34370 ) {
  1304 	if ( null !== $check ) {
  1272 		return false;
  1305 		return $check;
  1273 	}
  1306 	}
  1274 
  1307 
  1275 	global $wpdb;
  1308 	global $wpdb;
  1276 
  1309 
  1277 	return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, term_id FROM $wpdb->termmeta WHERE term_id = %d ORDER BY meta_key,meta_id", $term_id ), ARRAY_A );
  1310 	return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, term_id FROM $wpdb->termmeta WHERE term_id = %d ORDER BY meta_key,meta_id", $term_id ), ARRAY_A );
  1309 function unregister_term_meta( $taxonomy, $meta_key ) {
  1342 function unregister_term_meta( $taxonomy, $meta_key ) {
  1310 	return unregister_meta_key( 'term', $meta_key, $taxonomy );
  1343 	return unregister_meta_key( 'term', $meta_key, $taxonomy );
  1311 }
  1344 }
  1312 
  1345 
  1313 /**
  1346 /**
  1314  * Check if Term exists.
  1347  * Determines whether a term exists.
  1315  *
  1348  *
  1316  * Formerly is_term(), introduced in 2.3.0.
  1349  * Formerly is_term(), introduced in 2.3.0.
       
  1350  *
       
  1351  * For more information on this and similar theme functions, check out
       
  1352  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
       
  1353  * Conditional Tags} article in the Theme Developer Handbook.
  1317  *
  1354  *
  1318  * @since 3.0.0
  1355  * @since 3.0.0
  1319  *
  1356  *
  1320  * @global wpdb $wpdb WordPress database abstraction object.
  1357  * @global wpdb $wpdb WordPress database abstraction object.
  1321  *
  1358  *
  1322  * @param int|string $term     The term to check. Accepts term ID, slug, or name.
  1359  * @param int|string $term     The term to check. Accepts term ID, slug, or name.
  1323  * @param string     $taxonomy The taxonomy name to use
  1360  * @param string     $taxonomy The taxonomy name to use
  1324  * @param int        $parent   Optional. ID of parent term under which to confine the exists search.
  1361  * @param int        $parent   Optional. ID of parent term under which to confine the exists search.
  1325  * @return mixed Returns null if the term does not exist. Returns the term ID
  1362  * @return mixed Returns null if the term does not exist. Returns the term ID
  1326  *               if no taxonomy is specified and the term ID exists. Returns
  1363  *               if no taxonomy is specified and the term ID exists. Returns
  1327  *               an array of the term ID and the term taxonomy ID the taxonomy
  1364  *               an array of the term ID and the term taxonomy ID if the taxonomy
  1328  *               is specified and the pairing exists.
  1365  *               is specified and the pairing exists.
  1329  */
  1366  */
  1330 function term_exists( $term, $taxonomy = '', $parent = null ) {
  1367 function term_exists( $term, $taxonomy = '', $parent = null ) {
  1331 	global $wpdb;
  1368 	global $wpdb;
  1332 
  1369 
  1333 	$select = "SELECT term_id FROM $wpdb->terms as t WHERE ";
  1370 	$select     = "SELECT term_id FROM $wpdb->terms as t WHERE ";
  1334 	$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 ";
  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 ";
  1335 
  1372 
  1336 	if ( is_int($term) ) {
  1373 	if ( is_int( $term ) ) {
  1337 		if ( 0 == $term )
  1374 		if ( 0 == $term ) {
  1338 			return 0;
  1375 			return 0;
       
  1376 		}
  1339 		$where = 't.term_id = %d';
  1377 		$where = 't.term_id = %d';
  1340 		if ( !empty($taxonomy) )
  1378 		if ( ! empty( $taxonomy ) ) {
  1341 			return $wpdb->get_row( $wpdb->prepare( $tax_select . $where . " AND tt.taxonomy = %s", $term, $taxonomy ), ARRAY_A );
  1379 			return $wpdb->get_row( $wpdb->prepare( $tax_select . $where . ' AND tt.taxonomy = %s', $term, $taxonomy ), ARRAY_A );
  1342 		else
  1380 		} else {
  1343 			return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
  1381 			return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
       
  1382 		}
  1344 	}
  1383 	}
  1345 
  1384 
  1346 	$term = trim( wp_unslash( $term ) );
  1385 	$term = trim( wp_unslash( $term ) );
  1347 	$slug = sanitize_title( $term );
  1386 	$slug = sanitize_title( $term );
  1348 
  1387 
  1349 	$where = 't.slug = %s';
  1388 	$where             = 't.slug = %s';
  1350 	$else_where = 't.name = %s';
  1389 	$else_where        = 't.name = %s';
  1351 	$where_fields = array($slug);
  1390 	$where_fields      = array( $slug );
  1352 	$else_where_fields = array($term);
  1391 	$else_where_fields = array( $term );
  1353 	$orderby = 'ORDER BY t.term_id ASC';
  1392 	$orderby           = 'ORDER BY t.term_id ASC';
  1354 	$limit = 'LIMIT 1';
  1393 	$limit             = 'LIMIT 1';
  1355 	if ( !empty($taxonomy) ) {
  1394 	if ( ! empty( $taxonomy ) ) {
  1356 		if ( is_numeric( $parent ) ) {
  1395 		if ( is_numeric( $parent ) ) {
  1357 			$parent = (int) $parent;
  1396 			$parent              = (int) $parent;
  1358 			$where_fields[] = $parent;
  1397 			$where_fields[]      = $parent;
  1359 			$else_where_fields[] = $parent;
  1398 			$else_where_fields[] = $parent;
  1360 			$where .= ' AND tt.parent = %d';
  1399 			$where              .= ' AND tt.parent = %d';
  1361 			$else_where .= ' AND tt.parent = %d';
  1400 			$else_where         .= ' AND tt.parent = %d';
  1362 		}
  1401 		}
  1363 
  1402 
  1364 		$where_fields[] = $taxonomy;
  1403 		$where_fields[]      = $taxonomy;
  1365 		$else_where_fields[] = $taxonomy;
  1404 		$else_where_fields[] = $taxonomy;
  1366 
  1405 
  1367 		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) )
  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 ) ) {
  1368 			return $result;
  1407 			return $result;
  1369 
  1408 		}
  1370 		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);
  1409 
  1371 	}
  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 );
  1372 
  1411 	}
  1373 	if ( $result = $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $where $orderby $limit", $where_fields) ) )
  1412 
       
  1413 	if ( $result = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms as t WHERE $where $orderby $limit", $where_fields ) ) ) {
  1374 		return $result;
  1414 		return $result;
  1375 
  1415 	}
  1376 	return $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $else_where $orderby $limit", $else_where_fields) );
  1416 
       
  1417 	return $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms as t WHERE $else_where $orderby $limit", $else_where_fields ) );
  1377 }
  1418 }
  1378 
  1419 
  1379 /**
  1420 /**
  1380  * Check if a term is an ancestor of another term.
  1421  * Check if a term is an ancestor of another term.
  1381  *
  1422  *
  1387  * @param int|object $term2    The child term.
  1428  * @param int|object $term2    The child term.
  1388  * @param string     $taxonomy Taxonomy name that $term1 and `$term2` belong to.
  1429  * @param string     $taxonomy Taxonomy name that $term1 and `$term2` belong to.
  1389  * @return bool Whether `$term2` is a child of `$term1`.
  1430  * @return bool Whether `$term2` is a child of `$term1`.
  1390  */
  1431  */
  1391 function term_is_ancestor_of( $term1, $term2, $taxonomy ) {
  1432 function term_is_ancestor_of( $term1, $term2, $taxonomy ) {
  1392 	if ( ! isset( $term1->term_id ) )
  1433 	if ( ! isset( $term1->term_id ) ) {
  1393 		$term1 = get_term( $term1, $taxonomy );
  1434 		$term1 = get_term( $term1, $taxonomy );
  1394 	if ( ! isset( $term2->parent ) )
  1435 	}
       
  1436 	if ( ! isset( $term2->parent ) ) {
  1395 		$term2 = get_term( $term2, $taxonomy );
  1437 		$term2 = get_term( $term2, $taxonomy );
  1396 
  1438 	}
  1397 	if ( empty( $term1->term_id ) || empty( $term2->parent ) )
  1439 
       
  1440 	if ( empty( $term1->term_id ) || empty( $term2->parent ) ) {
  1398 		return false;
  1441 		return false;
  1399 	if ( $term2->parent == $term1->term_id )
  1442 	}
       
  1443 	if ( $term2->parent == $term1->term_id ) {
  1400 		return true;
  1444 		return true;
       
  1445 	}
  1401 
  1446 
  1402 	return term_is_ancestor_of( $term1, get_term( $term2->parent, $taxonomy ), $taxonomy );
  1447 	return term_is_ancestor_of( $term1, get_term( $term2->parent, $taxonomy ), $taxonomy );
  1403 }
  1448 }
  1404 
  1449 
  1405 /**
  1450 /**
  1417  * @param string       $taxonomy The taxonomy name to use.
  1462  * @param string       $taxonomy The taxonomy name to use.
  1418  * @param string       $context  Optional. Context in which to sanitize the term. Accepts 'edit', 'db',
  1463  * @param string       $context  Optional. Context in which to sanitize the term. Accepts 'edit', 'db',
  1419  *                               'display', 'attribute', or 'js'. Default 'display'.
  1464  *                               'display', 'attribute', or 'js'. Default 'display'.
  1420  * @return array|object Term with all fields sanitized.
  1465  * @return array|object Term with all fields sanitized.
  1421  */
  1466  */
  1422 function sanitize_term($term, $taxonomy, $context = 'display') {
  1467 function sanitize_term( $term, $taxonomy, $context = 'display' ) {
  1423 	$fields = array( 'term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group', 'term_taxonomy_id', 'object_id' );
  1468 	$fields = array( 'term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group', 'term_taxonomy_id', 'object_id' );
  1424 
  1469 
  1425 	$do_object = is_object( $term );
  1470 	$do_object = is_object( $term );
  1426 
  1471 
  1427 	$term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0);
  1472 	$term_id = $do_object ? $term->term_id : ( isset( $term['term_id'] ) ? $term['term_id'] : 0 );
  1428 
  1473 
  1429 	foreach ( (array) $fields as $field ) {
  1474 	foreach ( (array) $fields as $field ) {
  1430 		if ( $do_object ) {
  1475 		if ( $do_object ) {
  1431 			if ( isset($term->$field) )
  1476 			if ( isset( $term->$field ) ) {
  1432 				$term->$field = sanitize_term_field($field, $term->$field, $term_id, $taxonomy, $context);
  1477 				$term->$field = sanitize_term_field( $field, $term->$field, $term_id, $taxonomy, $context );
       
  1478 			}
  1433 		} else {
  1479 		} else {
  1434 			if ( isset($term[$field]) )
  1480 			if ( isset( $term[ $field ] ) ) {
  1435 				$term[$field] = sanitize_term_field($field, $term[$field], $term_id, $taxonomy, $context);
  1481 				$term[ $field ] = sanitize_term_field( $field, $term[ $field ], $term_id, $taxonomy, $context );
  1436 		}
  1482 			}
  1437 	}
  1483 		}
  1438 
  1484 	}
  1439 	if ( $do_object )
  1485 
       
  1486 	if ( $do_object ) {
  1440 		$term->filter = $context;
  1487 		$term->filter = $context;
  1441 	else
  1488 	} else {
  1442 		$term['filter'] = $context;
  1489 		$term['filter'] = $context;
       
  1490 	}
  1443 
  1491 
  1444 	return $term;
  1492 	return $term;
  1445 }
  1493 }
  1446 
  1494 
  1447 /**
  1495 /**
  1465  * @param string $taxonomy Taxonomy Name.
  1513  * @param string $taxonomy Taxonomy Name.
  1466  * @param string $context  Context in which to sanitize the term field. Accepts 'edit', 'db', 'display',
  1514  * @param string $context  Context in which to sanitize the term field. Accepts 'edit', 'db', 'display',
  1467  *                         'attribute', or 'js'.
  1515  *                         'attribute', or 'js'.
  1468  * @return mixed Sanitized field.
  1516  * @return mixed Sanitized field.
  1469  */
  1517  */
  1470 function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) {
  1518 function sanitize_term_field( $field, $value, $term_id, $taxonomy, $context ) {
  1471 	$int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' );
  1519 	$int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' );
  1472 	if ( in_array( $field, $int_fields ) ) {
  1520 	if ( in_array( $field, $int_fields ) ) {
  1473 		$value = (int) $value;
  1521 		$value = (int) $value;
  1474 		if ( $value < 0 )
  1522 		if ( $value < 0 ) {
  1475 			$value = 0;
  1523 			$value = 0;
  1476 	}
  1524 		}
  1477 
  1525 	}
  1478 	if ( 'raw' == $context )
  1526 
       
  1527 	if ( 'raw' == $context ) {
  1479 		return $value;
  1528 		return $value;
       
  1529 	}
  1480 
  1530 
  1481 	if ( 'edit' == $context ) {
  1531 	if ( 'edit' == $context ) {
  1482 
  1532 
  1483 		/**
  1533 		/**
  1484 		 * Filters a term field to edit before it is sanitized.
  1534 		 * Filters a term field to edit before it is sanitized.
  1504 		 * @param mixed $value   Value of the taxonomy field to edit.
  1554 		 * @param mixed $value   Value of the taxonomy field to edit.
  1505 		 * @param int   $term_id Term ID.
  1555 		 * @param int   $term_id Term ID.
  1506 		 */
  1556 		 */
  1507 		$value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id );
  1557 		$value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id );
  1508 
  1558 
  1509 		if ( 'description' == $field )
  1559 		if ( 'description' == $field ) {
  1510 			$value = esc_html($value); // textarea_escaped
  1560 			$value = esc_html( $value ); // textarea_escaped
  1511 		else
  1561 		} else {
  1512 			$value = esc_attr($value);
  1562 			$value = esc_attr( $value );
       
  1563 		}
  1513 	} elseif ( 'db' == $context ) {
  1564 	} elseif ( 'db' == $context ) {
  1514 
  1565 
  1515 		/**
  1566 		/**
  1516 		 * Filters a term field value before it is sanitized.
  1567 		 * Filters a term field value before it is sanitized.
  1517 		 *
  1568 		 *
  1547 			 *
  1598 			 *
  1548 			 * @param string $value The category nicename.
  1599 			 * @param string $value The category nicename.
  1549 			 */
  1600 			 */
  1550 			$value = apply_filters( 'pre_category_nicename', $value );
  1601 			$value = apply_filters( 'pre_category_nicename', $value );
  1551 		}
  1602 		}
  1552 
       
  1553 	} elseif ( 'rss' == $context ) {
  1603 	} elseif ( 'rss' == $context ) {
  1554 
  1604 
  1555 		/**
  1605 		/**
  1556 		 * Filters the term field for use in RSS.
  1606 		 * Filters the term field for use in RSS.
  1557 		 *
  1607 		 *
  1606 		 */
  1656 		 */
  1607 		$value = apply_filters( "{$taxonomy}_{$field}", $value, $term_id, $context );
  1657 		$value = apply_filters( "{$taxonomy}_{$field}", $value, $term_id, $context );
  1608 	}
  1658 	}
  1609 
  1659 
  1610 	if ( 'attribute' == $context ) {
  1660 	if ( 'attribute' == $context ) {
  1611 		$value = esc_attr($value);
  1661 		$value = esc_attr( $value );
  1612 	} elseif ( 'js' == $context ) {
  1662 	} elseif ( 'js' == $context ) {
  1613 		$value = esc_js($value);
  1663 		$value = esc_js( $value );
  1614 	}
  1664 	}
  1615 	return $value;
  1665 	return $value;
  1616 }
  1666 }
  1617 
  1667 
  1618 /**
  1668 /**
  1626  * @param array|string $args     Optional. Array of arguments that get passed to get_terms().
  1676  * @param array|string $args     Optional. Array of arguments that get passed to get_terms().
  1627  *                               Default empty array.
  1677  *                               Default empty array.
  1628  * @return array|int|WP_Error Number of terms in that taxonomy or WP_Error if the taxonomy does not exist.
  1678  * @return array|int|WP_Error Number of terms in that taxonomy or WP_Error if the taxonomy does not exist.
  1629  */
  1679  */
  1630 function wp_count_terms( $taxonomy, $args = array() ) {
  1680 function wp_count_terms( $taxonomy, $args = array() ) {
  1631 	$defaults = array('hide_empty' => false);
  1681 	$defaults = array( 'hide_empty' => false );
  1632 	$args = wp_parse_args($args, $defaults);
  1682 	$args     = wp_parse_args( $args, $defaults );
  1633 
  1683 
  1634 	// backward compatibility
  1684 	// backward compatibility
  1635 	if ( isset($args['ignore_empty']) ) {
  1685 	if ( isset( $args['ignore_empty'] ) ) {
  1636 		$args['hide_empty'] = $args['ignore_empty'];
  1686 		$args['hide_empty'] = $args['ignore_empty'];
  1637 		unset($args['ignore_empty']);
  1687 		unset( $args['ignore_empty'] );
  1638 	}
  1688 	}
  1639 
  1689 
  1640 	$args['fields'] = 'count';
  1690 	$args['fields'] = 'count';
  1641 
  1691 
  1642 	return get_terms($taxonomy, $args);
  1692 	return get_terms( $taxonomy, $args );
  1643 }
  1693 }
  1644 
  1694 
  1645 /**
  1695 /**
  1646  * Will unlink the object from the taxonomy or taxonomies.
  1696  * Will unlink the object from the taxonomy or taxonomies.
  1647  *
  1697  *
  1655  * @param string|array $taxonomies List of Taxonomy Names or single Taxonomy name.
  1705  * @param string|array $taxonomies List of Taxonomy Names or single Taxonomy name.
  1656  */
  1706  */
  1657 function wp_delete_object_term_relationships( $object_id, $taxonomies ) {
  1707 function wp_delete_object_term_relationships( $object_id, $taxonomies ) {
  1658 	$object_id = (int) $object_id;
  1708 	$object_id = (int) $object_id;
  1659 
  1709 
  1660 	if ( !is_array($taxonomies) )
  1710 	if ( ! is_array( $taxonomies ) ) {
  1661 		$taxonomies = array($taxonomies);
  1711 		$taxonomies = array( $taxonomies );
       
  1712 	}
  1662 
  1713 
  1663 	foreach ( (array) $taxonomies as $taxonomy ) {
  1714 	foreach ( (array) $taxonomies as $taxonomy ) {
  1664 		$term_ids = wp_get_object_terms( $object_id, $taxonomy, array( 'fields' => 'ids' ) );
  1715 		$term_ids = wp_get_object_terms( $object_id, $taxonomy, array( 'fields' => 'ids' ) );
  1665 		$term_ids = array_map( 'intval', $term_ids );
  1716 		$term_ids = array_map( 'intval', $term_ids );
  1666 		wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
  1717 		wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
  1697 function wp_delete_term( $term, $taxonomy, $args = array() ) {
  1748 function wp_delete_term( $term, $taxonomy, $args = array() ) {
  1698 	global $wpdb;
  1749 	global $wpdb;
  1699 
  1750 
  1700 	$term = (int) $term;
  1751 	$term = (int) $term;
  1701 
  1752 
  1702 	if ( ! $ids = term_exists($term, $taxonomy) )
  1753 	if ( ! $ids = term_exists( $term, $taxonomy ) ) {
  1703 		return false;
  1754 		return false;
  1704 	if ( is_wp_error( $ids ) )
  1755 	}
       
  1756 	if ( is_wp_error( $ids ) ) {
  1705 		return $ids;
  1757 		return $ids;
       
  1758 	}
  1706 
  1759 
  1707 	$tt_id = $ids['term_taxonomy_id'];
  1760 	$tt_id = $ids['term_taxonomy_id'];
  1708 
  1761 
  1709 	$defaults = array();
  1762 	$defaults = array();
  1710 
  1763 
  1711 	if ( 'category' == $taxonomy ) {
  1764 	if ( 'category' == $taxonomy ) {
  1712 		$defaults['default'] = get_option( 'default_category' );
  1765 		$defaults['default'] = get_option( 'default_category' );
  1713 		if ( $defaults['default'] == $term )
  1766 		if ( $defaults['default'] == $term ) {
  1714 			return 0; // Don't delete the default category
  1767 			return 0; // Don't delete the default category
  1715 	}
  1768 		}
  1716 
  1769 	}
  1717 	$args = wp_parse_args($args, $defaults);
  1770 
       
  1771 	$args = wp_parse_args( $args, $defaults );
  1718 
  1772 
  1719 	if ( isset( $args['default'] ) ) {
  1773 	if ( isset( $args['default'] ) ) {
  1720 		$default = (int) $args['default'];
  1774 		$default = (int) $args['default'];
  1721 		if ( ! term_exists( $default, $taxonomy ) ) {
  1775 		if ( ! term_exists( $default, $taxonomy ) ) {
  1722 			unset( $default );
  1776 			unset( $default );
  1736 	 * @param string $taxonomy Taxonomy Name.
  1790 	 * @param string $taxonomy Taxonomy Name.
  1737 	 */
  1791 	 */
  1738 	do_action( 'pre_delete_term', $term, $taxonomy );
  1792 	do_action( 'pre_delete_term', $term, $taxonomy );
  1739 
  1793 
  1740 	// Update children to point to new parent
  1794 	// Update children to point to new parent
  1741 	if ( is_taxonomy_hierarchical($taxonomy) ) {
  1795 	if ( is_taxonomy_hierarchical( $taxonomy ) ) {
  1742 		$term_obj = get_term($term, $taxonomy);
  1796 		$term_obj = get_term( $term, $taxonomy );
  1743 		if ( is_wp_error( $term_obj ) )
  1797 		if ( is_wp_error( $term_obj ) ) {
  1744 			return $term_obj;
  1798 			return $term_obj;
       
  1799 		}
  1745 		$parent = $term_obj->parent;
  1800 		$parent = $term_obj->parent;
  1746 
  1801 
  1747 		$edit_ids = $wpdb->get_results( "SELECT term_id, term_taxonomy_id FROM $wpdb->term_taxonomy WHERE `parent` = " . (int)$term_obj->term_id );
  1802 		$edit_ids    = $wpdb->get_results( "SELECT term_id, term_taxonomy_id FROM $wpdb->term_taxonomy WHERE `parent` = " . (int) $term_obj->term_id );
  1748 		$edit_tt_ids = wp_list_pluck( $edit_ids, 'term_taxonomy_id' );
  1803 		$edit_tt_ids = wp_list_pluck( $edit_ids, 'term_taxonomy_id' );
  1749 
  1804 
  1750 		/**
  1805 		/**
  1751 		 * Fires immediately before a term to delete's children are reassigned a parent.
  1806 		 * Fires immediately before a term to delete's children are reassigned a parent.
  1752 		 *
  1807 		 *
  1754 		 *
  1809 		 *
  1755 		 * @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
  1810 		 * @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
  1756 		 */
  1811 		 */
  1757 		do_action( 'edit_term_taxonomies', $edit_tt_ids );
  1812 		do_action( 'edit_term_taxonomies', $edit_tt_ids );
  1758 
  1813 
  1759 		$wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id) + compact( 'taxonomy' ) );
  1814 		$wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id ) + compact( 'taxonomy' ) );
  1760 
  1815 
  1761 		// Clean the cache for all child terms.
  1816 		// Clean the cache for all child terms.
  1762 		$edit_term_ids = wp_list_pluck( $edit_ids, 'term_id' );
  1817 		$edit_term_ids = wp_list_pluck( $edit_ids, 'term_id' );
  1763 		clean_term_cache( $edit_term_ids, $taxonomy );
  1818 		clean_term_cache( $edit_term_ids, $taxonomy );
  1764 
  1819 
  1776 	$deleted_term = get_term( $term, $taxonomy );
  1831 	$deleted_term = get_term( $term, $taxonomy );
  1777 
  1832 
  1778 	$object_ids = (array) $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
  1833 	$object_ids = (array) $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
  1779 
  1834 
  1780 	foreach ( $object_ids as $object_id ) {
  1835 	foreach ( $object_ids as $object_id ) {
  1781 		$terms = wp_get_object_terms( $object_id, $taxonomy, array( 'fields' => 'ids', 'orderby' => 'none' ) );
  1836 		$terms = wp_get_object_terms(
  1782 		if ( 1 == count($terms) && isset($default) ) {
  1837 			$object_id,
  1783 			$terms = array($default);
  1838 			$taxonomy,
       
  1839 			array(
       
  1840 				'fields'  => 'ids',
       
  1841 				'orderby' => 'none',
       
  1842 			)
       
  1843 		);
       
  1844 		if ( 1 == count( $terms ) && isset( $default ) ) {
       
  1845 			$terms = array( $default );
  1784 		} else {
  1846 		} else {
  1785 			$terms = array_diff($terms, array($term));
  1847 			$terms = array_diff( $terms, array( $term ) );
  1786 			if (isset($default) && isset($force_default) && $force_default)
  1848 			if ( isset( $default ) && isset( $force_default ) && $force_default ) {
  1787 				$terms = array_merge($terms, array($default));
  1849 				$terms = array_merge( $terms, array( $default ) );
  1788 		}
  1850 			}
  1789 		$terms = array_map('intval', $terms);
  1851 		}
       
  1852 		$terms = array_map( 'intval', $terms );
  1790 		wp_set_object_terms( $object_id, $terms, $taxonomy );
  1853 		wp_set_object_terms( $object_id, $terms, $taxonomy );
  1791 	}
  1854 	}
  1792 
  1855 
  1793 	// Clean the relationship caches for all object types using this term.
  1856 	// Clean the relationship caches for all object types using this term.
  1794 	$tax_object = get_taxonomy( $taxonomy );
  1857 	$tax_object = get_taxonomy( $taxonomy );
  1795 	foreach ( $tax_object->object_type as $object_type )
  1858 	foreach ( $tax_object->object_type as $object_type ) {
  1796 		clean_object_term_cache( $object_ids, $object_type );
  1859 		clean_object_term_cache( $object_ids, $object_type );
       
  1860 	}
  1797 
  1861 
  1798 	$term_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->termmeta WHERE term_id = %d ", $term ) );
  1862 	$term_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->termmeta WHERE term_id = %d ", $term ) );
  1799 	foreach ( $term_meta_ids as $mid ) {
  1863 	foreach ( $term_meta_ids as $mid ) {
  1800 		delete_metadata_by_mid( 'term', $mid );
  1864 		delete_metadata_by_mid( 'term', $mid );
  1801 	}
  1865 	}
  1818 	 * @param int $tt_id Term taxonomy ID.
  1882 	 * @param int $tt_id Term taxonomy ID.
  1819 	 */
  1883 	 */
  1820 	do_action( 'deleted_term_taxonomy', $tt_id );
  1884 	do_action( 'deleted_term_taxonomy', $tt_id );
  1821 
  1885 
  1822 	// Delete the term if no taxonomies use it.
  1886 	// Delete the term if no taxonomies use it.
  1823 	if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term) ) )
  1887 	if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term ) ) ) {
  1824 		$wpdb->delete( $wpdb->terms, array( 'term_id' => $term ) );
  1888 		$wpdb->delete( $wpdb->terms, array( 'term_id' => $term ) );
  1825 
  1889 	}
  1826 	clean_term_cache($term, $taxonomy);
  1890 
       
  1891 	clean_term_cache( $term, $taxonomy );
  1827 
  1892 
  1828 	/**
  1893 	/**
  1829 	 * Fires after a term is deleted from the database and the cache is cleaned.
  1894 	 * Fires after a term is deleted from the database and the cache is cleaned.
  1830 	 *
  1895 	 *
  1831 	 * @since 2.5.0
  1896 	 * @since 2.5.0
  1865  *
  1930  *
  1866  * @since 2.0.0
  1931  * @since 2.0.0
  1867  *
  1932  *
  1868  * @param int $cat_ID Category term ID.
  1933  * @param int $cat_ID Category term ID.
  1869  * @return bool|int|WP_Error Returns true if completes delete action; false if term doesn't exist;
  1934  * @return bool|int|WP_Error Returns true if completes delete action; false if term doesn't exist;
  1870  * 	Zero on attempted deletion of default Category; WP_Error object is also a possibility.
  1935  *  Zero on attempted deletion of default Category; WP_Error object is also a possibility.
  1871  */
  1936  */
  1872 function wp_delete_category( $cat_ID ) {
  1937 function wp_delete_category( $cat_ID ) {
  1873 	return wp_delete_term( $cat_ID, 'category' );
  1938 	return wp_delete_term( $cat_ID, 'category' );
  1874 }
  1939 }
  1875 
  1940 
  1887  * @param string|array $taxonomies The taxonomies to retrieve terms from.
  1952  * @param string|array $taxonomies The taxonomies to retrieve terms from.
  1888  * @param array|string $args       See WP_Term_Query::__construct() for supported arguments.
  1953  * @param array|string $args       See WP_Term_Query::__construct() for supported arguments.
  1889  * @return array|WP_Error The requested term data or empty array if no terms found.
  1954  * @return array|WP_Error The requested term data or empty array if no terms found.
  1890  *                        WP_Error if any of the $taxonomies don't exist.
  1955  *                        WP_Error if any of the $taxonomies don't exist.
  1891  */
  1956  */
  1892 function wp_get_object_terms($object_ids, $taxonomies, $args = array()) {
  1957 function wp_get_object_terms( $object_ids, $taxonomies, $args = array() ) {
  1893 	if ( empty( $object_ids ) || empty( $taxonomies ) )
  1958 	if ( empty( $object_ids ) || empty( $taxonomies ) ) {
  1894 		return array();
  1959 		return array();
  1895 
  1960 	}
  1896 	if ( !is_array($taxonomies) )
  1961 
  1897 		$taxonomies = array($taxonomies);
  1962 	if ( ! is_array( $taxonomies ) ) {
       
  1963 		$taxonomies = array( $taxonomies );
       
  1964 	}
  1898 
  1965 
  1899 	foreach ( $taxonomies as $taxonomy ) {
  1966 	foreach ( $taxonomies as $taxonomy ) {
  1900 		if ( ! taxonomy_exists($taxonomy) )
  1967 		if ( ! taxonomy_exists( $taxonomy ) ) {
  1901 			return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  1968 			return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  1902 	}
  1969 		}
  1903 
  1970 	}
  1904 	if ( !is_array($object_ids) )
  1971 
  1905 		$object_ids = array($object_ids);
  1972 	if ( ! is_array( $object_ids ) ) {
  1906 	$object_ids = array_map('intval', $object_ids);
  1973 		$object_ids = array( $object_ids );
       
  1974 	}
       
  1975 	$object_ids = array_map( 'intval', $object_ids );
  1907 
  1976 
  1908 	$args = wp_parse_args( $args );
  1977 	$args = wp_parse_args( $args );
  1909 
  1978 
  1910 	/**
  1979 	/**
  1911 	 * Filter arguments for retrieving object terms.
  1980 	 * Filter arguments for retrieving object terms.
  1937 		if ( isset( $t->args ) && is_array( $t->args ) ) {
  2006 		if ( isset( $t->args ) && is_array( $t->args ) ) {
  1938 			$args = array_merge( $args, $t->args );
  2007 			$args = array_merge( $args, $t->args );
  1939 		}
  2008 		}
  1940 	}
  2009 	}
  1941 
  2010 
  1942 	$args['taxonomy'] = $taxonomies;
  2011 	$args['taxonomy']   = $taxonomies;
  1943 	$args['object_ids'] = $object_ids;
  2012 	$args['object_ids'] = $object_ids;
  1944 
  2013 
  1945 	// Taxonomies registered without an 'args' param are handled here.
  2014 	// Taxonomies registered without an 'args' param are handled here.
  1946 	if ( ! empty( $taxonomies ) ) {
  2015 	if ( ! empty( $taxonomies ) ) {
  1947 		$terms_from_remaining_taxonomies = get_terms( $args );
  2016 		$terms_from_remaining_taxonomies = get_terms( $args );
  2031  *                        WP_Error otherwise.
  2100  *                        WP_Error otherwise.
  2032  */
  2101  */
  2033 function wp_insert_term( $term, $taxonomy, $args = array() ) {
  2102 function wp_insert_term( $term, $taxonomy, $args = array() ) {
  2034 	global $wpdb;
  2103 	global $wpdb;
  2035 
  2104 
  2036 	if ( ! taxonomy_exists($taxonomy) ) {
  2105 	if ( ! taxonomy_exists( $taxonomy ) ) {
  2037 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  2106 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  2038 	}
  2107 	}
  2039 	/**
  2108 	/**
  2040 	 * Filters a term before it is sanitized and inserted into the database.
  2109 	 * Filters a term before it is sanitized and inserted into the database.
  2041 	 *
  2110 	 *
  2052 		return new WP_Error( 'invalid_term_id', __( 'Invalid term ID.' ) );
  2121 		return new WP_Error( 'invalid_term_id', __( 'Invalid term ID.' ) );
  2053 	}
  2122 	}
  2054 	if ( '' == trim( $term ) ) {
  2123 	if ( '' == trim( $term ) ) {
  2055 		return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) );
  2124 		return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) );
  2056 	}
  2125 	}
  2057 	$defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
  2126 	$defaults = array(
  2058 	$args = wp_parse_args( $args, $defaults );
  2127 		'alias_of'    => '',
       
  2128 		'description' => '',
       
  2129 		'parent'      => 0,
       
  2130 		'slug'        => '',
       
  2131 	);
       
  2132 	$args     = wp_parse_args( $args, $defaults );
  2059 
  2133 
  2060 	if ( $args['parent'] > 0 && ! term_exists( (int) $args['parent'] ) ) {
  2134 	if ( $args['parent'] > 0 && ! term_exists( (int) $args['parent'] ) ) {
  2061 		return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
  2135 		return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
  2062 	}
  2136 	}
  2063 
  2137 
  2064 	$args['name'] = $term;
  2138 	$args['name']     = $term;
  2065 	$args['taxonomy'] = $taxonomy;
  2139 	$args['taxonomy'] = $taxonomy;
  2066 
  2140 
  2067 	// Coerce null description to strings, to avoid database errors.
  2141 	// Coerce null description to strings, to avoid database errors.
  2068 	$args['description'] = (string) $args['description'];
  2142 	$args['description'] = (string) $args['description'];
  2069 
  2143 
  2070 	$args = sanitize_term($args, $taxonomy, 'db');
  2144 	$args = sanitize_term( $args, $taxonomy, 'db' );
  2071 
  2145 
  2072 	// expected_slashed ($name)
  2146 	// expected_slashed ($name)
  2073 	$name = wp_unslash( $args['name'] );
  2147 	$name        = wp_unslash( $args['name'] );
  2074 	$description = wp_unslash( $args['description'] );
  2148 	$description = wp_unslash( $args['description'] );
  2075 	$parent = (int) $args['parent'];
  2149 	$parent      = (int) $args['parent'];
  2076 
  2150 
  2077 	$slug_provided = ! empty( $args['slug'] );
  2151 	$slug_provided = ! empty( $args['slug'] );
  2078 	if ( ! $slug_provided ) {
  2152 	if ( ! $slug_provided ) {
  2079 		$slug = sanitize_title( $name );
  2153 		$slug = sanitize_title( $name );
  2080 	} else {
  2154 	} else {
  2090 		} elseif ( ! empty( $alias->term_id ) ) {
  2164 		} elseif ( ! empty( $alias->term_id ) ) {
  2091 			/*
  2165 			/*
  2092 			 * The alias is not in a group, so we create a new one
  2166 			 * The alias is not in a group, so we create a new one
  2093 			 * and add the alias to it.
  2167 			 * and add the alias to it.
  2094 			 */
  2168 			 */
  2095 			$term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
  2169 			$term_group = $wpdb->get_var( "SELECT MAX(term_group) FROM $wpdb->terms" ) + 1;
  2096 
  2170 
  2097 			wp_update_term( $alias->term_id, $taxonomy, array(
  2171 			wp_update_term(
  2098 				'term_group' => $term_group,
  2172 				$alias->term_id,
  2099 			) );
  2173 				$taxonomy,
       
  2174 				array(
       
  2175 					'term_group' => $term_group,
       
  2176 				)
       
  2177 			);
  2100 		}
  2178 		}
  2101 	}
  2179 	}
  2102 
  2180 
  2103 	/*
  2181 	/*
  2104 	 * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy,
  2182 	 * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy,
  2105 	 * unless a unique slug has been explicitly provided.
  2183 	 * unless a unique slug has been explicitly provided.
  2106 	 */
  2184 	 */
  2107 	$name_matches = get_terms( $taxonomy, array(
  2185 	$name_matches = get_terms(
  2108 		'name' => $name,
  2186 		$taxonomy,
  2109 		'hide_empty' => false,
  2187 		array(
  2110 		'parent' => $args['parent'],
  2188 			'name'                   => $name,
  2111 	) );
  2189 			'hide_empty'             => false,
       
  2190 			'parent'                 => $args['parent'],
       
  2191 			'update_term_meta_cache' => false,
       
  2192 		)
       
  2193 	);
  2112 
  2194 
  2113 	/*
  2195 	/*
  2114 	 * The `name` match in `get_terms()` doesn't differentiate accented characters,
  2196 	 * The `name` match in `get_terms()` doesn't differentiate accented characters,
  2115 	 * so we do a stricter comparison here.
  2197 	 * so we do a stricter comparison here.
  2116 	 */
  2198 	 */
  2126 
  2208 
  2127 	if ( $name_match ) {
  2209 	if ( $name_match ) {
  2128 		$slug_match = get_term_by( 'slug', $slug, $taxonomy );
  2210 		$slug_match = get_term_by( 'slug', $slug, $taxonomy );
  2129 		if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) {
  2211 		if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) {
  2130 			if ( is_taxonomy_hierarchical( $taxonomy ) ) {
  2212 			if ( is_taxonomy_hierarchical( $taxonomy ) ) {
  2131 				$siblings = get_terms( $taxonomy, array( 'get' => 'all', 'parent' => $parent ) );
  2213 				$siblings = get_terms(
       
  2214 					$taxonomy,
       
  2215 					array(
       
  2216 						'get'                    => 'all',
       
  2217 						'parent'                 => $parent,
       
  2218 						'update_term_meta_cache' => false,
       
  2219 					)
       
  2220 				);
  2132 
  2221 
  2133 				$existing_term = null;
  2222 				$existing_term = null;
  2134 				if ( ( ! $slug_provided || $name_match->slug === $slug ) && in_array( $name, wp_list_pluck( $siblings, 'name' ) ) ) {
  2223 				if ( ( ! $slug_provided || $name_match->slug === $slug ) && in_array( $name, wp_list_pluck( $siblings, 'name' ) ) ) {
  2135 					$existing_term = $name_match;
  2224 					$existing_term = $name_match;
  2136 				} elseif ( $slug_match && in_array( $slug, wp_list_pluck( $siblings, 'slug' ) ) ) {
  2225 				} elseif ( $slug_match && in_array( $slug, wp_list_pluck( $siblings, 'slug' ) ) ) {
  2166 	}
  2255 	}
  2167 
  2256 
  2168 	$term_id = (int) $wpdb->insert_id;
  2257 	$term_id = (int) $wpdb->insert_id;
  2169 
  2258 
  2170 	// Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string.
  2259 	// Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string.
  2171 	if ( empty($slug) ) {
  2260 	if ( empty( $slug ) ) {
  2172 		$slug = sanitize_title($slug, $term_id);
  2261 		$slug = sanitize_title( $slug, $term_id );
  2173 
  2262 
  2174 		/** This action is documented in wp-includes/taxonomy.php */
  2263 		/** This action is documented in wp-includes/taxonomy.php */
  2175 		do_action( 'edit_terms', $term_id, $taxonomy );
  2264 		do_action( 'edit_terms', $term_id, $taxonomy );
  2176 		$wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
  2265 		$wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
  2177 
  2266 
  2179 		do_action( 'edited_terms', $term_id, $taxonomy );
  2268 		do_action( 'edited_terms', $term_id, $taxonomy );
  2180 	}
  2269 	}
  2181 
  2270 
  2182 	$tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) );
  2271 	$tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) );
  2183 
  2272 
  2184 	if ( !empty($tt_id) ) {
  2273 	if ( ! empty( $tt_id ) ) {
  2185 		return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
  2274 		return array(
  2186 	}
  2275 			'term_id'          => $term_id,
  2187 	$wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) );
  2276 			'term_taxonomy_id' => $tt_id,
       
  2277 		);
       
  2278 	}
       
  2279 	$wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ) + array( 'count' => 0 ) );
  2188 	$tt_id = (int) $wpdb->insert_id;
  2280 	$tt_id = (int) $wpdb->insert_id;
  2189 
  2281 
  2190 	/*
  2282 	/*
  2191 	 * Sanity check: if we just created a term with the same parent + taxonomy + slug but a higher term_id than
  2283 	 * Sanity check: if we just created a term with the same parent + taxonomy + slug but a higher term_id than
  2192 	 * an existing term, then we have unwittingly created a duplicate term. Delete the dupe, and use the term_id
  2284 	 * an existing term, then we have unwittingly created a duplicate term. Delete the dupe, and use the term_id
  2193 	 * and term_taxonomy_id of the older term instead. Then return out of the function so that the "create" hooks
  2285 	 * and term_taxonomy_id of the older term instead. Then return out of the function so that the "create" hooks
  2194 	 * are not fired.
  2286 	 * are not fired.
  2195 	 */
  2287 	 */
  2196 	$duplicate_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.term_id, tt.term_taxonomy_id FROM $wpdb->terms t INNER JOIN $wpdb->term_taxonomy tt ON ( tt.term_id = t.term_id ) WHERE t.slug = %s AND tt.parent = %d AND tt.taxonomy = %s AND t.term_id < %d AND tt.term_taxonomy_id != %d", $slug, $parent, $taxonomy, $term_id, $tt_id ) );
  2288 	$duplicate_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.term_id, t.slug, tt.term_taxonomy_id, tt.taxonomy FROM $wpdb->terms t INNER JOIN $wpdb->term_taxonomy tt ON ( tt.term_id = t.term_id ) WHERE t.slug = %s AND tt.parent = %d AND tt.taxonomy = %s AND t.term_id < %d AND tt.term_taxonomy_id != %d", $slug, $parent, $taxonomy, $term_id, $tt_id ) );
       
  2289 
       
  2290 	/**
       
  2291 	 * Filters the duplicate term check that takes place during term creation.
       
  2292 	 *
       
  2293 	 * Term parent+taxonomy+slug combinations are meant to be unique, and wp_insert_term()
       
  2294 	 * performs a last-minute confirmation of this uniqueness before allowing a new term
       
  2295 	 * to be created. Plugins with different uniqueness requirements may use this filter
       
  2296 	 * to bypass or modify the duplicate-term check.
       
  2297 	 *
       
  2298 	 * @since 5.1.0
       
  2299 	 *
       
  2300 	 * @param object $duplicate_term Duplicate term row from terms table, if found.
       
  2301 	 * @param string $term           Term being inserted.
       
  2302 	 * @param string $taxonomy       Taxonomy name.
       
  2303 	 * @param array  $args           Term arguments passed to the function.
       
  2304 	 * @param int    $tt_id          term_taxonomy_id for the newly created term.
       
  2305 	 */
       
  2306 	$duplicate_term = apply_filters( 'wp_insert_term_duplicate_term_check', $duplicate_term, $term, $taxonomy, $args, $tt_id );
       
  2307 
  2197 	if ( $duplicate_term ) {
  2308 	if ( $duplicate_term ) {
  2198 		$wpdb->delete( $wpdb->terms, array( 'term_id' => $term_id ) );
  2309 		$wpdb->delete( $wpdb->terms, array( 'term_id' => $term_id ) );
  2199 		$wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
  2310 		$wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
  2200 
  2311 
  2201 		$term_id = (int) $duplicate_term->term_id;
  2312 		$term_id = (int) $duplicate_term->term_id;
  2202 		$tt_id   = (int) $duplicate_term->term_taxonomy_id;
  2313 		$tt_id   = (int) $duplicate_term->term_taxonomy_id;
  2203 
  2314 
  2204 		clean_term_cache( $term_id, $taxonomy );
  2315 		clean_term_cache( $term_id, $taxonomy );
  2205 		return array( 'term_id' => $term_id, 'term_taxonomy_id' => $tt_id );
  2316 		return array(
       
  2317 			'term_id'          => $term_id,
       
  2318 			'term_taxonomy_id' => $tt_id,
       
  2319 		);
  2206 	}
  2320 	}
  2207 
  2321 
  2208 	/**
  2322 	/**
  2209 	 * Fires immediately after a new term is created, before the term cache is cleaned.
  2323 	 * Fires immediately after a new term is created, before the term cache is cleaned.
  2210 	 *
  2324 	 *
  2212 	 *
  2326 	 *
  2213 	 * @param int    $term_id  Term ID.
  2327 	 * @param int    $term_id  Term ID.
  2214 	 * @param int    $tt_id    Term taxonomy ID.
  2328 	 * @param int    $tt_id    Term taxonomy ID.
  2215 	 * @param string $taxonomy Taxonomy slug.
  2329 	 * @param string $taxonomy Taxonomy slug.
  2216 	 */
  2330 	 */
  2217 	do_action( "create_term", $term_id, $tt_id, $taxonomy );
  2331 	do_action( 'create_term', $term_id, $tt_id, $taxonomy );
  2218 
  2332 
  2219 	/**
  2333 	/**
  2220 	 * Fires after a new term is created for a specific taxonomy.
  2334 	 * Fires after a new term is created for a specific taxonomy.
  2221 	 *
  2335 	 *
  2222 	 * The dynamic portion of the hook name, `$taxonomy`, refers
  2336 	 * The dynamic portion of the hook name, `$taxonomy`, refers
  2237 	 * @param int $term_id Term ID.
  2351 	 * @param int $term_id Term ID.
  2238 	 * @param int $tt_id   Taxonomy term ID.
  2352 	 * @param int $tt_id   Taxonomy term ID.
  2239 	 */
  2353 	 */
  2240 	$term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
  2354 	$term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
  2241 
  2355 
  2242 	clean_term_cache($term_id, $taxonomy);
  2356 	clean_term_cache( $term_id, $taxonomy );
  2243 
  2357 
  2244 	/**
  2358 	/**
  2245 	 * Fires after a new term is created, and after the term cache has been cleaned.
  2359 	 * Fires after a new term is created, and after the term cache has been cleaned.
  2246 	 *
  2360 	 *
  2247 	 * @since 2.3.0
  2361 	 * @since 2.3.0
  2263 	 * @param int $term_id Term ID.
  2377 	 * @param int $term_id Term ID.
  2264 	 * @param int $tt_id   Term taxonomy ID.
  2378 	 * @param int $tt_id   Term taxonomy ID.
  2265 	 */
  2379 	 */
  2266 	do_action( "created_{$taxonomy}", $term_id, $tt_id );
  2380 	do_action( "created_{$taxonomy}", $term_id, $tt_id );
  2267 
  2381 
  2268 	return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
  2382 	return array(
       
  2383 		'term_id'          => $term_id,
       
  2384 		'term_taxonomy_id' => $tt_id,
       
  2385 	);
  2269 }
  2386 }
  2270 
  2387 
  2271 /**
  2388 /**
  2272  * Create Term and Taxonomy Relationships.
  2389  * Create Term and Taxonomy Relationships.
  2273  *
  2390  *
  2298 
  2415 
  2299 	if ( ! taxonomy_exists( $taxonomy ) ) {
  2416 	if ( ! taxonomy_exists( $taxonomy ) ) {
  2300 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  2417 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
  2301 	}
  2418 	}
  2302 
  2419 
  2303 	if ( !is_array($terms) )
  2420 	if ( ! is_array( $terms ) ) {
  2304 		$terms = array($terms);
  2421 		$terms = array( $terms );
  2305 
  2422 	}
  2306 	if ( ! $append )
  2423 
  2307 		$old_tt_ids =  wp_get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids', 'orderby' => 'none'));
  2424 	if ( ! $append ) {
  2308 	else
  2425 		$old_tt_ids = wp_get_object_terms(
       
  2426 			$object_id,
       
  2427 			$taxonomy,
       
  2428 			array(
       
  2429 				'fields'                 => 'tt_ids',
       
  2430 				'orderby'                => 'none',
       
  2431 				'update_term_meta_cache' => false,
       
  2432 			)
       
  2433 		);
       
  2434 	} else {
  2309 		$old_tt_ids = array();
  2435 		$old_tt_ids = array();
  2310 
  2436 	}
  2311 	$tt_ids = array();
  2437 
  2312 	$term_ids = array();
  2438 	$tt_ids     = array();
       
  2439 	$term_ids   = array();
  2313 	$new_tt_ids = array();
  2440 	$new_tt_ids = array();
  2314 
  2441 
  2315 	foreach ( (array) $terms as $term) {
  2442 	foreach ( (array) $terms as $term ) {
  2316 		if ( !strlen(trim($term)) )
  2443 		if ( ! strlen( trim( $term ) ) ) {
  2317 			continue;
  2444 			continue;
  2318 
  2445 		}
  2319 		if ( !$term_info = term_exists($term, $taxonomy) ) {
  2446 
       
  2447 		if ( ! $term_info = term_exists( $term, $taxonomy ) ) {
  2320 			// Skip if a non-existent term ID is passed.
  2448 			// Skip if a non-existent term ID is passed.
  2321 			if ( is_int($term) )
  2449 			if ( is_int( $term ) ) {
  2322 				continue;
  2450 				continue;
  2323 			$term_info = wp_insert_term($term, $taxonomy);
  2451 			}
  2324 		}
  2452 			$term_info = wp_insert_term( $term, $taxonomy );
  2325 		if ( is_wp_error($term_info) )
  2453 		}
       
  2454 		if ( is_wp_error( $term_info ) ) {
  2326 			return $term_info;
  2455 			return $term_info;
       
  2456 		}
  2327 		$term_ids[] = $term_info['term_id'];
  2457 		$term_ids[] = $term_info['term_id'];
  2328 		$tt_id = $term_info['term_taxonomy_id'];
  2458 		$tt_id      = $term_info['term_taxonomy_id'];
  2329 		$tt_ids[] = $tt_id;
  2459 		$tt_ids[]   = $tt_id;
  2330 
  2460 
  2331 		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 ) ) )
  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 ) ) ) {
  2332 			continue;
  2462 			continue;
       
  2463 		}
  2333 
  2464 
  2334 		/**
  2465 		/**
  2335 		 * Fires immediately before an object-term relationship is added.
  2466 		 * Fires immediately before an object-term relationship is added.
  2336 		 *
  2467 		 *
  2337 		 * @since 2.9.0
  2468 		 * @since 2.9.0
  2340 		 * @param int    $object_id Object ID.
  2471 		 * @param int    $object_id Object ID.
  2341 		 * @param int    $tt_id     Term taxonomy ID.
  2472 		 * @param int    $tt_id     Term taxonomy ID.
  2342 		 * @param string $taxonomy  Taxonomy slug.
  2473 		 * @param string $taxonomy  Taxonomy slug.
  2343 		 */
  2474 		 */
  2344 		do_action( 'add_term_relationship', $object_id, $tt_id, $taxonomy );
  2475 		do_action( 'add_term_relationship', $object_id, $tt_id, $taxonomy );
  2345 		$wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $tt_id ) );
  2476 		$wpdb->insert(
       
  2477 			$wpdb->term_relationships,
       
  2478 			array(
       
  2479 				'object_id'        => $object_id,
       
  2480 				'term_taxonomy_id' => $tt_id,
       
  2481 			)
       
  2482 		);
  2346 
  2483 
  2347 		/**
  2484 		/**
  2348 		 * Fires immediately after an object-term relationship is added.
  2485 		 * Fires immediately after an object-term relationship is added.
  2349 		 *
  2486 		 *
  2350 		 * @since 2.9.0
  2487 		 * @since 2.9.0
  2356 		 */
  2493 		 */
  2357 		do_action( 'added_term_relationship', $object_id, $tt_id, $taxonomy );
  2494 		do_action( 'added_term_relationship', $object_id, $tt_id, $taxonomy );
  2358 		$new_tt_ids[] = $tt_id;
  2495 		$new_tt_ids[] = $tt_id;
  2359 	}
  2496 	}
  2360 
  2497 
  2361 	if ( $new_tt_ids )
  2498 	if ( $new_tt_ids ) {
  2362 		wp_update_term_count( $new_tt_ids, $taxonomy );
  2499 		wp_update_term_count( $new_tt_ids, $taxonomy );
       
  2500 	}
  2363 
  2501 
  2364 	if ( ! $append ) {
  2502 	if ( ! $append ) {
  2365 		$delete_tt_ids = array_diff( $old_tt_ids, $tt_ids );
  2503 		$delete_tt_ids = array_diff( $old_tt_ids, $tt_ids );
  2366 
  2504 
  2367 		if ( $delete_tt_ids ) {
  2505 		if ( $delete_tt_ids ) {
  2368 			$in_delete_tt_ids = "'" . implode( "', '", $delete_tt_ids ) . "'";
  2506 			$in_delete_tt_ids = "'" . implode( "', '", $delete_tt_ids ) . "'";
  2369 			$delete_term_ids = $wpdb->get_col( $wpdb->prepare( "SELECT tt.term_id FROM $wpdb->term_taxonomy AS tt WHERE tt.taxonomy = %s AND tt.term_taxonomy_id IN ($in_delete_tt_ids)", $taxonomy ) );
  2507 			$delete_term_ids  = $wpdb->get_col( $wpdb->prepare( "SELECT tt.term_id FROM $wpdb->term_taxonomy AS tt WHERE tt.taxonomy = %s AND tt.term_taxonomy_id IN ($in_delete_tt_ids)", $taxonomy ) );
  2370 			$delete_term_ids = array_map( 'intval', $delete_term_ids );
  2508 			$delete_term_ids  = array_map( 'intval', $delete_term_ids );
  2371 
  2509 
  2372 			$remove = wp_remove_object_terms( $object_id, $delete_term_ids, $taxonomy );
  2510 			$remove = wp_remove_object_terms( $object_id, $delete_term_ids, $taxonomy );
  2373 			if ( is_wp_error( $remove ) ) {
  2511 			if ( is_wp_error( $remove ) ) {
  2374 				return $remove;
  2512 				return $remove;
  2375 			}
  2513 			}
  2376 		}
  2514 		}
  2377 	}
  2515 	}
  2378 
  2516 
  2379 	$t = get_taxonomy($taxonomy);
  2517 	$t = get_taxonomy( $taxonomy );
  2380 	if ( ! $append && isset($t->sort) && $t->sort ) {
  2518 	if ( ! $append && isset( $t->sort ) && $t->sort ) {
  2381 		$values = array();
  2519 		$values       = array();
  2382 		$term_order = 0;
  2520 		$term_order   = 0;
  2383 		$final_tt_ids = wp_get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids'));
  2521 		$final_tt_ids = wp_get_object_terms(
  2384 		foreach ( $tt_ids as $tt_id )
  2522 			$object_id,
  2385 			if ( in_array($tt_id, $final_tt_ids) )
  2523 			$taxonomy,
  2386 				$values[] = $wpdb->prepare( "(%d, %d, %d)", $object_id, $tt_id, ++$term_order);
  2524 			array(
  2387 		if ( $values )
  2525 				'fields'                 => 'tt_ids',
  2388 			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)" ) )
  2526 				'update_term_meta_cache' => false,
       
  2527 			)
       
  2528 		);
       
  2529 		foreach ( $tt_ids as $tt_id ) {
       
  2530 			if ( in_array( $tt_id, $final_tt_ids ) ) {
       
  2531 				$values[] = $wpdb->prepare( '(%d, %d, %d)', $object_id, $tt_id, ++$term_order );
       
  2532 			}
       
  2533 		}
       
  2534 		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)' ) ) {
  2389 				return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database.' ), $wpdb->last_error );
  2536 				return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database.' ), $wpdb->last_error );
       
  2537 			}
       
  2538 		}
  2390 	}
  2539 	}
  2391 
  2540 
  2392 	wp_cache_delete( $object_id, $taxonomy . '_relationships' );
  2541 	wp_cache_delete( $object_id, $taxonomy . '_relationships' );
  2393 	wp_cache_delete( 'last_changed', 'terms' );
  2542 	wp_cache_delete( 'last_changed', 'terms' );
  2394 
  2543 
  2515  * slug has to be globally unique for every taxonomy.
  2664  * slug has to be globally unique for every taxonomy.
  2516  *
  2665  *
  2517  * The way this works is that if the taxonomy that the term belongs to is
  2666  * The way this works is that if the taxonomy that the term belongs to is
  2518  * hierarchical and has a parent, it will append that parent to the $slug.
  2667  * hierarchical and has a parent, it will append that parent to the $slug.
  2519  *
  2668  *
  2520  * If that still doesn't return an unique slug, then it try to append a number
  2669  * If that still doesn't return a unique slug, then it tries to append a number
  2521  * until it finds a number that is truly unique.
  2670  * until it finds a number that is truly unique.
  2522  *
  2671  *
  2523  * The only purpose for `$term` is for appending a parent, if one exists.
  2672  * The only purpose for `$term` is for appending a parent, if one exists.
  2524  *
  2673  *
  2525  * @since 2.3.0
  2674  * @since 2.3.0
  2531  * @return string Will return a true unique slug.
  2680  * @return string Will return a true unique slug.
  2532  */
  2681  */
  2533 function wp_unique_term_slug( $slug, $term ) {
  2682 function wp_unique_term_slug( $slug, $term ) {
  2534 	global $wpdb;
  2683 	global $wpdb;
  2535 
  2684 
  2536 	$needs_suffix = true;
  2685 	$needs_suffix  = true;
  2537 	$original_slug = $slug;
  2686 	$original_slug = $slug;
  2538 
  2687 
  2539 	// As of 4.1, duplicate slugs are allowed as long as they're in different taxonomies.
  2688 	// As of 4.1, duplicate slugs are allowed as long as they're in different taxonomies.
  2540 	if ( ! term_exists( $slug ) || get_option( 'db_version' ) >= 30133 && ! get_term_by( 'slug', $slug, $term->taxonomy ) ) {
  2689 	if ( ! term_exists( $slug ) || get_option( 'db_version' ) >= 30133 && ! get_term_by( 'slug', $slug, $term->taxonomy ) ) {
  2541 		$needs_suffix = false;
  2690 		$needs_suffix = false;
  2546 	 * by incorporating parent slugs.
  2695 	 * by incorporating parent slugs.
  2547 	 */
  2696 	 */
  2548 	$parent_suffix = '';
  2697 	$parent_suffix = '';
  2549 	if ( $needs_suffix && is_taxonomy_hierarchical( $term->taxonomy ) && ! empty( $term->parent ) ) {
  2698 	if ( $needs_suffix && is_taxonomy_hierarchical( $term->taxonomy ) && ! empty( $term->parent ) ) {
  2550 		$the_parent = $term->parent;
  2699 		$the_parent = $term->parent;
  2551 		while ( ! empty($the_parent) ) {
  2700 		while ( ! empty( $the_parent ) ) {
  2552 			$parent_term = get_term($the_parent, $term->taxonomy);
  2701 			$parent_term = get_term( $the_parent, $term->taxonomy );
  2553 			if ( is_wp_error($parent_term) || empty($parent_term) )
  2702 			if ( is_wp_error( $parent_term ) || empty( $parent_term ) ) {
  2554 				break;
  2703 				break;
       
  2704 			}
  2555 			$parent_suffix .= '-' . $parent_term->slug;
  2705 			$parent_suffix .= '-' . $parent_term->slug;
  2556 			if ( ! term_exists( $slug . $parent_suffix ) ) {
  2706 			if ( ! term_exists( $slug . $parent_suffix ) ) {
  2557 				break;
  2707 				break;
  2558 			}
  2708 			}
  2559 
  2709 
  2560 			if ( empty($parent_term->parent) )
  2710 			if ( empty( $parent_term->parent ) ) {
  2561 				break;
  2711 				break;
       
  2712 			}
  2562 			$the_parent = $parent_term->parent;
  2713 			$the_parent = $parent_term->parent;
  2563 		}
  2714 		}
  2564 	}
  2715 	}
  2565 
  2716 
  2566 	// If we didn't get a unique slug, try appending a number to make it unique.
  2717 	// If we didn't get a unique slug, try appending a number to make it unique.
  2576 	 */
  2727 	 */
  2577 	if ( apply_filters( 'wp_unique_term_slug_is_bad_slug', $needs_suffix, $slug, $term ) ) {
  2728 	if ( apply_filters( 'wp_unique_term_slug_is_bad_slug', $needs_suffix, $slug, $term ) ) {
  2578 		if ( $parent_suffix ) {
  2729 		if ( $parent_suffix ) {
  2579 			$slug .= $parent_suffix;
  2730 			$slug .= $parent_suffix;
  2580 		} else {
  2731 		} else {
  2581 			if ( ! empty( $term->term_id ) )
  2732 			if ( ! empty( $term->term_id ) ) {
  2582 				$query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id );
  2733 				$query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id );
  2583 			else
  2734 			} else {
  2584 				$query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug );
  2735 				$query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug );
       
  2736 			}
  2585 
  2737 
  2586 			if ( $wpdb->get_var( $query ) ) {
  2738 			if ( $wpdb->get_var( $query ) ) {
  2587 				$num = 2;
  2739 				$num = 2;
  2588 				do {
  2740 				do {
  2589 					$alt_slug = $slug . "-$num";
  2741 					$alt_slug = $slug . "-$num";
  2661 
  2813 
  2662 	// Escape data pulled from DB.
  2814 	// Escape data pulled from DB.
  2663 	$term = wp_slash( $term );
  2815 	$term = wp_slash( $term );
  2664 
  2816 
  2665 	// Merge old and new args with new args overwriting old ones.
  2817 	// Merge old and new args with new args overwriting old ones.
  2666 	$args = array_merge($term, $args);
  2818 	$args = array_merge( $term, $args );
  2667 
  2819 
  2668 	$defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
  2820 	$defaults    = array(
  2669 	$args = wp_parse_args($args, $defaults);
  2821 		'alias_of'    => '',
  2670 	$args = sanitize_term($args, $taxonomy, 'db');
  2822 		'description' => '',
       
  2823 		'parent'      => 0,
       
  2824 		'slug'        => '',
       
  2825 	);
       
  2826 	$args        = wp_parse_args( $args, $defaults );
       
  2827 	$args        = sanitize_term( $args, $taxonomy, 'db' );
  2671 	$parsed_args = $args;
  2828 	$parsed_args = $args;
  2672 
  2829 
  2673 	// expected_slashed ($name)
  2830 	// expected_slashed ($name)
  2674 	$name = wp_unslash( $args['name'] );
  2831 	$name        = wp_unslash( $args['name'] );
  2675 	$description = wp_unslash( $args['description'] );
  2832 	$description = wp_unslash( $args['description'] );
  2676 
  2833 
  2677 	$parsed_args['name'] = $name;
  2834 	$parsed_args['name']        = $name;
  2678 	$parsed_args['description'] = $description;
  2835 	$parsed_args['description'] = $description;
  2679 
  2836 
  2680 	if ( '' == trim( $name ) ) {
  2837 	if ( '' == trim( $name ) ) {
  2681 		return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) );
  2838 		return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) );
  2682 	}
  2839 	}
  2686 	}
  2843 	}
  2687 
  2844 
  2688 	$empty_slug = false;
  2845 	$empty_slug = false;
  2689 	if ( empty( $args['slug'] ) ) {
  2846 	if ( empty( $args['slug'] ) ) {
  2690 		$empty_slug = true;
  2847 		$empty_slug = true;
  2691 		$slug = sanitize_title($name);
  2848 		$slug       = sanitize_title( $name );
  2692 	} else {
  2849 	} else {
  2693 		$slug = $args['slug'];
  2850 		$slug = $args['slug'];
  2694 	}
  2851 	}
  2695 
  2852 
  2696 	$parsed_args['slug'] = $slug;
  2853 	$parsed_args['slug'] = $slug;
  2704 		} elseif ( ! empty( $alias->term_id ) ) {
  2861 		} elseif ( ! empty( $alias->term_id ) ) {
  2705 			/*
  2862 			/*
  2706 			 * The alias is not in a group, so we create a new one
  2863 			 * The alias is not in a group, so we create a new one
  2707 			 * and add the alias to it.
  2864 			 * and add the alias to it.
  2708 			 */
  2865 			 */
  2709 			$term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
  2866 			$term_group = $wpdb->get_var( "SELECT MAX(term_group) FROM $wpdb->terms" ) + 1;
  2710 
  2867 
  2711 			wp_update_term( $alias->term_id, $taxonomy, array(
  2868 			wp_update_term(
  2712 				'term_group' => $term_group,
  2869 				$alias->term_id,
  2713 			) );
  2870 				$taxonomy,
       
  2871 				array(
       
  2872 					'term_group' => $term_group,
       
  2873 				)
       
  2874 			);
  2714 		}
  2875 		}
  2715 
  2876 
  2716 		$parsed_args['term_group'] = $term_group;
  2877 		$parsed_args['term_group'] = $term_group;
  2717 	}
  2878 	}
  2718 
  2879 
  2734 	// Check for duplicate slug
  2895 	// Check for duplicate slug
  2735 	$duplicate = get_term_by( 'slug', $slug, $taxonomy );
  2896 	$duplicate = get_term_by( 'slug', $slug, $taxonomy );
  2736 	if ( $duplicate && $duplicate->term_id != $term_id ) {
  2897 	if ( $duplicate && $duplicate->term_id != $term_id ) {
  2737 		// If an empty slug was passed or the parent changed, reset the slug to something unique.
  2898 		// If an empty slug was passed or the parent changed, reset the slug to something unique.
  2738 		// Otherwise, bail.
  2899 		// Otherwise, bail.
  2739 		if ( $empty_slug || ( $parent != $term['parent']) ) {
  2900 		if ( $empty_slug || ( $parent != $term['parent'] ) ) {
  2740 			$slug = wp_unique_term_slug($slug, (object) $args);
  2901 			$slug = wp_unique_term_slug( $slug, (object) $args );
  2741 		} else {
  2902 		} else {
  2742 			/* translators: 1: Taxonomy term slug */
  2903 			/* translators: %s: taxonomy term slug */
  2743 			return new WP_Error( 'duplicate_term_slug', sprintf( __( 'The slug &#8220;%s&#8221; is already in use by another term.' ), $slug ) );
  2904 			return new WP_Error( 'duplicate_term_slug', sprintf( __( 'The slug &#8220;%s&#8221; is already in use by another term.' ), $slug ) );
  2744 		}
  2905 		}
  2745 	}
  2906 	}
  2746 
  2907 
  2747 	$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) );
  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 ) );
  2748 
  2909 
  2749 	// Check whether this is a shared term that needs splitting.
  2910 	// Check whether this is a shared term that needs splitting.
  2750 	$_term_id = _split_shared_term( $term_id, $tt_id );
  2911 	$_term_id = _split_shared_term( $term_id, $tt_id );
  2751 	if ( ! is_wp_error( $_term_id ) ) {
  2912 	if ( ! is_wp_error( $_term_id ) ) {
  2752 		$term_id = $_term_id;
  2913 		$term_id = $_term_id;
  2775 	 * @param array  $args     Arguments passed to wp_update_term().
  2936 	 * @param array  $args     Arguments passed to wp_update_term().
  2776 	 */
  2937 	 */
  2777 	$data = apply_filters( 'wp_update_term_data', $data, $term_id, $taxonomy, $args );
  2938 	$data = apply_filters( 'wp_update_term_data', $data, $term_id, $taxonomy, $args );
  2778 
  2939 
  2779 	$wpdb->update( $wpdb->terms, $data, compact( 'term_id' ) );
  2940 	$wpdb->update( $wpdb->terms, $data, compact( 'term_id' ) );
  2780 	if ( empty($slug) ) {
  2941 	if ( empty( $slug ) ) {
  2781 		$slug = sanitize_title($name, $term_id);
  2942 		$slug = sanitize_title( $name, $term_id );
  2782 		$wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
  2943 		$wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
  2783 	}
  2944 	}
  2784 
  2945 
  2785 	/**
  2946 	/**
  2786 	 * Fires immediately after the given terms are edited.
  2947 	 * Fires immediately after the given terms are edited.
  2821 	 *
  2982 	 *
  2822 	 * @param int    $term_id  Term ID.
  2983 	 * @param int    $term_id  Term ID.
  2823 	 * @param int    $tt_id    Term taxonomy ID.
  2984 	 * @param int    $tt_id    Term taxonomy ID.
  2824 	 * @param string $taxonomy Taxonomy slug.
  2985 	 * @param string $taxonomy Taxonomy slug.
  2825 	 */
  2986 	 */
  2826 	do_action( "edit_term", $term_id, $tt_id, $taxonomy );
  2987 	do_action( 'edit_term', $term_id, $tt_id, $taxonomy );
  2827 
  2988 
  2828 	/**
  2989 	/**
  2829 	 * Fires after a term in a specific taxonomy has been updated, but before the term
  2990 	 * Fires after a term in a specific taxonomy has been updated, but before the term
  2830 	 * cache has been cleaned.
  2991 	 * cache has been cleaned.
  2831 	 *
  2992 	 *
  2839 	do_action( "edit_{$taxonomy}", $term_id, $tt_id );
  3000 	do_action( "edit_{$taxonomy}", $term_id, $tt_id );
  2840 
  3001 
  2841 	/** This filter is documented in wp-includes/taxonomy.php */
  3002 	/** This filter is documented in wp-includes/taxonomy.php */
  2842 	$term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
  3003 	$term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
  2843 
  3004 
  2844 	clean_term_cache($term_id, $taxonomy);
  3005 	clean_term_cache( $term_id, $taxonomy );
  2845 
  3006 
  2846 	/**
  3007 	/**
  2847 	 * Fires after a term has been updated, and the term cache has been cleaned.
  3008 	 * Fires after a term has been updated, and the term cache has been cleaned.
  2848 	 *
  3009 	 *
  2849 	 * @since 2.3.0
  3010 	 * @since 2.3.0
  2850 	 *
  3011 	 *
  2851 	 * @param int    $term_id  Term ID.
  3012 	 * @param int    $term_id  Term ID.
  2852 	 * @param int    $tt_id    Term taxonomy ID.
  3013 	 * @param int    $tt_id    Term taxonomy ID.
  2853 	 * @param string $taxonomy Taxonomy slug.
  3014 	 * @param string $taxonomy Taxonomy slug.
  2854 	 */
  3015 	 */
  2855 	do_action( "edited_term", $term_id, $tt_id, $taxonomy );
  3016 	do_action( 'edited_term', $term_id, $tt_id, $taxonomy );
  2856 
  3017 
  2857 	/**
  3018 	/**
  2858 	 * Fires after a term for a specific taxonomy has been updated, and the term
  3019 	 * Fires after a term for a specific taxonomy has been updated, and the term
  2859 	 * cache has been cleaned.
  3020 	 * cache has been cleaned.
  2860 	 *
  3021 	 *
  2865 	 * @param int $term_id Term ID.
  3026 	 * @param int $term_id Term ID.
  2866 	 * @param int $tt_id   Term taxonomy ID.
  3027 	 * @param int $tt_id   Term taxonomy ID.
  2867 	 */
  3028 	 */
  2868 	do_action( "edited_{$taxonomy}", $term_id, $tt_id );
  3029 	do_action( "edited_{$taxonomy}", $term_id, $tt_id );
  2869 
  3030 
  2870 	return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
  3031 	return array(
       
  3032 		'term_id'          => $term_id,
       
  3033 		'term_taxonomy_id' => $tt_id,
       
  3034 	);
  2871 }
  3035 }
  2872 
  3036 
  2873 /**
  3037 /**
  2874  * Enable or disable term counting.
  3038  * Enable or disable term counting.
  2875  *
  3039  *
  2878  * @staticvar bool $_defer
  3042  * @staticvar bool $_defer
  2879  *
  3043  *
  2880  * @param bool $defer Optional. Enable if true, disable if false.
  3044  * @param bool $defer Optional. Enable if true, disable if false.
  2881  * @return bool Whether term counting is enabled or disabled.
  3045  * @return bool Whether term counting is enabled or disabled.
  2882  */
  3046  */
  2883 function wp_defer_term_counting($defer=null) {
  3047 function wp_defer_term_counting( $defer = null ) {
  2884 	static $_defer = false;
  3048 	static $_defer = false;
  2885 
  3049 
  2886 	if ( is_bool($defer) ) {
  3050 	if ( is_bool( $defer ) ) {
  2887 		$_defer = $defer;
  3051 		$_defer = $defer;
  2888 		// flush any deferred counts
  3052 		// flush any deferred counts
  2889 		if ( !$defer )
  3053 		if ( ! $defer ) {
  2890 			wp_update_term_count( null, null, true );
  3054 			wp_update_term_count( null, null, true );
       
  3055 		}
  2891 	}
  3056 	}
  2892 
  3057 
  2893 	return $_defer;
  3058 	return $_defer;
  2894 }
  3059 }
  2895 
  3060 
  2913  */
  3078  */
  2914 function wp_update_term_count( $terms, $taxonomy, $do_deferred = false ) {
  3079 function wp_update_term_count( $terms, $taxonomy, $do_deferred = false ) {
  2915 	static $_deferred = array();
  3080 	static $_deferred = array();
  2916 
  3081 
  2917 	if ( $do_deferred ) {
  3082 	if ( $do_deferred ) {
  2918 		foreach ( (array) array_keys($_deferred) as $tax ) {
  3083 		foreach ( (array) array_keys( $_deferred ) as $tax ) {
  2919 			wp_update_term_count_now( $_deferred[$tax], $tax );
  3084 			wp_update_term_count_now( $_deferred[ $tax ], $tax );
  2920 			unset( $_deferred[$tax] );
  3085 			unset( $_deferred[ $tax ] );
  2921 		}
  3086 		}
  2922 	}
  3087 	}
  2923 
  3088 
  2924 	if ( empty($terms) )
  3089 	if ( empty( $terms ) ) {
  2925 		return false;
  3090 		return false;
  2926 
  3091 	}
  2927 	if ( !is_array($terms) )
  3092 
  2928 		$terms = array($terms);
  3093 	if ( ! is_array( $terms ) ) {
       
  3094 		$terms = array( $terms );
       
  3095 	}
  2929 
  3096 
  2930 	if ( wp_defer_term_counting() ) {
  3097 	if ( wp_defer_term_counting() ) {
  2931 		if ( !isset($_deferred[$taxonomy]) )
  3098 		if ( ! isset( $_deferred[ $taxonomy ] ) ) {
  2932 			$_deferred[$taxonomy] = array();
  3099 			$_deferred[ $taxonomy ] = array();
  2933 		$_deferred[$taxonomy] = array_unique( array_merge($_deferred[$taxonomy], $terms) );
  3100 		}
       
  3101 		$_deferred[ $taxonomy ] = array_unique( array_merge( $_deferred[ $taxonomy ], $terms ) );
  2934 		return true;
  3102 		return true;
  2935 	}
  3103 	}
  2936 
  3104 
  2937 	return wp_update_term_count_now( $terms, $taxonomy );
  3105 	return wp_update_term_count_now( $terms, $taxonomy );
  2938 }
  3106 }
  2945  * @param array  $terms    The term_taxonomy_id of terms to update.
  3113  * @param array  $terms    The term_taxonomy_id of terms to update.
  2946  * @param string $taxonomy The context of the term.
  3114  * @param string $taxonomy The context of the term.
  2947  * @return true Always true when complete.
  3115  * @return true Always true when complete.
  2948  */
  3116  */
  2949 function wp_update_term_count_now( $terms, $taxonomy ) {
  3117 function wp_update_term_count_now( $terms, $taxonomy ) {
  2950 	$terms = array_map('intval', $terms);
  3118 	$terms = array_map( 'intval', $terms );
  2951 
  3119 
  2952 	$taxonomy = get_taxonomy($taxonomy);
  3120 	$taxonomy = get_taxonomy( $taxonomy );
  2953 	if ( !empty($taxonomy->update_count_callback) ) {
  3121 	if ( ! empty( $taxonomy->update_count_callback ) ) {
  2954 		call_user_func($taxonomy->update_count_callback, $terms, $taxonomy);
  3122 		call_user_func( $taxonomy->update_count_callback, $terms, $taxonomy );
  2955 	} else {
  3123 	} else {
  2956 		$object_types = (array) $taxonomy->object_type;
  3124 		$object_types = (array) $taxonomy->object_type;
  2957 		foreach ( $object_types as &$object_type ) {
  3125 		foreach ( $object_types as &$object_type ) {
  2958 			if ( 0 === strpos( $object_type, 'attachment:' ) )
  3126 			if ( 0 === strpos( $object_type, 'attachment:' ) ) {
  2959 				list( $object_type ) = explode( ':', $object_type );
  3127 				list( $object_type ) = explode( ':', $object_type );
       
  3128 			}
  2960 		}
  3129 		}
  2961 
  3130 
  2962 		if ( $object_types == array_filter( $object_types, 'post_type_exists' ) ) {
  3131 		if ( $object_types == array_filter( $object_types, 'post_type_exists' ) ) {
  2963 			// Only post types are attached to this taxonomy
  3132 			// Only post types are attached to this taxonomy
  2964 			_update_post_term_count( $terms, $taxonomy );
  3133 			_update_post_term_count( $terms, $taxonomy );
  2966 			// Default count updater
  3135 			// Default count updater
  2967 			_update_generic_term_count( $terms, $taxonomy );
  3136 			_update_generic_term_count( $terms, $taxonomy );
  2968 		}
  3137 		}
  2969 	}
  3138 	}
  2970 
  3139 
  2971 	clean_term_cache($terms, '', false);
  3140 	clean_term_cache( $terms, '', false );
  2972 
  3141 
  2973 	return true;
  3142 	return true;
  2974 }
  3143 }
  2975 
  3144 
  2976 //
  3145 //
  2991  * @see get_object_taxonomies() for more on $object_type.
  3160  * @see get_object_taxonomies() for more on $object_type.
  2992  *
  3161  *
  2993  * @param int|array    $object_ids  Single or list of term object ID(s).
  3162  * @param int|array    $object_ids  Single or list of term object ID(s).
  2994  * @param array|string $object_type The taxonomy object type.
  3163  * @param array|string $object_type The taxonomy object type.
  2995  */
  3164  */
  2996 function clean_object_term_cache($object_ids, $object_type) {
  3165 function clean_object_term_cache( $object_ids, $object_type ) {
  2997 	global $_wp_suspend_cache_invalidation;
  3166 	global $_wp_suspend_cache_invalidation;
  2998 
  3167 
  2999 	if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
  3168 	if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
  3000 		return;
  3169 		return;
  3001 	}
  3170 	}
  3002 
  3171 
  3003 	if ( !is_array($object_ids) )
  3172 	if ( ! is_array( $object_ids ) ) {
  3004 		$object_ids = array($object_ids);
  3173 		$object_ids = array( $object_ids );
       
  3174 	}
  3005 
  3175 
  3006 	$taxonomies = get_object_taxonomies( $object_type );
  3176 	$taxonomies = get_object_taxonomies( $object_type );
  3007 
  3177 
  3008 	foreach ( $object_ids as $id ) {
  3178 	foreach ( $object_ids as $id ) {
  3009 		foreach ( $taxonomies as $taxonomy ) {
  3179 		foreach ( $taxonomies as $taxonomy ) {
  3010 			wp_cache_delete($id, "{$taxonomy}_relationships");
  3180 			wp_cache_delete( $id, "{$taxonomy}_relationships" );
  3011 		}
  3181 		}
  3012 	}
  3182 	}
  3013 
  3183 
  3014 	/**
  3184 	/**
  3015 	 * Fires after the object term cache has been cleaned.
  3185 	 * Fires after the object term cache has been cleaned.
  3034  * @param string    $taxonomy       Optional. Can be empty and will assume `tt_ids`, else will use for context.
  3204  * @param string    $taxonomy       Optional. Can be empty and will assume `tt_ids`, else will use for context.
  3035  *                                  Default empty.
  3205  *                                  Default empty.
  3036  * @param bool      $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual
  3206  * @param bool      $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual
  3037  *                                  term object caches (false). Default true.
  3207  *                                  term object caches (false). Default true.
  3038  */
  3208  */
  3039 function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) {
  3209 function clean_term_cache( $ids, $taxonomy = '', $clean_taxonomy = true ) {
  3040 	global $wpdb, $_wp_suspend_cache_invalidation;
  3210 	global $wpdb, $_wp_suspend_cache_invalidation;
  3041 
  3211 
  3042 	if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
  3212 	if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
  3043 		return;
  3213 		return;
  3044 	}
  3214 	}
  3045 
  3215 
  3046 	if ( !is_array($ids) )
  3216 	if ( ! is_array( $ids ) ) {
  3047 		$ids = array($ids);
  3217 		$ids = array( $ids );
       
  3218 	}
  3048 
  3219 
  3049 	$taxonomies = array();
  3220 	$taxonomies = array();
  3050 	// If no taxonomy, assume tt_ids.
  3221 	// If no taxonomy, assume tt_ids.
  3051 	if ( empty($taxonomy) ) {
  3222 	if ( empty( $taxonomy ) ) {
  3052 		$tt_ids = array_map('intval', $ids);
  3223 		$tt_ids = array_map( 'intval', $ids );
  3053 		$tt_ids = implode(', ', $tt_ids);
  3224 		$tt_ids = implode( ', ', $tt_ids );
  3054 		$terms = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)");
  3225 		$terms  = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)" );
  3055 		$ids = array();
  3226 		$ids    = array();
  3056 		foreach ( (array) $terms as $term ) {
  3227 		foreach ( (array) $terms as $term ) {
  3057 			$taxonomies[] = $term->taxonomy;
  3228 			$taxonomies[] = $term->taxonomy;
  3058 			$ids[] = $term->term_id;
  3229 			$ids[]        = $term->term_id;
  3059 			wp_cache_delete( $term->term_id, 'terms' );
  3230 			wp_cache_delete( $term->term_id, 'terms' );
  3060 		}
  3231 		}
  3061 		$taxonomies = array_unique($taxonomies);
  3232 		$taxonomies = array_unique( $taxonomies );
  3062 	} else {
  3233 	} else {
  3063 		$taxonomies = array($taxonomy);
  3234 		$taxonomies = array( $taxonomy );
  3064 		foreach ( $taxonomies as $taxonomy ) {
  3235 		foreach ( $taxonomies as $taxonomy ) {
  3065 			foreach ( $ids as $id ) {
  3236 			foreach ( $ids as $id ) {
  3066 				wp_cache_delete( $id, 'terms' );
  3237 				wp_cache_delete( $id, 'terms' );
  3067 			}
  3238 			}
  3068 		}
  3239 		}
  3120  * Upstream functions (like get_the_terms() and is_object_in_term()) are
  3291  * Upstream functions (like get_the_terms() and is_object_in_term()) are
  3121  * responsible for populating the object-term relationship cache. The current
  3292  * responsible for populating the object-term relationship cache. The current
  3122  * function only fetches relationship data that is already in the cache.
  3293  * function only fetches relationship data that is already in the cache.
  3123  *
  3294  *
  3124  * @since 2.3.0
  3295  * @since 2.3.0
  3125  * @since 4.7.0 Returns a WP_Error object if get_term() returns an error for
  3296  * @since 4.7.0 Returns a `WP_Error` object if `get_term()` returns an error for
  3126  *              any of the matched terms.
  3297  *              any of the matched terms.
  3127  *
  3298  *
  3128  * @param int    $id       Term object ID.
  3299  * @param int    $id       Term object ID.
  3129  * @param string $taxonomy Taxonomy name.
  3300  * @param string $taxonomy Taxonomy name.
  3130  * @return bool|array|WP_Error Array of `WP_Term` objects, if cached.
  3301  * @return bool|array|WP_Error Array of `WP_Term` objects, if cached.
  3179  *
  3350  *
  3180  * @param string|array $object_ids  Comma-separated list or array of term object IDs.
  3351  * @param string|array $object_ids  Comma-separated list or array of term object IDs.
  3181  * @param array|string $object_type The taxonomy object type.
  3352  * @param array|string $object_type The taxonomy object type.
  3182  * @return void|false False if all of the terms in `$object_ids` are already cached.
  3353  * @return void|false False if all of the terms in `$object_ids` are already cached.
  3183  */
  3354  */
  3184 function update_object_term_cache($object_ids, $object_type) {
  3355 function update_object_term_cache( $object_ids, $object_type ) {
  3185 	if ( empty($object_ids) )
  3356 	if ( empty( $object_ids ) ) {
  3186 		return;
  3357 		return;
  3187 
  3358 	}
  3188 	if ( !is_array($object_ids) )
  3359 
  3189 		$object_ids = explode(',', $object_ids);
  3360 	if ( ! is_array( $object_ids ) ) {
  3190 
  3361 		$object_ids = explode( ',', $object_ids );
  3191 	$object_ids = array_map('intval', $object_ids);
  3362 	}
  3192 
  3363 
  3193 	$taxonomies = get_object_taxonomies($object_type);
  3364 	$object_ids = array_map( 'intval', $object_ids );
       
  3365 
       
  3366 	$taxonomies = get_object_taxonomies( $object_type );
  3194 
  3367 
  3195 	$ids = array();
  3368 	$ids = array();
  3196 	foreach ( (array) $object_ids as $id ) {
  3369 	foreach ( (array) $object_ids as $id ) {
  3197 		foreach ( $taxonomies as $taxonomy ) {
  3370 		foreach ( $taxonomies as $taxonomy ) {
  3198 			if ( false === wp_cache_get($id, "{$taxonomy}_relationships") ) {
  3371 			if ( false === wp_cache_get( $id, "{$taxonomy}_relationships" ) ) {
  3199 				$ids[] = $id;
  3372 				$ids[] = $id;
  3200 				break;
  3373 				break;
  3201 			}
  3374 			}
  3202 		}
  3375 		}
  3203 	}
  3376 	}
  3204 
  3377 
  3205 	if ( empty( $ids ) )
  3378 	if ( empty( $ids ) ) {
  3206 		return false;
  3379 		return false;
  3207 
  3380 	}
  3208 	$terms = wp_get_object_terms( $ids, $taxonomies, array(
  3381 
  3209 		'fields' => 'all_with_object_id',
  3382 	$terms = wp_get_object_terms(
  3210 		'orderby' => 'name',
  3383 		$ids,
  3211 		'update_term_meta_cache' => false,
  3384 		$taxonomies,
  3212 	) );
  3385 		array(
       
  3386 			'fields'                 => 'all_with_object_id',
       
  3387 			'orderby'                => 'name',
       
  3388 			'update_term_meta_cache' => false,
       
  3389 		)
       
  3390 	);
  3213 
  3391 
  3214 	$object_terms = array();
  3392 	$object_terms = array();
  3215 	foreach ( (array) $terms as $term ) {
  3393 	foreach ( (array) $terms as $term ) {
  3216 		$object_terms[ $term->object_id ][ $term->taxonomy ][] = $term->term_id;
  3394 		$object_terms[ $term->object_id ][ $term->taxonomy ][] = $term->term_id;
  3217 	}
  3395 	}
  3218 
  3396 
  3219 	foreach ( $ids as $id ) {
  3397 	foreach ( $ids as $id ) {
  3220 		foreach ( $taxonomies as $taxonomy ) {
  3398 		foreach ( $taxonomies as $taxonomy ) {
  3221 			if ( ! isset($object_terms[$id][$taxonomy]) ) {
  3399 			if ( ! isset( $object_terms[ $id ][ $taxonomy ] ) ) {
  3222 				if ( !isset($object_terms[$id]) )
  3400 				if ( ! isset( $object_terms[ $id ] ) ) {
  3223 					$object_terms[$id] = array();
  3401 					$object_terms[ $id ] = array();
  3224 				$object_terms[$id][$taxonomy] = array();
  3402 				}
       
  3403 				$object_terms[ $id ][ $taxonomy ] = array();
  3225 			}
  3404 			}
  3226 		}
  3405 		}
  3227 	}
  3406 	}
  3228 
  3407 
  3229 	foreach ( $object_terms as $id => $value ) {
  3408 	foreach ( $object_terms as $id => $value ) {
  3258 //
  3437 //
  3259 
  3438 
  3260 /**
  3439 /**
  3261  * Retrieves children of taxonomy as Term IDs.
  3440  * Retrieves children of taxonomy as Term IDs.
  3262  *
  3441  *
  3263  * @ignore
  3442  * @access private
  3264  * @since 2.3.0
  3443  * @since 2.3.0
  3265  *
  3444  *
  3266  * @param string $taxonomy Taxonomy name.
  3445  * @param string $taxonomy Taxonomy name.
  3267  * @return array Empty if $taxonomy isn't hierarchical or returns children as Term IDs.
  3446  * @return array Empty if $taxonomy isn't hierarchical or returns children as Term IDs.
  3268  */
  3447  */
  3269 function _get_term_hierarchy( $taxonomy ) {
  3448 function _get_term_hierarchy( $taxonomy ) {
  3270 	if ( !is_taxonomy_hierarchical($taxonomy) )
  3449 	if ( ! is_taxonomy_hierarchical( $taxonomy ) ) {
  3271 		return array();
  3450 		return array();
  3272 	$children = get_option("{$taxonomy}_children");
  3451 	}
  3273 
  3452 	$children = get_option( "{$taxonomy}_children" );
  3274 	if ( is_array($children) )
  3453 
       
  3454 	if ( is_array( $children ) ) {
  3275 		return $children;
  3455 		return $children;
       
  3456 	}
  3276 	$children = array();
  3457 	$children = array();
  3277 	$terms = get_terms($taxonomy, array('get' => 'all', 'orderby' => 'id', 'fields' => 'id=>parent'));
  3458 	$terms    = get_terms(
       
  3459 		$taxonomy,
       
  3460 		array(
       
  3461 			'get'                    => 'all',
       
  3462 			'orderby'                => 'id',
       
  3463 			'fields'                 => 'id=>parent',
       
  3464 			'update_term_meta_cache' => false,
       
  3465 		)
       
  3466 	);
  3278 	foreach ( $terms as $term_id => $parent ) {
  3467 	foreach ( $terms as $term_id => $parent ) {
  3279 		if ( $parent > 0 )
  3468 		if ( $parent > 0 ) {
  3280 			$children[$parent][] = $term_id;
  3469 			$children[ $parent ][] = $term_id;
  3281 	}
  3470 		}
  3282 	update_option("{$taxonomy}_children", $children);
  3471 	}
       
  3472 	update_option( "{$taxonomy}_children", $children );
  3283 
  3473 
  3284 	return $children;
  3474 	return $children;
  3285 }
  3475 }
  3286 
  3476 
  3287 /**
  3477 /**
  3303  *                          with 1 as value. Default empty array.
  3493  *                          with 1 as value. Default empty array.
  3304  * @return array|WP_Error The subset of $terms that are descendants of $term_id.
  3494  * @return array|WP_Error The subset of $terms that are descendants of $term_id.
  3305  */
  3495  */
  3306 function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) {
  3496 function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) {
  3307 	$empty_array = array();
  3497 	$empty_array = array();
  3308 	if ( empty($terms) )
  3498 	if ( empty( $terms ) ) {
  3309 		return $empty_array;
  3499 		return $empty_array;
  3310 
  3500 	}
  3311 	$term_list = array();
  3501 
  3312 	$has_children = _get_term_hierarchy($taxonomy);
  3502 	$term_list    = array();
  3313 
  3503 	$has_children = _get_term_hierarchy( $taxonomy );
  3314 	if  ( ( 0 != $term_id ) && ! isset($has_children[$term_id]) )
  3504 
       
  3505 	if ( ( 0 != $term_id ) && ! isset( $has_children[ $term_id ] ) ) {
  3315 		return $empty_array;
  3506 		return $empty_array;
       
  3507 	}
  3316 
  3508 
  3317 	// Include the term itself in the ancestors array, so we can properly detect when a loop has occurred.
  3509 	// Include the term itself in the ancestors array, so we can properly detect when a loop has occurred.
  3318 	if ( empty( $ancestors ) ) {
  3510 	if ( empty( $ancestors ) ) {
  3319 		$ancestors[ $term_id ] = 1;
  3511 		$ancestors[ $term_id ] = 1;
  3320 	}
  3512 	}
  3321 
  3513 
  3322 	foreach ( (array) $terms as $term ) {
  3514 	foreach ( (array) $terms as $term ) {
  3323 		$use_id = false;
  3515 		$use_id = false;
  3324 		if ( !is_object($term) ) {
  3516 		if ( ! is_object( $term ) ) {
  3325 			$term = get_term($term, $taxonomy);
  3517 			$term = get_term( $term, $taxonomy );
  3326 			if ( is_wp_error( $term ) )
  3518 			if ( is_wp_error( $term ) ) {
  3327 				return $term;
  3519 				return $term;
       
  3520 			}
  3328 			$use_id = true;
  3521 			$use_id = true;
  3329 		}
  3522 		}
  3330 
  3523 
  3331 		// Don't recurse if we've already identified the term as a child - this indicates a loop.
  3524 		// Don't recurse if we've already identified the term as a child - this indicates a loop.
  3332 		if ( isset( $ancestors[ $term->term_id ] ) ) {
  3525 		if ( isset( $ancestors[ $term->term_id ] ) ) {
  3333 			continue;
  3526 			continue;
  3334 		}
  3527 		}
  3335 
  3528 
  3336 		if ( $term->parent == $term_id ) {
  3529 		if ( $term->parent == $term_id ) {
  3337 			if ( $use_id )
  3530 			if ( $use_id ) {
  3338 				$term_list[] = $term->term_id;
  3531 				$term_list[] = $term->term_id;
  3339 			else
  3532 			} else {
  3340 				$term_list[] = $term;
  3533 				$term_list[] = $term;
  3341 
  3534 			}
  3342 			if ( !isset($has_children[$term->term_id]) )
  3535 
       
  3536 			if ( ! isset( $has_children[ $term->term_id ] ) ) {
  3343 				continue;
  3537 				continue;
       
  3538 			}
  3344 
  3539 
  3345 			$ancestors[ $term->term_id ] = 1;
  3540 			$ancestors[ $term->term_id ] = 1;
  3346 
  3541 
  3347 			if ( $children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors) )
  3542 			if ( $children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors ) ) {
  3348 				$term_list = array_merge($term_list, $children);
  3543 				$term_list = array_merge( $term_list, $children );
       
  3544 			}
  3349 		}
  3545 		}
  3350 	}
  3546 	}
  3351 
  3547 
  3352 	return $term_list;
  3548 	return $term_list;
  3353 }
  3549 }
  3368  */
  3564  */
  3369 function _pad_term_counts( &$terms, $taxonomy ) {
  3565 function _pad_term_counts( &$terms, $taxonomy ) {
  3370 	global $wpdb;
  3566 	global $wpdb;
  3371 
  3567 
  3372 	// This function only works for hierarchical taxonomies like post categories.
  3568 	// This function only works for hierarchical taxonomies like post categories.
  3373 	if ( !is_taxonomy_hierarchical( $taxonomy ) )
  3569 	if ( ! is_taxonomy_hierarchical( $taxonomy ) ) {
  3374 		return;
  3570 		return;
  3375 
  3571 	}
  3376 	$term_hier = _get_term_hierarchy($taxonomy);
  3572 
  3377 
  3573 	$term_hier = _get_term_hierarchy( $taxonomy );
  3378 	if ( empty($term_hier) )
  3574 
       
  3575 	if ( empty( $term_hier ) ) {
  3379 		return;
  3576 		return;
  3380 
  3577 	}
  3381 	$term_items = array();
  3578 
       
  3579 	$term_items  = array();
  3382 	$terms_by_id = array();
  3580 	$terms_by_id = array();
  3383 	$term_ids = array();
  3581 	$term_ids    = array();
  3384 
  3582 
  3385 	foreach ( (array) $terms as $key => $term ) {
  3583 	foreach ( (array) $terms as $key => $term ) {
  3386 		$terms_by_id[$term->term_id] = & $terms[$key];
  3584 		$terms_by_id[ $term->term_id ]       = & $terms[ $key ];
  3387 		$term_ids[$term->term_taxonomy_id] = $term->term_id;
  3585 		$term_ids[ $term->term_taxonomy_id ] = $term->term_id;
  3388 	}
  3586 	}
  3389 
  3587 
  3390 	// Get the object and term ids and stick them in a lookup table.
  3588 	// Get the object and term ids and stick them in a lookup table.
  3391 	$tax_obj = get_taxonomy($taxonomy);
  3589 	$tax_obj      = get_taxonomy( $taxonomy );
  3392 	$object_types = esc_sql($tax_obj->object_type);
  3590 	$object_types = esc_sql( $tax_obj->object_type );
  3393 	$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'");
  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'" );
  3394 	foreach ( $results as $row ) {
  3592 	foreach ( $results as $row ) {
  3395 		$id = $term_ids[$row->term_taxonomy_id];
  3593 		$id                                   = $term_ids[ $row->term_taxonomy_id ];
  3396 		$term_items[$id][$row->object_id] = isset($term_items[$id][$row->object_id]) ? ++$term_items[$id][$row->object_id] : 1;
  3594 		$term_items[ $id ][ $row->object_id ] = isset( $term_items[ $id ][ $row->object_id ] ) ? ++$term_items[ $id ][ $row->object_id ] : 1;
  3397 	}
  3595 	}
  3398 
  3596 
  3399 	// Touch every ancestor's lookup row for each post in each term.
  3597 	// Touch every ancestor's lookup row for each post in each term.
  3400 	foreach ( $term_ids as $term_id ) {
  3598 	foreach ( $term_ids as $term_id ) {
  3401 		$child = $term_id;
  3599 		$child     = $term_id;
  3402 		$ancestors = array();
  3600 		$ancestors = array();
  3403 		while ( !empty( $terms_by_id[$child] ) && $parent = $terms_by_id[$child]->parent ) {
  3601 		while ( ! empty( $terms_by_id[ $child ] ) && $parent = $terms_by_id[ $child ]->parent ) {
  3404 			$ancestors[] = $child;
  3602 			$ancestors[] = $child;
  3405 			if ( !empty( $term_items[$term_id] ) )
  3603 			if ( ! empty( $term_items[ $term_id ] ) ) {
  3406 				foreach ( $term_items[$term_id] as $item_id => $touches ) {
  3604 				foreach ( $term_items[ $term_id ] as $item_id => $touches ) {
  3407 					$term_items[$parent][$item_id] = isset($term_items[$parent][$item_id]) ? ++$term_items[$parent][$item_id]: 1;
  3605 					$term_items[ $parent ][ $item_id ] = isset( $term_items[ $parent ][ $item_id ] ) ? ++$term_items[ $parent ][ $item_id ] : 1;
  3408 				}
  3606 				}
       
  3607 			}
  3409 			$child = $parent;
  3608 			$child = $parent;
  3410 
  3609 
  3411 			if ( in_array( $parent, $ancestors ) ) {
  3610 			if ( in_array( $parent, $ancestors ) ) {
  3412 				break;
  3611 				break;
  3413 			}
  3612 			}
  3414 		}
  3613 		}
  3415 	}
  3614 	}
  3416 
  3615 
  3417 	// Transfer the touched cells.
  3616 	// Transfer the touched cells.
  3418 	foreach ( (array) $term_items as $id => $items )
  3617 	foreach ( (array) $term_items as $id => $items ) {
  3419 		if ( isset($terms_by_id[$id]) )
  3618 		if ( isset( $terms_by_id[ $id ] ) ) {
  3420 			$terms_by_id[$id]->count = count($items);
  3619 			$terms_by_id[ $id ]->count = count( $items );
       
  3620 		}
       
  3621 	}
  3421 }
  3622 }
  3422 
  3623 
  3423 /**
  3624 /**
  3424  * Adds any terms from the given IDs to the cache that do not already exist in cache.
  3625  * Adds any terms from the given IDs to the cache that do not already exist in cache.
  3425  *
  3626  *
  3434 function _prime_term_caches( $term_ids, $update_meta_cache = true ) {
  3635 function _prime_term_caches( $term_ids, $update_meta_cache = true ) {
  3435 	global $wpdb;
  3636 	global $wpdb;
  3436 
  3637 
  3437 	$non_cached_ids = _get_non_cached_ids( $term_ids, 'terms' );
  3638 	$non_cached_ids = _get_non_cached_ids( $term_ids, 'terms' );
  3438 	if ( ! empty( $non_cached_ids ) ) {
  3639 	if ( ! empty( $non_cached_ids ) ) {
  3439 		$fresh_terms = $wpdb->get_results( sprintf( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE t.term_id IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) );
  3640 		$fresh_terms = $wpdb->get_results( sprintf( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE t.term_id IN (%s)", join( ',', array_map( 'intval', $non_cached_ids ) ) ) );
  3440 
  3641 
  3441 		update_term_cache( $fresh_terms, $update_meta_cache );
  3642 		update_term_cache( $fresh_terms, $update_meta_cache );
  3442 
  3643 
  3443 		if ( $update_meta_cache ) {
  3644 		if ( $update_meta_cache ) {
  3444 			update_termmeta_cache( $non_cached_ids );
  3645 			update_termmeta_cache( $non_cached_ids );
  3467 function _update_post_term_count( $terms, $taxonomy ) {
  3668 function _update_post_term_count( $terms, $taxonomy ) {
  3468 	global $wpdb;
  3669 	global $wpdb;
  3469 
  3670 
  3470 	$object_types = (array) $taxonomy->object_type;
  3671 	$object_types = (array) $taxonomy->object_type;
  3471 
  3672 
  3472 	foreach ( $object_types as &$object_type )
  3673 	foreach ( $object_types as &$object_type ) {
  3473 		list( $object_type ) = explode( ':', $object_type );
  3674 		list( $object_type ) = explode( ':', $object_type );
       
  3675 	}
  3474 
  3676 
  3475 	$object_types = array_unique( $object_types );
  3677 	$object_types = array_unique( $object_types );
  3476 
  3678 
  3477 	if ( false !== ( $check_attachments = array_search( 'attachment', $object_types ) ) ) {
  3679 	if ( false !== ( $check_attachments = array_search( 'attachment', $object_types ) ) ) {
  3478 		unset( $object_types[ $check_attachments ] );
  3680 		unset( $object_types[ $check_attachments ] );
  3479 		$check_attachments = true;
  3681 		$check_attachments = true;
  3480 	}
  3682 	}
  3481 
  3683 
  3482 	if ( $object_types )
  3684 	if ( $object_types ) {
  3483 		$object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) );
  3685 		$object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) );
       
  3686 	}
  3484 
  3687 
  3485 	foreach ( (array) $terms as $term ) {
  3688 	foreach ( (array) $terms as $term ) {
  3486 		$count = 0;
  3689 		$count = 0;
  3487 
  3690 
  3488 		// Attachments can be 'inherit' status, we need to base count off the parent's status if so.
  3691 		// Attachments can be 'inherit' status, we need to base count off the parent's status if so.
  3489 		if ( $check_attachments )
  3692 		if ( $check_attachments ) {
  3490 			$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 ) );
  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 ) );
  3491 
  3694 		}
  3492 		if ( $object_types )
  3695 
  3493 			$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 ) );
  3696 		if ( $object_types ) {
       
  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 ) );
       
  3698 		}
  3494 
  3699 
  3495 		/** This action is documented in wp-includes/taxonomy.php */
  3700 		/** This action is documented in wp-includes/taxonomy.php */
  3496 		do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
  3701 		do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
  3497 		$wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
  3702 		$wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
  3498 
  3703 
  3554 function _split_shared_term( $term_id, $term_taxonomy_id, $record = true ) {
  3759 function _split_shared_term( $term_id, $term_taxonomy_id, $record = true ) {
  3555 	global $wpdb;
  3760 	global $wpdb;
  3556 
  3761 
  3557 	if ( is_object( $term_id ) ) {
  3762 	if ( is_object( $term_id ) ) {
  3558 		$shared_term = $term_id;
  3763 		$shared_term = $term_id;
  3559 		$term_id = intval( $shared_term->term_id );
  3764 		$term_id     = intval( $shared_term->term_id );
  3560 	}
  3765 	}
  3561 
  3766 
  3562 	if ( is_object( $term_taxonomy_id ) ) {
  3767 	if ( is_object( $term_taxonomy_id ) ) {
  3563 		$term_taxonomy = $term_taxonomy_id;
  3768 		$term_taxonomy    = $term_taxonomy_id;
  3564 		$term_taxonomy_id = intval( $term_taxonomy->term_taxonomy_id );
  3769 		$term_taxonomy_id = intval( $term_taxonomy->term_taxonomy_id );
  3565 	}
  3770 	}
  3566 
  3771 
  3567 	// If there are no shared term_taxonomy rows, there's nothing to do here.
  3772 	// If there are no shared term_taxonomy rows, there's nothing to do here.
  3568 	$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 ) );
  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 ) );
  3584 	if ( empty( $shared_term ) ) {
  3789 	if ( empty( $shared_term ) ) {
  3585 		$shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->terms t WHERE t.term_id = %d", $term_id ) );
  3790 		$shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->terms t WHERE t.term_id = %d", $term_id ) );
  3586 	}
  3791 	}
  3587 
  3792 
  3588 	$new_term_data = array(
  3793 	$new_term_data = array(
  3589 		'name' => $shared_term->name,
  3794 		'name'       => $shared_term->name,
  3590 		'slug' => $shared_term->slug,
  3795 		'slug'       => $shared_term->slug,
  3591 		'term_group' => $shared_term->term_group,
  3796 		'term_group' => $shared_term->term_group,
  3592 	);
  3797 	);
  3593 
  3798 
  3594 	if ( false === $wpdb->insert( $wpdb->terms, $new_term_data ) ) {
  3799 	if ( false === $wpdb->insert( $wpdb->terms, $new_term_data ) ) {
  3595 		return new WP_Error( 'db_insert_error', __( 'Could not split shared term.' ), $wpdb->last_error );
  3800 		return new WP_Error( 'db_insert_error', __( 'Could not split shared term.' ), $wpdb->last_error );
  3596 	}
  3801 	}
  3597 
  3802 
  3598 	$new_term_id = (int) $wpdb->insert_id;
  3803 	$new_term_id = (int) $wpdb->insert_id;
  3599 
  3804 
  3600 	// Update the existing term_taxonomy to point to the newly created term.
  3805 	// Update the existing term_taxonomy to point to the newly created term.
  3601 	$wpdb->update( $wpdb->term_taxonomy,
  3806 	$wpdb->update(
       
  3807 		$wpdb->term_taxonomy,
  3602 		array( 'term_id' => $new_term_id ),
  3808 		array( 'term_id' => $new_term_id ),
  3603 		array( 'term_taxonomy_id' => $term_taxonomy_id )
  3809 		array( 'term_taxonomy_id' => $term_taxonomy_id )
  3604 	);
  3810 	);
  3605 
  3811 
  3606 	// Reassign child terms to the new parent.
  3812 	// Reassign child terms to the new parent.
  3609 	}
  3815 	}
  3610 
  3816 
  3611 	$children_tt_ids = $wpdb->get_col( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE parent = %d AND taxonomy = %s", $term_id, $term_taxonomy->taxonomy ) );
  3817 	$children_tt_ids = $wpdb->get_col( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE parent = %d AND taxonomy = %s", $term_id, $term_taxonomy->taxonomy ) );
  3612 	if ( ! empty( $children_tt_ids ) ) {
  3818 	if ( ! empty( $children_tt_ids ) ) {
  3613 		foreach ( $children_tt_ids as $child_tt_id ) {
  3819 		foreach ( $children_tt_ids as $child_tt_id ) {
  3614 			$wpdb->update( $wpdb->term_taxonomy,
  3820 			$wpdb->update(
       
  3821 				$wpdb->term_taxonomy,
  3615 				array( 'parent' => $new_term_id ),
  3822 				array( 'parent' => $new_term_id ),
  3616 				array( 'term_taxonomy_id' => $child_tt_id )
  3823 				array( 'term_taxonomy_id' => $child_tt_id )
  3617 			);
  3824 			);
  3618 			clean_term_cache( (int) $child_tt_id, '', false );
  3825 			clean_term_cache( (int) $child_tt_id, '', false );
  3619 		}
  3826 		}
  3630 	 */
  3837 	 */
  3631 	$taxonomies_to_clean = array( $term_taxonomy->taxonomy );
  3838 	$taxonomies_to_clean = array( $term_taxonomy->taxonomy );
  3632 
  3839 
  3633 	// Clean the cache for term taxonomies formerly shared with the current term.
  3840 	// Clean the cache for term taxonomies formerly shared with the current term.
  3634 	$shared_term_taxonomies = $wpdb->get_col( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) );
  3841 	$shared_term_taxonomies = $wpdb->get_col( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) );
  3635 	$taxonomies_to_clean = array_merge( $taxonomies_to_clean, $shared_term_taxonomies );
  3842 	$taxonomies_to_clean    = array_merge( $taxonomies_to_clean, $shared_term_taxonomies );
  3636 
  3843 
  3637 	foreach ( $taxonomies_to_clean as $taxonomy_to_clean ) {
  3844 	foreach ( $taxonomies_to_clean as $taxonomy_to_clean ) {
  3638 		clean_taxonomy_cache( $taxonomy_to_clean );
  3845 		clean_taxonomy_cache( $taxonomy_to_clean );
  3639 	}
  3846 	}
  3640 
  3847 
  3724 	wp_schedule_single_event( time() + ( 2 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
  3931 	wp_schedule_single_event( time() + ( 2 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
  3725 
  3932 
  3726 	// Rekey shared term array for faster lookups.
  3933 	// Rekey shared term array for faster lookups.
  3727 	$_shared_terms = array();
  3934 	$_shared_terms = array();
  3728 	foreach ( $shared_terms as $shared_term ) {
  3935 	foreach ( $shared_terms as $shared_term ) {
  3729 		$term_id = intval( $shared_term->term_id );
  3936 		$term_id                   = intval( $shared_term->term_id );
  3730 		$_shared_terms[ $term_id ] = $shared_term;
  3937 		$_shared_terms[ $term_id ] = $shared_term;
  3731 	}
  3938 	}
  3732 	$shared_terms = $_shared_terms;
  3939 	$shared_terms = $_shared_terms;
  3733 
  3940 
  3734 	// Get term taxonomy data for all shared terms.
  3941 	// Get term taxonomy data for all shared terms.
  3735 	$shared_term_ids = implode( ',', array_keys( $shared_terms ) );
  3942 	$shared_term_ids = implode( ',', array_keys( $shared_terms ) );
  3736 	$shared_tts = $wpdb->get_results( "SELECT * FROM {$wpdb->term_taxonomy} WHERE `term_id` IN ({$shared_term_ids})" );
  3943 	$shared_tts      = $wpdb->get_results( "SELECT * FROM {$wpdb->term_taxonomy} WHERE `term_id` IN ({$shared_term_ids})" );
  3737 
  3944 
  3738 	// Split term data recording is slow, so we do it just once, outside the loop.
  3945 	// Split term data recording is slow, so we do it just once, outside the loop.
  3739 	$split_term_data = get_option( '_split_terms', array() );
  3946 	$split_term_data    = get_option( '_split_terms', array() );
  3740 	$skipped_first_term = $taxonomies = array();
  3947 	$skipped_first_term = $taxonomies = array();
  3741 	foreach ( $shared_tts as $shared_tt ) {
  3948 	foreach ( $shared_tts as $shared_tt ) {
  3742 		$term_id = intval( $shared_tt->term_id );
  3949 		$term_id = intval( $shared_tt->term_id );
  3743 
  3950 
  3744 		// Don't split the first tt belonging to a given term_id.
  3951 		// Don't split the first tt belonging to a given term_id.
  3820  * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
  4027  * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
  3821  * @param string $taxonomy         Taxonomy for the split term.
  4028  * @param string $taxonomy         Taxonomy for the split term.
  3822  */
  4029  */
  3823 function _wp_check_split_terms_in_menus( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
  4030 function _wp_check_split_terms_in_menus( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
  3824 	global $wpdb;
  4031 	global $wpdb;
  3825 	$post_ids = $wpdb->get_col( $wpdb->prepare(
  4032 	$post_ids = $wpdb->get_col(
  3826 		"SELECT m1.post_id
  4033 		$wpdb->prepare(
       
  4034 			"SELECT m1.post_id
  3827 		FROM {$wpdb->postmeta} AS m1
  4035 		FROM {$wpdb->postmeta} AS m1
  3828 			INNER JOIN {$wpdb->postmeta} AS m2 ON ( m2.post_id = m1.post_id )
  4036 			INNER JOIN {$wpdb->postmeta} AS m2 ON ( m2.post_id = m1.post_id )
  3829 			INNER JOIN {$wpdb->postmeta} AS m3 ON ( m3.post_id = m1.post_id )
  4037 			INNER JOIN {$wpdb->postmeta} AS m3 ON ( m3.post_id = m1.post_id )
  3830 		WHERE ( m1.meta_key = '_menu_item_type' AND m1.meta_value = 'taxonomy' )
  4038 		WHERE ( m1.meta_key = '_menu_item_type' AND m1.meta_value = 'taxonomy' )
  3831 			AND ( m2.meta_key = '_menu_item_object' AND m2.meta_value = %s )
  4039 			AND ( m2.meta_key = '_menu_item_object' AND m2.meta_value = %s )
  3832 			AND ( m3.meta_key = '_menu_item_object_id' AND m3.meta_value = %d )",
  4040 			AND ( m3.meta_key = '_menu_item_object_id' AND m3.meta_value = %d )",
  3833 		$taxonomy,
  4041 			$taxonomy,
  3834 		$term_id
  4042 			$term_id
  3835 	) );
  4043 		)
       
  4044 	);
  3836 
  4045 
  3837 	if ( $post_ids ) {
  4046 	if ( $post_ids ) {
  3838 		foreach ( $post_ids as $post_id ) {
  4047 		foreach ( $post_ids as $post_id ) {
  3839 			update_post_meta( $post_id, '_menu_item_object_id', $new_term_id, $term_id );
  4048 			update_post_meta( $post_id, '_menu_item_object_id', $new_term_id, $term_id );
  3840 		}
  4049 		}
  3916  *
  4125  *
  3917  * @since 4.4.0
  4126  * @since 4.4.0
  3918  *
  4127  *
  3919  * @param int $term_id Term ID.
  4128  * @param int $term_id Term ID.
  3920  * @return bool Returns false if a term is not shared between multiple taxonomies or
  4129  * @return bool Returns false if a term is not shared between multiple taxonomies or
  3921  *              if splittng shared taxonomy terms is finished.
  4130  *              if splitting shared taxonomy terms is finished.
  3922  */
  4131  */
  3923 function wp_term_is_shared( $term_id ) {
  4132 function wp_term_is_shared( $term_id ) {
  3924 	global $wpdb;
  4133 	global $wpdb;
  3925 
  4134 
  3926 	if ( get_option( 'finished_splitting_shared_terms' ) ) {
  4135 	if ( get_option( 'finished_splitting_shared_terms' ) ) {
  3944  * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
  4153  * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
  3945  */
  4154  */
  3946 function get_term_link( $term, $taxonomy = '' ) {
  4155 function get_term_link( $term, $taxonomy = '' ) {
  3947 	global $wp_rewrite;
  4156 	global $wp_rewrite;
  3948 
  4157 
  3949 	if ( !is_object($term) ) {
  4158 	if ( ! is_object( $term ) ) {
  3950 		if ( is_int( $term ) ) {
  4159 		if ( is_int( $term ) ) {
  3951 			$term = get_term( $term, $taxonomy );
  4160 			$term = get_term( $term, $taxonomy );
  3952 		} else {
  4161 		} else {
  3953 			$term = get_term_by( 'slug', $term, $taxonomy );
  4162 			$term = get_term_by( 'slug', $term, $taxonomy );
  3954 		}
  4163 		}
  3955 	}
  4164 	}
  3956 
  4165 
  3957 	if ( !is_object($term) )
  4166 	if ( ! is_object( $term ) ) {
  3958 		$term = new WP_Error( 'invalid_term', __( 'Empty Term.' ) );
  4167 		$term = new WP_Error( 'invalid_term', __( 'Empty Term.' ) );
  3959 
  4168 	}
  3960 	if ( is_wp_error( $term ) )
  4169 
       
  4170 	if ( is_wp_error( $term ) ) {
  3961 		return $term;
  4171 		return $term;
       
  4172 	}
  3962 
  4173 
  3963 	$taxonomy = $term->taxonomy;
  4174 	$taxonomy = $term->taxonomy;
  3964 
  4175 
  3965 	$termlink = $wp_rewrite->get_extra_permastruct($taxonomy);
  4176 	$termlink = $wp_rewrite->get_extra_permastruct( $taxonomy );
  3966 
  4177 
  3967 	/**
  4178 	/**
  3968 	 * Filters the permalink structure for a terms before token replacement occurs.
  4179 	 * Filters the permalink structure for a terms before token replacement occurs.
  3969 	 *
  4180 	 *
  3970 	 * @since 4.9.0
  4181 	 * @since 4.9.0
  3973 	 * @param WP_Term $term     The term object.
  4184 	 * @param WP_Term $term     The term object.
  3974 	 */
  4185 	 */
  3975 	$termlink = apply_filters( 'pre_term_link', $termlink, $term );
  4186 	$termlink = apply_filters( 'pre_term_link', $termlink, $term );
  3976 
  4187 
  3977 	$slug = $term->slug;
  4188 	$slug = $term->slug;
  3978 	$t = get_taxonomy($taxonomy);
  4189 	$t    = get_taxonomy( $taxonomy );
  3979 
  4190 
  3980 	if ( empty($termlink) ) {
  4191 	if ( empty( $termlink ) ) {
  3981 		if ( 'category' == $taxonomy )
  4192 		if ( 'category' == $taxonomy ) {
  3982 			$termlink = '?cat=' . $term->term_id;
  4193 			$termlink = '?cat=' . $term->term_id;
  3983 		elseif ( $t->query_var )
  4194 		} elseif ( $t->query_var ) {
  3984 			$termlink = "?$t->query_var=$slug";
  4195 			$termlink = "?$t->query_var=$slug";
  3985 		else
  4196 		} else {
  3986 			$termlink = "?taxonomy=$taxonomy&term=$slug";
  4197 			$termlink = "?taxonomy=$taxonomy&term=$slug";
  3987 		$termlink = home_url($termlink);
  4198 		}
       
  4199 		$termlink = home_url( $termlink );
  3988 	} else {
  4200 	} else {
  3989 		if ( $t->rewrite['hierarchical'] ) {
  4201 		if ( $t->rewrite['hierarchical'] ) {
  3990 			$hierarchical_slugs = array();
  4202 			$hierarchical_slugs = array();
  3991 			$ancestors = get_ancestors( $term->term_id, $taxonomy, 'taxonomy' );
  4203 			$ancestors          = get_ancestors( $term->term_id, $taxonomy, 'taxonomy' );
  3992 			foreach ( (array)$ancestors as $ancestor ) {
  4204 			foreach ( (array) $ancestors as $ancestor ) {
  3993 				$ancestor_term = get_term($ancestor, $taxonomy);
  4205 				$ancestor_term        = get_term( $ancestor, $taxonomy );
  3994 				$hierarchical_slugs[] = $ancestor_term->slug;
  4206 				$hierarchical_slugs[] = $ancestor_term->slug;
  3995 			}
  4207 			}
  3996 			$hierarchical_slugs = array_reverse($hierarchical_slugs);
  4208 			$hierarchical_slugs   = array_reverse( $hierarchical_slugs );
  3997 			$hierarchical_slugs[] = $slug;
  4209 			$hierarchical_slugs[] = $slug;
  3998 			$termlink = str_replace("%$taxonomy%", implode('/', $hierarchical_slugs), $termlink);
  4210 			$termlink             = str_replace( "%$taxonomy%", implode( '/', $hierarchical_slugs ), $termlink );
  3999 		} else {
  4211 		} else {
  4000 			$termlink = str_replace("%$taxonomy%", $slug, $termlink);
  4212 			$termlink = str_replace( "%$taxonomy%", $slug, $termlink );
  4001 		}
  4213 		}
  4002 		$termlink = home_url( user_trailingslashit($termlink, 'category') );
  4214 		$termlink = home_url( user_trailingslashit( $termlink, 'category' ) );
  4003 	}
  4215 	}
  4004 	// Back Compat filters.
  4216 	// Back Compat filters.
  4005 	if ( 'post_tag' == $taxonomy ) {
  4217 	if ( 'post_tag' == $taxonomy ) {
  4006 
  4218 
  4007 		/**
  4219 		/**
  4059  *     @type  string      $after  Displays after the taxonomies. Default empty string.
  4271  *     @type  string      $after  Displays after the taxonomies. Default empty string.
  4060  * }
  4272  * }
  4061  */
  4273  */
  4062 function the_taxonomies( $args = array() ) {
  4274 function the_taxonomies( $args = array() ) {
  4063 	$defaults = array(
  4275 	$defaults = array(
  4064 		'post' => 0,
  4276 		'post'   => 0,
  4065 		'before' => '',
  4277 		'before' => '',
  4066 		'sep' => ' ',
  4278 		'sep'    => ' ',
  4067 		'after' => '',
  4279 		'after'  => '',
  4068 	);
  4280 	);
  4069 
  4281 
  4070 	$r = wp_parse_args( $args, $defaults );
  4282 	$r = wp_parse_args( $args, $defaults );
  4071 
  4283 
  4072 	echo $r['before'] . join( $r['sep'], get_the_taxonomies( $r['post'], $r ) ) . $r['after'];
  4284 	echo $r['before'] . join( $r['sep'], get_the_taxonomies( $r['post'], $r ) ) . $r['after'];
  4092  * @return array List of taxonomies.
  4304  * @return array List of taxonomies.
  4093  */
  4305  */
  4094 function get_the_taxonomies( $post = 0, $args = array() ) {
  4306 function get_the_taxonomies( $post = 0, $args = array() ) {
  4095 	$post = get_post( $post );
  4307 	$post = get_post( $post );
  4096 
  4308 
  4097 	$args = wp_parse_args( $args, array(
  4309 	$args = wp_parse_args(
  4098 		/* translators: %s: taxonomy label, %l: list of terms formatted as per $term_template */
  4310 		$args,
  4099 		'template' => __( '%s: %l.' ),
  4311 		array(
  4100 		'term_template' => '<a href="%1$s">%2$s</a>',
  4312 			/* translators: %s: taxonomy label, %l: list of terms formatted as per $term_template */
  4101 	) );
  4313 			'template'      => __( '%s: %l.' ),
       
  4314 			'term_template' => '<a href="%1$s">%2$s</a>',
       
  4315 		)
       
  4316 	);
  4102 
  4317 
  4103 	$taxonomies = array();
  4318 	$taxonomies = array();
  4104 
  4319 
  4105 	if ( ! $post ) {
  4320 	if ( ! $post ) {
  4106 		return $taxonomies;
  4321 		return $taxonomies;
  4129 
  4344 
  4130 		foreach ( $terms as $term ) {
  4345 		foreach ( $terms as $term ) {
  4131 			$links[] = wp_sprintf( $t['term_template'], esc_attr( get_term_link( $term ) ), $term->name );
  4346 			$links[] = wp_sprintf( $t['term_template'], esc_attr( get_term_link( $term ) ), $term->name );
  4132 		}
  4347 		}
  4133 		if ( $links ) {
  4348 		if ( $links ) {
  4134 			$taxonomies[$taxonomy] = wp_sprintf( $t['template'], $t['label'], $links, $terms );
  4349 			$taxonomies[ $taxonomy ] = wp_sprintf( $t['template'], $t['label'], $links, $terms );
  4135 		}
  4350 		}
  4136 	}
  4351 	}
  4137 	return $taxonomies;
  4352 	return $taxonomies;
  4138 }
  4353 }
  4139 
  4354 
  4146  * @return array An array of all taxonomy names for the given post.
  4361  * @return array An array of all taxonomy names for the given post.
  4147  */
  4362  */
  4148 function get_post_taxonomies( $post = 0 ) {
  4363 function get_post_taxonomies( $post = 0 ) {
  4149 	$post = get_post( $post );
  4364 	$post = get_post( $post );
  4150 
  4365 
  4151 	return get_object_taxonomies($post);
  4366 	return get_object_taxonomies( $post );
  4152 }
  4367 }
  4153 
  4368 
  4154 /**
  4369 /**
  4155  * Determine if the given object is associated with any of the given terms.
  4370  * Determine if the given object is associated with any of the given terms.
  4156  *
  4371  *
  4164  * @param string           $taxonomy  Single taxonomy name.
  4379  * @param string           $taxonomy  Single taxonomy name.
  4165  * @param int|string|array $terms     Optional. Term term_id, name, slug or array of said. Default null.
  4380  * @param int|string|array $terms     Optional. Term term_id, name, slug or array of said. Default null.
  4166  * @return bool|WP_Error WP_Error on input error.
  4381  * @return bool|WP_Error WP_Error on input error.
  4167  */
  4382  */
  4168 function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
  4383 function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
  4169 	if ( !$object_id = (int) $object_id )
  4384 	if ( ! $object_id = (int) $object_id ) {
  4170 		return new WP_Error( 'invalid_object', __( 'Invalid object ID.' ) );
  4385 		return new WP_Error( 'invalid_object', __( 'Invalid object ID.' ) );
       
  4386 	}
  4171 
  4387 
  4172 	$object_terms = get_object_term_cache( $object_id, $taxonomy );
  4388 	$object_terms = get_object_term_cache( $object_id, $taxonomy );
  4173 	if ( false === $object_terms ) {
  4389 	if ( false === $object_terms ) {
  4174 		$object_terms = wp_get_object_terms( $object_id, $taxonomy, array( 'update_term_meta_cache' => false ) );
  4390 		$object_terms = wp_get_object_terms( $object_id, $taxonomy, array( 'update_term_meta_cache' => false ) );
  4175 		if ( is_wp_error( $object_terms ) ) {
  4391 		if ( is_wp_error( $object_terms ) ) {
  4177 		}
  4393 		}
  4178 
  4394 
  4179 		wp_cache_set( $object_id, wp_list_pluck( $object_terms, 'term_id' ), "{$taxonomy}_relationships" );
  4395 		wp_cache_set( $object_id, wp_list_pluck( $object_terms, 'term_id' ), "{$taxonomy}_relationships" );
  4180 	}
  4396 	}
  4181 
  4397 
  4182 	if ( is_wp_error( $object_terms ) )
  4398 	if ( is_wp_error( $object_terms ) ) {
  4183 		return $object_terms;
  4399 		return $object_terms;
  4184 	if ( empty( $object_terms ) )
  4400 	}
       
  4401 	if ( empty( $object_terms ) ) {
  4185 		return false;
  4402 		return false;
  4186 	if ( empty( $terms ) )
  4403 	}
  4187 		return ( !empty( $object_terms ) );
  4404 	if ( empty( $terms ) ) {
       
  4405 		return ( ! empty( $object_terms ) );
       
  4406 	}
  4188 
  4407 
  4189 	$terms = (array) $terms;
  4408 	$terms = (array) $terms;
  4190 
  4409 
  4191 	if ( $ints = array_filter( $terms, 'is_int' ) )
  4410 	if ( $ints = array_filter( $terms, 'is_int' ) ) {
  4192 		$strs = array_diff( $terms, $ints );
  4411 		$strs = array_diff( $terms, $ints );
  4193 	else
  4412 	} else {
  4194 		$strs =& $terms;
  4413 		$strs =& $terms;
       
  4414 	}
  4195 
  4415 
  4196 	foreach ( $object_terms as $object_term ) {
  4416 	foreach ( $object_terms as $object_term ) {
  4197 		// If term is an int, check against term_ids only.
  4417 		// If term is an int, check against term_ids only.
  4198 		if ( $ints && in_array( $object_term->term_id, $ints ) ) {
  4418 		if ( $ints && in_array( $object_term->term_id, $ints ) ) {
  4199 			return true;
  4419 			return true;
  4204 			$numeric_strs = array_map( 'intval', array_filter( $strs, 'is_numeric' ) );
  4424 			$numeric_strs = array_map( 'intval', array_filter( $strs, 'is_numeric' ) );
  4205 			if ( in_array( $object_term->term_id, $numeric_strs, true ) ) {
  4425 			if ( in_array( $object_term->term_id, $numeric_strs, true ) ) {
  4206 				return true;
  4426 				return true;
  4207 			}
  4427 			}
  4208 
  4428 
  4209 			if ( in_array( $object_term->name, $strs ) ) return true;
  4429 			if ( in_array( $object_term->name, $strs ) ) {
  4210 			if ( in_array( $object_term->slug, $strs ) ) return true;
  4430 				return true;
       
  4431 			}
       
  4432 			if ( in_array( $object_term->slug, $strs ) ) {
       
  4433 				return true;
       
  4434 			}
  4211 		}
  4435 		}
  4212 	}
  4436 	}
  4213 
  4437 
  4214 	return false;
  4438 	return false;
  4215 }
  4439 }
  4262 			$resource_type = 'post_type';
  4486 			$resource_type = 'post_type';
  4263 		}
  4487 		}
  4264 	}
  4488 	}
  4265 
  4489 
  4266 	if ( 'taxonomy' === $resource_type ) {
  4490 	if ( 'taxonomy' === $resource_type ) {
  4267 		$term = get_term($object_id, $object_type);
  4491 		$term = get_term( $object_id, $object_type );
  4268 		while ( ! is_wp_error($term) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors ) ) {
  4492 		while ( ! is_wp_error( $term ) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors ) ) {
  4269 			$ancestors[] = (int) $term->parent;
  4493 			$ancestors[] = (int) $term->parent;
  4270 			$term = get_term($term->parent, $object_type);
  4494 			$term        = get_term( $term->parent, $object_type );
  4271 		}
  4495 		}
  4272 	} elseif ( 'post_type' === $resource_type ) {
  4496 	} elseif ( 'post_type' === $resource_type ) {
  4273 		$ancestors = get_post_ancestors($object_id);
  4497 		$ancestors = get_post_ancestors( $object_id );
  4274 	}
  4498 	}
  4275 
  4499 
  4276 	/**
  4500 	/**
  4277 	 * Filters a given object's ancestors.
  4501 	 * Filters a given object's ancestors.
  4278 	 *
  4502 	 *
  4318  *
  4542  *
  4319  * @return int The new parent for the term.
  4543  * @return int The new parent for the term.
  4320  */
  4544  */
  4321 function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) {
  4545 function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) {
  4322 	// Nothing fancy here - bail
  4546 	// Nothing fancy here - bail
  4323 	if ( !$parent )
  4547 	if ( ! $parent ) {
  4324 		return 0;
  4548 		return 0;
       
  4549 	}
  4325 
  4550 
  4326 	// Can't be its own parent.
  4551 	// Can't be its own parent.
  4327 	if ( $parent == $term_id )
  4552 	if ( $parent == $term_id ) {
  4328 		return 0;
  4553 		return 0;
       
  4554 	}
  4329 
  4555 
  4330 	// Now look for larger loops.
  4556 	// Now look for larger loops.
  4331 	if ( !$loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ) )
  4557 	if ( ! $loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ) ) {
  4332 		return $parent; // No loop
  4558 		return $parent; // No loop
       
  4559 	}
  4333 
  4560 
  4334 	// Setting $parent to the given value causes a loop.
  4561 	// Setting $parent to the given value causes a loop.
  4335 	if ( isset( $loop[$term_id] ) )
  4562 	if ( isset( $loop[ $term_id ] ) ) {
  4336 		return 0;
  4563 		return 0;
       
  4564 	}
  4337 
  4565 
  4338 	// There's a loop, but it doesn't contain $term_id. Break the loop.
  4566 	// There's a loop, but it doesn't contain $term_id. Break the loop.
  4339 	foreach ( array_keys( $loop ) as $loop_member )
  4567 	foreach ( array_keys( $loop ) as $loop_member ) {
  4340 		wp_update_term( $loop_member, $taxonomy, array( 'parent' => 0 ) );
  4568 		wp_update_term( $loop_member, $taxonomy, array( 'parent' => 0 ) );
       
  4569 	}
  4341 
  4570 
  4342 	return $parent;
  4571 	return $parent;
  4343 }
  4572 }
       
  4573 
       
  4574 /**
       
  4575  * Determines whether a taxonomy is considered "viewable".
       
  4576  *
       
  4577  * @since 5.1.0
       
  4578  *
       
  4579  * @param string|WP_Taxonomy $taxonomy Taxonomy name or object.
       
  4580  * @return bool Whether the taxonomy should be considered viewable.
       
  4581  */
       
  4582 function is_taxonomy_viewable( $taxonomy ) {
       
  4583 	if ( is_scalar( $taxonomy ) ) {
       
  4584 		$taxonomy = get_taxonomy( $taxonomy );
       
  4585 		if ( ! $taxonomy ) {
       
  4586 			return false;
       
  4587 		}
       
  4588 	}
       
  4589 
       
  4590 	return $taxonomy->publicly_queryable;
       
  4591 }
       
  4592 
       
  4593 /**
       
  4594  * Sets the last changed time for the 'terms' cache group.
       
  4595  *
       
  4596  * @since 5.0.0
       
  4597  */
       
  4598 function wp_cache_set_terms_last_changed() {
       
  4599 	wp_cache_set( 'last_changed', microtime(), 'terms' );
       
  4600 }
       
  4601 
       
  4602 /**
       
  4603  * Aborts calls to term meta if it is not supported.
       
  4604  *
       
  4605  * @since 5.0.0
       
  4606  *
       
  4607  * @param mixed $check Skip-value for whether to proceed term meta function execution.
       
  4608  * @return mixed Original value of $check, or false if term meta is not supported.
       
  4609  */
       
  4610 function wp_check_term_meta_support_prefilter( $check ) {
       
  4611 	if ( get_option( 'db_version' ) < 34370 ) {
       
  4612 		return false;
       
  4613 	}
       
  4614 
       
  4615 	return $check;
       
  4616 }