wp/wp-includes/taxonomy.php
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
4:346c88efed21 5:5e2f62d02dcd
    22 	global $wp_rewrite;
    22 	global $wp_rewrite;
    23 
    23 
    24 	if ( ! did_action( 'init' ) ) {
    24 	if ( ! did_action( 'init' ) ) {
    25 		$rewrite = array( 'category' => false, 'post_tag' => false, 'post_format' => false );
    25 		$rewrite = array( 'category' => false, 'post_tag' => false, 'post_format' => false );
    26 	} else {
    26 	} else {
       
    27 
       
    28 		/**
       
    29 		 * Filter the post formats rewrite base.
       
    30 		 *
       
    31 		 * @since 3.1.0
       
    32 		 *
       
    33 		 * @param string $context Context of the rewrite base. Default 'type'.
       
    34 		 */
    27 		$post_format_base = apply_filters( 'post_format_rewrite_base', 'type' );
    35 		$post_format_base = apply_filters( 'post_format_rewrite_base', 'type' );
    28 		$rewrite = array(
    36 		$rewrite = array(
    29 			'category' => array(
    37 			'category' => array(
    30 				'hierarchical' => true,
    38 				'hierarchical' => true,
    31 				'slug' => get_option('category_base') ? get_option('category_base') : 'category',
    39 				'slug' => get_option('category_base') ? get_option('category_base') : 'category',
    32 				'with_front' => ! get_option('category_base') || $wp_rewrite->using_index_permalinks(),
    40 				'with_front' => ! get_option('category_base') || $wp_rewrite->using_index_permalinks(),
    33 				'ep_mask' => EP_CATEGORIES,
    41 				'ep_mask' => EP_CATEGORIES,
    34 			),
    42 			),
    35 			'post_tag' => array(
    43 			'post_tag' => array(
       
    44 				'hierarchical' => false,
    36 				'slug' => get_option('tag_base') ? get_option('tag_base') : 'tag',
    45 				'slug' => get_option('tag_base') ? get_option('tag_base') : 'tag',
    37 				'with_front' => ! get_option('tag_base') || $wp_rewrite->using_index_permalinks(),
    46 				'with_front' => ! get_option('tag_base') || $wp_rewrite->using_index_permalinks(),
    38 				'ep_mask' => EP_TAGS,
    47 				'ep_mask' => EP_TAGS,
    39 			),
    48 			),
    40 			'post_format' => $post_format_base ? array( 'slug' => $post_format_base ) : false,
    49 			'post_format' => $post_format_base ? array( 'slug' => $post_format_base ) : false,
   116 		'show_ui' => false,
   125 		'show_ui' => false,
   117 		'_builtin' => true,
   126 		'_builtin' => true,
   118 		'show_in_nav_menus' => current_theme_supports( 'post-formats' ),
   127 		'show_in_nav_menus' => current_theme_supports( 'post-formats' ),
   119 	) );
   128 	) );
   120 }
   129 }
   121 add_action( 'init', 'create_initial_taxonomies', 0 ); // highest priority
       
   122 
   130 
   123 /**
   131 /**
   124  * Get a list of registered taxonomy objects.
   132  * Get a list of registered taxonomy objects.
   125  *
   133  *
   126  * @package WordPress
       
   127  * @subpackage Taxonomy
       
   128  * @since 3.0.0
   134  * @since 3.0.0
   129  * @uses $wp_taxonomies
   135  * @uses $wp_taxonomies
   130  * @see register_taxonomy
       
   131  *
   136  *
   132  * @param array $args An array of key => value arguments to match against the taxonomy objects.
   137  * @param array $args An array of key => value arguments to match against the taxonomy objects.
   133  * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
   138  * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
   134  * @param string $operator The logical operation to perform. 'or' means only one element
   139  * @param string $operator The logical operation to perform. 'or' means only one element
   135  *  from the array needs to match; 'and' means all elements must match. The default is 'and'.
   140  *  from the array needs to match; 'and' means all elements must match. The default is 'and'.
   147  * Return all of the taxonomy names that are of $object_type.
   152  * Return all of the taxonomy names that are of $object_type.
   148  *
   153  *
   149  * It appears that this function can be used to find all of the names inside of
   154  * It appears that this function can be used to find all of the names inside of
   150  * $wp_taxonomies global variable.
   155  * $wp_taxonomies global variable.
   151  *
   156  *
   152  * <code><?php $taxonomies = get_object_taxonomies('post'); ?></code> Should
   157  * `<?php $taxonomies = get_object_taxonomies('post'); ?>` Should
   153  * result in <code>Array('category', 'post_tag')</code>
   158  * result in `Array( 'category', 'post_tag' )`
   154  *
   159  *
   155  * @package WordPress
       
   156  * @subpackage Taxonomy
       
   157  * @since 2.3.0
   160  * @since 2.3.0
   158  *
   161  *
   159  * @uses $wp_taxonomies
   162  * @uses $wp_taxonomies
   160  *
   163  *
   161  * @param array|string|object $object Name of the type of taxonomy object, or an object (row from posts)
   164  * @param array|string|object $object Name of the type of taxonomy object, or an object (row from posts)
   190  * Retrieves the taxonomy object of $taxonomy.
   193  * Retrieves the taxonomy object of $taxonomy.
   191  *
   194  *
   192  * The get_taxonomy function will first check that the parameter string given
   195  * The get_taxonomy function will first check that the parameter string given
   193  * is a taxonomy object and if it is, it will return it.
   196  * is a taxonomy object and if it is, it will return it.
   194  *
   197  *
   195  * @package WordPress
       
   196  * @subpackage Taxonomy
       
   197  * @since 2.3.0
   198  * @since 2.3.0
   198  *
   199  *
   199  * @uses $wp_taxonomies
   200  * @uses $wp_taxonomies
   200  * @uses taxonomy_exists() Checks whether taxonomy exists
       
   201  *
   201  *
   202  * @param string $taxonomy Name of taxonomy object to return
   202  * @param string $taxonomy Name of taxonomy object to return
   203  * @return object|bool The Taxonomy Object or false if $taxonomy doesn't exist
   203  * @return object|bool The Taxonomy Object or false if $taxonomy doesn't exist
   204  */
   204  */
   205 function get_taxonomy( $taxonomy ) {
   205 function get_taxonomy( $taxonomy ) {
   214 /**
   214 /**
   215  * Checks that the taxonomy name exists.
   215  * Checks that the taxonomy name exists.
   216  *
   216  *
   217  * Formerly is_taxonomy(), introduced in 2.3.0.
   217  * Formerly is_taxonomy(), introduced in 2.3.0.
   218  *
   218  *
   219  * @package WordPress
       
   220  * @subpackage Taxonomy
       
   221  * @since 3.0.0
   219  * @since 3.0.0
   222  *
   220  *
   223  * @uses $wp_taxonomies
   221  * @uses $wp_taxonomies
   224  *
   222  *
   225  * @param string $taxonomy Name of taxonomy object
   223  * @param string $taxonomy Name of taxonomy object
   237  * Checks to make sure that the taxonomy is an object first. Then Gets the
   235  * Checks to make sure that the taxonomy is an object first. Then Gets the
   238  * object, and finally returns the hierarchical value in the object.
   236  * object, and finally returns the hierarchical value in the object.
   239  *
   237  *
   240  * A false return value might also mean that the taxonomy does not exist.
   238  * A false return value might also mean that the taxonomy does not exist.
   241  *
   239  *
   242  * @package WordPress
       
   243  * @subpackage Taxonomy
       
   244  * @since 2.3.0
   240  * @since 2.3.0
   245  *
       
   246  * @uses taxonomy_exists() Checks whether taxonomy exists
       
   247  * @uses get_taxonomy() Used to get the taxonomy object
       
   248  *
   241  *
   249  * @param string $taxonomy Name of taxonomy object
   242  * @param string $taxonomy Name of taxonomy object
   250  * @return bool Whether the taxonomy is hierarchical
   243  * @return bool Whether the taxonomy is hierarchical
   251  */
   244  */
   252 function is_taxonomy_hierarchical($taxonomy) {
   245 function is_taxonomy_hierarchical($taxonomy) {
   276  *     * You can see accepted values in {@link get_taxonomy_labels()}.
   269  *     * You can see accepted values in {@link get_taxonomy_labels()}.
   277  * - description - A short descriptive summary of what the taxonomy is for. Defaults to blank.
   270  * - description - A short descriptive summary of what the taxonomy is for. Defaults to blank.
   278  * - public - If the taxonomy should be publicly queryable; //@TODO not implemented.
   271  * - public - If the taxonomy should be publicly queryable; //@TODO not implemented.
   279  *     * Defaults to true.
   272  *     * Defaults to true.
   280  * - hierarchical - Whether the taxonomy is hierarchical (e.g. category). Defaults to false.
   273  * - hierarchical - Whether the taxonomy is hierarchical (e.g. category). Defaults to false.
   281  * - show_ui -Whether to generate a default UI for managing this taxonomy in the admin.
   274  * - show_ui - Whether to generate a default UI for managing this taxonomy in the admin.
   282  *     * If not set, the default is inherited from public.
   275  *     * If not set, the default is inherited from public.
   283  * - show_in_menu - Where to show the taxonomy in the admin menu.
   276  * - show_in_menu - Whether to show the taxonomy in the admin menu.
   284  *     * If true, the taxonomy is shown as a submenu of the object type menu.
   277  *     * If true, the taxonomy is shown as a submenu of the object type menu.
   285  *     * If false, no menu is shown.
   278  *     * If false, no menu is shown.
   286  *     * show_ui must be true.
   279  *     * show_ui must be true.
   287  *     * If not set, the default is inherited from show_ui.
   280  *     * If not set, the default is inherited from show_ui.
   288  * - show_in_nav_menus - Makes this taxonomy available for selection in navigation menus.
   281  * - show_in_nav_menus - Makes this taxonomy available for selection in navigation menus.
   289  *     * If not set, the default is inherited from public.
   282  *     * If not set, the default is inherited from public.
   290  * - show_tagcloud - Whether to list the taxonomy in the Tag Cloud Widget.
   283  * - show_tagcloud - Whether to list the taxonomy in the Tag Cloud Widget.
   291  *     * If not set, the default is inherited from show_ui.
   284  *     * If not set, the default is inherited from show_ui.
   292  * - meta_box_cb - Provide a callback function for the meta box display. Defaults to
   285  * - show_in_quick_edit - Whether to show the taxonomy in the quick/bulk edit panel.
   293  *     post_categories_meta_box for hierarchical taxonomies and post_tags_meta_box for non-hierarchical.
   286  *     * It not set, the default is inherited from show_ui.
       
   287  * - show_admin_column - Whether to display a column for the taxonomy on its post type listing screens.
       
   288  *     * Defaults to false.
       
   289  * - meta_box_cb - Provide a callback function for the meta box display.
       
   290  *     * If not set, defaults to post_categories_meta_box for hierarchical taxonomies
       
   291  *     and post_tags_meta_box for non-hierarchical.
       
   292  *     * If false, no meta box is shown.
   294  * - capabilities - Array of capabilities for this taxonomy.
   293  * - capabilities - Array of capabilities for this taxonomy.
   295  *     * You can see accepted values in this function.
   294  *     * You can see accepted values in this function.
   296  * - rewrite - Triggers the handling of rewrites for this taxonomy. Defaults to true, using $taxonomy as slug.
   295  * - rewrite - Triggers the handling of rewrites for this taxonomy. Defaults to true, using $taxonomy as slug.
   297  *     * To prevent rewrite, set to false.
   296  *     * To prevent rewrite, set to false.
   298  *     * To specify rewrite rules, an array can be passed with any of these keys
   297  *     * To specify rewrite rules, an array can be passed with any of these keys
   309  *       that the objects are published before counting them.
   308  *       that the objects are published before counting them.
   310  *     * Defaults to _update_generic_term_count() for taxonomies attached to other object types, such as links.
   309  *     * Defaults to _update_generic_term_count() for taxonomies attached to other object types, such as links.
   311  * - _builtin - true if this taxonomy is a native or "built-in" taxonomy. THIS IS FOR INTERNAL USE ONLY!
   310  * - _builtin - true if this taxonomy is a native or "built-in" taxonomy. THIS IS FOR INTERNAL USE ONLY!
   312  *
   311  *
   313  * @since 2.3.0
   312  * @since 2.3.0
   314  * @uses $wp_taxonomies Inserts new taxonomy object into the list
   313  * @since 4.2.0 Introduced `show_in_quick_edit` argument.
   315  * @uses $wp Adds query vars
   314  *
       
   315  * @global array $wp_taxonomies Registered taxonomies.
       
   316  * @global WP    $wp            WP instance.
   316  *
   317  *
   317  * @param string $taxonomy Taxonomy key, must not exceed 32 characters.
   318  * @param string $taxonomy Taxonomy key, must not exceed 32 characters.
   318  * @param array|string $object_type Name of the object type for the taxonomy object.
   319  * @param array|string $object_type Name of the object type for the taxonomy object.
   319  * @param array|string $args See optional args description above.
   320  * @param array|string $args See optional args description above.
   320  * @return null|WP_Error WP_Error if errors, otherwise null.
   321  * @return null|WP_Error WP_Error if errors, otherwise null.
   332 		'hierarchical'          => false,
   333 		'hierarchical'          => false,
   333 		'show_ui'               => null,
   334 		'show_ui'               => null,
   334 		'show_in_menu'          => null,
   335 		'show_in_menu'          => null,
   335 		'show_in_nav_menus'     => null,
   336 		'show_in_nav_menus'     => null,
   336 		'show_tagcloud'         => null,
   337 		'show_tagcloud'         => null,
       
   338 		'show_in_quick_edit'	=> null,
       
   339 		'show_admin_column'     => false,
   337 		'meta_box_cb'           => null,
   340 		'meta_box_cb'           => null,
   338 		'capabilities'          => array(),
   341 		'capabilities'          => array(),
   339 		'rewrite'               => true,
   342 		'rewrite'               => true,
   340 		'query_var'             => $taxonomy,
   343 		'query_var'             => $taxonomy,
   341 		'update_count_callback' => '',
   344 		'update_count_callback' => '',
   342 		'_builtin'              => false,
   345 		'_builtin'              => false,
   343 	);
   346 	);
   344 	$args = wp_parse_args( $args, $defaults );
   347 	$args = wp_parse_args( $args, $defaults );
   345 
   348 
   346 	if ( strlen( $taxonomy ) > 32 )
   349 	if ( empty( $taxonomy ) || strlen( $taxonomy ) > 32 ) {
   347 		return new WP_Error( 'taxonomy_too_long', __( 'Taxonomies cannot exceed 32 characters in length' ) );
   350 		_doing_it_wrong( __FUNCTION__, __( 'Taxonomy names must be between 1 and 32 characters in length.' ), '4.2' );
       
   351 		return new WP_Error( 'taxonomy_length_invalid', __( 'Taxonomy names must be between 1 and 32 characters in length.' ) );
       
   352 	}
   348 
   353 
   349 	if ( false !== $args['query_var'] && ! empty( $wp ) ) {
   354 	if ( false !== $args['query_var'] && ! empty( $wp ) ) {
   350 		if ( true === $args['query_var'] )
   355 		if ( true === $args['query_var'] )
   351 			$args['query_var'] = $taxonomy;
   356 			$args['query_var'] = $taxonomy;
   352 		else
   357 		else
   386 		$args['show_in_nav_menus'] = $args['public'];
   391 		$args['show_in_nav_menus'] = $args['public'];
   387 
   392 
   388 	// If not set, default to the setting for show_ui.
   393 	// If not set, default to the setting for show_ui.
   389 	if ( null === $args['show_tagcloud'] )
   394 	if ( null === $args['show_tagcloud'] )
   390 		$args['show_tagcloud'] = $args['show_ui'];
   395 		$args['show_tagcloud'] = $args['show_ui'];
       
   396 
       
   397 	// If not set, default to the setting for show_ui.
       
   398 	if ( null === $args['show_in_quick_edit'] ) {
       
   399 		$args['show_in_quick_edit'] = $args['show_ui'];
       
   400 	}
   391 
   401 
   392 	$default_caps = array(
   402 	$default_caps = array(
   393 		'manage_terms' => 'manage_categories',
   403 		'manage_terms' => 'manage_categories',
   394 		'edit_terms'   => 'manage_categories',
   404 		'edit_terms'   => 'manage_categories',
   395 		'delete_terms' => 'manage_categories',
   405 		'delete_terms' => 'manage_categories',
   415 	$wp_taxonomies[ $taxonomy ] = (object) $args;
   425 	$wp_taxonomies[ $taxonomy ] = (object) $args;
   416 
   426 
   417 	// register callback handling for metabox
   427 	// register callback handling for metabox
   418  	add_filter( 'wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term' );
   428  	add_filter( 'wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term' );
   419 
   429 
       
   430 	/**
       
   431 	 * Fires after a taxonomy is registered.
       
   432 	 *
       
   433 	 * @since 3.3.0
       
   434 	 *
       
   435 	 * @param string       $taxonomy    Taxonomy slug.
       
   436 	 * @param array|string $object_type Object type or array of object types.
       
   437 	 * @param array        $args        Array of taxonomy registration arguments.
       
   438 	 */
   420 	do_action( 'registered_taxonomy', $taxonomy, $object_type, $args );
   439 	do_action( 'registered_taxonomy', $taxonomy, $object_type, $args );
   421 }
   440 }
   422 
   441 
   423 /**
   442 /**
   424  * Builds an object with all taxonomy labels out of a taxonomy object
   443  * Builds an object with all taxonomy labels out of a taxonomy object
   425  *
   444  *
   426  * Accepted keys of the label array in the taxonomy object:
   445  * Accepted keys of the label array in the taxonomy object:
       
   446  *
   427  * - name - general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is Tags/Categories
   447  * - name - general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is Tags/Categories
   428  * - singular_name - name for one object of this taxonomy. Default is Tag/Category
   448  * - singular_name - name for one object of this taxonomy. Default is Tag/Category
   429  * - search_items - Default is Search Tags/Search Categories
   449  * - search_items - Default is Search Tags/Search Categories
   430  * - popular_items - This string isn't used on hierarchical taxonomies. Default is Popular Tags
   450  * - popular_items - This string isn't used on hierarchical taxonomies. Default is Popular Tags
   431  * - all_items - Default is All Tags/All Categories
   451  * - all_items - Default is All Tags/All Categories
   432  * - parent_item - This string isn't used on non-hierarchical taxonomies. In hierarchical ones the default is Parent Category
   452  * - parent_item - This string isn't used on non-hierarchical taxonomies. In hierarchical ones the default is Parent Category
   433  * - parent_item_colon - The same as <code>parent_item</code>, but with colon <code>:</code> in the end
   453  * - parent_item_colon - The same as `parent_item`, but with colon `:` in the end
   434  * - edit_item - Default is Edit Tag/Edit Category
   454  * - edit_item - Default is Edit Tag/Edit Category
   435  * - view_item - Default is View Tag/View Category
   455  * - view_item - Default is View Tag/View Category
   436  * - update_item - Default is Update Tag/Update Category
   456  * - update_item - Default is Update Tag/Update Category
   437  * - add_new_item - Default is Add New Tag/Add New Category
   457  * - add_new_item - Default is Add New Tag/Add New Category
   438  * - new_item_name - Default is New Tag Name/New Category Name
   458  * - new_item_name - Default is New Tag Name/New Category Name
   439  * - separate_items_with_commas - This string isn't used on hierarchical taxonomies. Default is "Separate tags with commas", used in the meta box.
   459  * - separate_items_with_commas - This string isn't used on hierarchical taxonomies. Default is "Separate tags with commas", used in the meta box.
   440  * - add_or_remove_items - This string isn't used on hierarchical taxonomies. Default is "Add or remove tags", used in the meta box when JavaScript is disabled.
   460  * - add_or_remove_items - This string isn't used on hierarchical taxonomies. Default is "Add or remove tags", used in the meta box when JavaScript is disabled.
   441  * - choose_from_most_used - This string isn't used on hierarchical taxonomies. Default is "Choose from the most used tags", used in the meta box.
   461  * - choose_from_most_used - This string isn't used on hierarchical taxonomies. Default is "Choose from the most used tags", used in the meta box.
   442  * - not_found - This string isn't used on hierarchical taxonomies. Default is "No tags found", used in the meta box.
   462  * - not_found - Default is "No tags found"/"No categories found", used in the meta box and taxonomy list table.
   443  *
   463  *
   444  * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories).
   464  * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories).
   445  *
   465  *
   446  * @since 3.0.0
   466  * @since 3.0.0
   447  * @param object $tax Taxonomy object
   467  * @param object $tax Taxonomy object
   471 		'add_new_item' => array( __( 'Add New Tag' ), __( 'Add New Category' ) ),
   491 		'add_new_item' => array( __( 'Add New Tag' ), __( 'Add New Category' ) ),
   472 		'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ),
   492 		'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ),
   473 		'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ),
   493 		'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ),
   474 		'add_or_remove_items' => array( __( 'Add or remove tags' ), null ),
   494 		'add_or_remove_items' => array( __( 'Add or remove tags' ), null ),
   475 		'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ),
   495 		'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ),
   476 		'not_found' => array( __( 'No tags found.' ), null ),
   496 		'not_found' => array( __( 'No tags found.' ), __( 'No categories found.' ) ),
   477 	);
   497 	);
   478 	$nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
   498 	$nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
   479 
   499 
   480 	return _get_custom_object_labels( $tax, $nohier_vs_hier_defaults );
   500 	return _get_custom_object_labels( $tax, $nohier_vs_hier_defaults );
   481 }
   501 }
   482 
   502 
   483 /**
   503 /**
   484  * Add an already registered taxonomy to an object type.
   504  * Add an already registered taxonomy to an object type.
   485  *
   505  *
   486  * @package WordPress
       
   487  * @subpackage Taxonomy
       
   488  * @since 3.0.0
   506  * @since 3.0.0
   489  * @uses $wp_taxonomies Modifies taxonomy object
   507  * @uses $wp_taxonomies Modifies taxonomy object
   490  *
   508  *
   491  * @param string $taxonomy Name of taxonomy object
   509  * @param string $taxonomy Name of taxonomy object
   492  * @param string $object_type Name of the object type
   510  * @param string $object_type Name of the object type
   550  *
   568  *
   551  * It is possible to change the order that object_ids is returned by either
   569  * It is possible to change the order that object_ids is returned by either
   552  * using PHP sort family functions or using the database by using $args with
   570  * using PHP sort family functions or using the database by using $args with
   553  * either ASC or DESC array. The value should be in the key named 'order'.
   571  * either ASC or DESC array. The value should be in the key named 'order'.
   554  *
   572  *
   555  * @package WordPress
       
   556  * @subpackage Taxonomy
       
   557  * @since 2.3.0
   573  * @since 2.3.0
   558  *
   574  *
   559  * @uses $wpdb
   575  * @global wpdb $wpdb WordPress database abstraction object.
   560  * @uses wp_parse_args() Creates an array from string $args.
       
   561  *
   576  *
   562  * @param int|array $term_ids Term id or array of term ids of terms that will be used
   577  * @param int|array $term_ids Term id or array of term ids of terms that will be used
   563  * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names
   578  * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names
   564  * @param array|string $args Change the order of the object_ids, either ASC or DESC
   579  * @param array|string $args Change the order of the object_ids, either ASC or DESC
   565  * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success
   580  * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success
   566  *	the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
   581  *	the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
   567  */
   582  */
   568 function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
   583 function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
   569 	global $wpdb;
   584 	global $wpdb;
   570 
   585 
   571 	if ( ! is_array( $term_ids ) )
   586 	if ( ! is_array( $term_ids ) ) {
   572 		$term_ids = array( $term_ids );
   587 		$term_ids = array( $term_ids );
   573 
   588 	}
   574 	if ( ! is_array( $taxonomies ) )
   589 	if ( ! is_array( $taxonomies ) ) {
   575 		$taxonomies = array( $taxonomies );
   590 		$taxonomies = array( $taxonomies );
   576 
   591 	}
   577 	foreach ( (array) $taxonomies as $taxonomy ) {
   592 	foreach ( (array) $taxonomies as $taxonomy ) {
   578 		if ( ! taxonomy_exists( $taxonomy ) )
   593 		if ( ! taxonomy_exists( $taxonomy ) ) {
   579 			return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
   594 			return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
       
   595 		}
   580 	}
   596 	}
   581 
   597 
   582 	$defaults = array( 'order' => 'ASC' );
   598 	$defaults = array( 'order' => 'ASC' );
   583 	$args = wp_parse_args( $args, $defaults );
   599 	$args = wp_parse_args( $args, $defaults );
   584 	extract( $args, EXTR_SKIP );
   600 
   585 
   601 	$order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC';
   586 	$order = ( 'desc' == strtolower( $order ) ) ? 'DESC' : 'ASC';
       
   587 
   602 
   588 	$term_ids = array_map('intval', $term_ids );
   603 	$term_ids = array_map('intval', $term_ids );
   589 
   604 
   590 	$taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
   605 	$taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
   591 	$term_ids = "'" . implode( "', '", $term_ids ) . "'";
   606 	$term_ids = "'" . implode( "', '", $term_ids ) . "'";
   592 
   607 
   593 	$object_ids = $wpdb->get_col("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");
   608 	$object_ids = $wpdb->get_col("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");
   594 
   609 
   595 	if ( ! $object_ids )
   610 	if ( ! $object_ids ){
   596 		return array();
   611 		return array();
   597 
   612 	}
   598 	return $object_ids;
   613 	return $object_ids;
   599 }
   614 }
   600 
   615 
   601 /**
   616 /**
   602  * Given a taxonomy query, generates SQL to be appended to a main query.
   617  * Given a taxonomy query, generates SQL to be appended to a main query.
   614 	$tax_query_obj = new WP_Tax_Query( $tax_query );
   629 	$tax_query_obj = new WP_Tax_Query( $tax_query );
   615 	return $tax_query_obj->get_sql( $primary_table, $primary_id_column );
   630 	return $tax_query_obj->get_sql( $primary_table, $primary_id_column );
   616 }
   631 }
   617 
   632 
   618 /**
   633 /**
   619  * Container class for a multiple taxonomy query.
   634  * Class for generating SQL clauses that filter a primary query according to object taxonomy terms.
       
   635  *
       
   636  * `WP_Tax_Query` is a helper that allows primary query classes, such as {@see WP_Query}, to filter
       
   637  * their results by object metadata, by generating `JOIN` and `WHERE` subclauses to be attached
       
   638  * to the primary SQL query string.
   620  *
   639  *
   621  * @since 3.1.0
   640  * @since 3.1.0
   622  */
   641  */
   623 class WP_Tax_Query {
   642 class WP_Tax_Query {
   624 
   643 
   625 	/**
   644 	/**
   626 	 * List of taxonomy queries. A single taxonomy query is an associative array:
   645 	 * Array of taxonomy queries.
   627 	 * - 'taxonomy' string The taxonomy being queried
   646 	 *
   628 	 * - 'terms' string|array The list of terms
   647 	 * See {@see WP_Tax_Query::__construct()} for information on tax query arguments.
   629 	 * - 'field' string (optional) Which term field is being used.
       
   630 	 *		Possible values: 'term_id', 'slug' or 'name'
       
   631 	 *		Default: 'term_id'
       
   632 	 * - 'operator' string (optional)
       
   633 	 *		Possible values: 'AND', 'IN' or 'NOT IN'.
       
   634 	 *		Default: 'IN'
       
   635 	 * - 'include_children' bool (optional) Whether to include child terms.
       
   636 	 *		Default: true
       
   637 	 *
   648 	 *
   638 	 * @since 3.1.0
   649 	 * @since 3.1.0
   639 	 * @access public
   650 	 * @access public
   640 	 * @var array
   651 	 * @var array
   641 	 */
   652 	 */
   655 	 *
   666 	 *
   656 	 * @since 3.2.0
   667 	 * @since 3.2.0
   657 	 * @access private
   668 	 * @access private
   658 	 * @var string
   669 	 * @var string
   659 	 */
   670 	 */
   660 	private static $no_results = array( 'join' => '', 'where' => ' AND 0 = 1' );
   671 	private static $no_results = array( 'join' => array( '' ), 'where' => array( '0 = 1' ) );
       
   672 
       
   673 	/**
       
   674 	 * A flat list of table aliases used in the JOIN clauses.
       
   675 	 *
       
   676 	 * @since 4.1.0
       
   677 	 * @access protected
       
   678 	 * @var array
       
   679 	 */
       
   680 	protected $table_aliases = array();
       
   681 
       
   682 	/**
       
   683 	 * Terms and taxonomies fetched by this query.
       
   684 	 *
       
   685 	 * We store this data in a flat array because they are referenced in a
       
   686 	 * number of places by {@see WP_Query}.
       
   687 	 *
       
   688 	 * @since 4.1.0
       
   689 	 * @access public
       
   690 	 * @var array
       
   691 	 */
       
   692 	public $queried_terms = array();
       
   693 
       
   694 	/**
       
   695 	 * Database table that where the metadata's objects are stored (eg $wpdb->users).
       
   696 	 *
       
   697 	 * @since 4.1.0
       
   698 	 * @access public
       
   699 	 * @var string
       
   700 	 */
       
   701 	public $primary_table;
       
   702 
       
   703 	/**
       
   704 	 * Column in 'primary_table' that represents the ID of the object.
       
   705 	 *
       
   706 	 * @since 4.1.0
       
   707 	 * @access public
       
   708 	 * @var string
       
   709 	 */
       
   710 	public $primary_id_column;
   661 
   711 
   662 	/**
   712 	/**
   663 	 * Constructor.
   713 	 * Constructor.
   664 	 *
   714 	 *
   665 	 * Parses a compact tax query and sets defaults.
       
   666 	 *
       
   667 	 * @since 3.1.0
   715 	 * @since 3.1.0
       
   716 	 * @since 4.1.0 Added support for `$operator` 'NOT EXISTS' and 'EXISTS' values.
   668 	 * @access public
   717 	 * @access public
   669 	 *
   718 	 *
   670 	 * @param array $tax_query A compact tax query:
   719 	 * @param array $tax_query {
   671 	 *  array(
   720 	 *     Array of taxonomy query clauses.
   672 	 *    'relation' => 'OR',
   721 	 *
   673 	 *    array(
   722 	 *     @type string $relation Optional. The MySQL keyword used to join
   674 	 *      'taxonomy' => 'tax1',
   723 	 *                            the clauses of the query. Accepts 'AND', or 'OR'. Default 'AND'.
   675 	 *      'terms' => array( 'term1', 'term2' ),
   724 	 *     @type array {
   676 	 *      'field' => 'slug',
   725 	 *         Optional. An array of first-order clause parameters, or another fully-formed tax query.
   677 	 *    ),
   726 	 *
   678 	 *    array(
   727 	 *         @type string           $taxonomy         Taxonomy being queried. Optional when field=term_taxonomy_id.
   679 	 *      'taxonomy' => 'tax2',
   728 	 *         @type string|int|array $terms            Term or terms to filter by.
   680 	 *      'terms' => array( 'term-a', 'term-b' ),
   729 	 *         @type string           $field            Field to match $terms against. Accepts 'term_id', 'slug',
   681 	 *      'field' => 'slug',
   730 	 *                                                 'name', or 'term_taxonomy_id'. Default: 'term_id'.
   682 	 *    ),
   731 	 *         @type string           $operator         MySQL operator to be used with $terms in the WHERE clause.
   683 	 *  )
   732 	 *                                                  Accepts 'AND', 'IN', 'NOT IN', 'EXISTS', 'NOT EXISTS'.
       
   733 	 *                                                  Default: 'IN'.
       
   734 	 *         @type bool             $include_children Optional. Whether to include child terms.
       
   735 	 *                                                  Requires a $taxonomy. Default: true.
       
   736 	 *     }
       
   737 	 * }
   684 	 */
   738 	 */
   685 	public function __construct( $tax_query ) {
   739 	public function __construct( $tax_query ) {
   686 		if ( isset( $tax_query['relation'] ) && strtoupper( $tax_query['relation'] ) == 'OR' ) {
   740 		if ( isset( $tax_query['relation'] ) ) {
   687 			$this->relation = 'OR';
   741 			$this->relation = $this->sanitize_relation( $tax_query['relation'] );
   688 		} else {
   742 		} else {
   689 			$this->relation = 'AND';
   743 			$this->relation = 'AND';
   690 		}
   744 		}
       
   745 
       
   746 		$this->queries = $this->sanitize_query( $tax_query );
       
   747 	}
       
   748 
       
   749 	/**
       
   750 	 * Ensure the 'tax_query' argument passed to the class constructor is well-formed.
       
   751 	 *
       
   752 	 * Ensures that each query-level clause has a 'relation' key, and that
       
   753 	 * each first-order clause contains all the necessary keys from `$defaults`.
       
   754 	 *
       
   755 	 * @since 4.1.0
       
   756 	 * @access public
       
   757 	 *
       
   758 	 * @param array $queries Array of queries clauses.
       
   759 	 * @return array Sanitized array of query clauses.
       
   760 	 */
       
   761 	public function sanitize_query( $queries ) {
       
   762 		$cleaned_query = array();
   691 
   763 
   692 		$defaults = array(
   764 		$defaults = array(
   693 			'taxonomy' => '',
   765 			'taxonomy' => '',
   694 			'terms' => array(),
   766 			'terms' => array(),
   695 			'include_children' => true,
       
   696 			'field' => 'term_id',
   767 			'field' => 'term_id',
   697 			'operator' => 'IN',
   768 			'operator' => 'IN',
       
   769 			'include_children' => true,
   698 		);
   770 		);
   699 
   771 
   700 		foreach ( $tax_query as $query ) {
   772 		foreach ( $queries as $key => $query ) {
   701 			if ( ! is_array( $query ) )
   773 			if ( 'relation' === $key ) {
   702 				continue;
   774 				$cleaned_query['relation'] = $this->sanitize_relation( $query );
   703 
   775 
   704 			$query = array_merge( $defaults, $query );
   776 			// First-order clause.
   705 
   777 			} elseif ( self::is_first_order_clause( $query ) ) {
   706 			$query['terms'] = (array) $query['terms'];
   778 
   707 
   779 				$cleaned_clause = array_merge( $defaults, $query );
   708 			$this->queries[] = $query;
   780 				$cleaned_clause['terms'] = (array) $cleaned_clause['terms'];
   709 		}
   781 				$cleaned_query[] = $cleaned_clause;
       
   782 
       
   783 				/*
       
   784 				 * Keep a copy of the clause in the flate
       
   785 				 * $queried_terms array, for use in WP_Query.
       
   786 				 */
       
   787 				if ( ! empty( $cleaned_clause['taxonomy'] ) && 'NOT IN' !== $cleaned_clause['operator'] ) {
       
   788 					$taxonomy = $cleaned_clause['taxonomy'];
       
   789 					if ( ! isset( $this->queried_terms[ $taxonomy ] ) ) {
       
   790 						$this->queried_terms[ $taxonomy ] = array();
       
   791 					}
       
   792 
       
   793 					/*
       
   794 					 * Backward compatibility: Only store the first
       
   795 					 * 'terms' and 'field' found for a given taxonomy.
       
   796 					 */
       
   797 					if ( ! empty( $cleaned_clause['terms'] ) && ! isset( $this->queried_terms[ $taxonomy ]['terms'] ) ) {
       
   798 						$this->queried_terms[ $taxonomy ]['terms'] = $cleaned_clause['terms'];
       
   799 					}
       
   800 
       
   801 					if ( ! empty( $cleaned_clause['field'] ) && ! isset( $this->queried_terms[ $taxonomy ]['field'] ) ) {
       
   802 						$this->queried_terms[ $taxonomy ]['field'] = $cleaned_clause['field'];
       
   803 					}
       
   804 				}
       
   805 
       
   806 			// Otherwise, it's a nested query, so we recurse.
       
   807 			} elseif ( is_array( $query ) ) {
       
   808 				$cleaned_subquery = $this->sanitize_query( $query );
       
   809 
       
   810 				if ( ! empty( $cleaned_subquery ) ) {
       
   811 					// All queries with children must have a relation.
       
   812 					if ( ! isset( $cleaned_subquery['relation'] ) ) {
       
   813 						$cleaned_subquery['relation'] = 'AND';
       
   814 					}
       
   815 
       
   816 					$cleaned_query[] = $cleaned_subquery;
       
   817 				}
       
   818 			}
       
   819 		}
       
   820 
       
   821 		return $cleaned_query;
       
   822 	}
       
   823 
       
   824 	/**
       
   825 	 * Sanitize a 'relation' operator.
       
   826 	 *
       
   827 	 * @since 4.1.0
       
   828 	 * @access public
       
   829 	 *
       
   830 	 * @param string $relation Raw relation key from the query argument.
       
   831 	 * @return string Sanitized relation ('AND' or 'OR').
       
   832 	 */
       
   833 	public function sanitize_relation( $relation ) {
       
   834 		if ( 'OR' === strtoupper( $relation ) ) {
       
   835 			return 'OR';
       
   836 		} else {
       
   837 			return 'AND';
       
   838 		}
       
   839 	}
       
   840 
       
   841 	/**
       
   842 	 * Determine whether a clause is first-order.
       
   843 	 *
       
   844 	 * A "first-order" clause is one that contains any of the first-order
       
   845 	 * clause keys ('terms', 'taxonomy', 'include_children', 'field',
       
   846 	 * 'operator'). An empty clause also counts as a first-order clause,
       
   847 	 * for backward compatibility. Any clause that doesn't meet this is
       
   848 	 * determined, by process of elimination, to be a higher-order query.
       
   849 	 *
       
   850 	 * @since 4.1.0
       
   851 	 * @access protected
       
   852 	 *
       
   853 	 * @param array $query Tax query arguments.
       
   854 	 * @return bool Whether the query clause is a first-order clause.
       
   855 	 */
       
   856 	protected static function is_first_order_clause( $query ) {
       
   857 		return is_array( $query ) && ( empty( $query ) || array_key_exists( 'terms', $query ) || array_key_exists( 'taxonomy', $query ) || array_key_exists( 'include_children', $query ) || array_key_exists( 'field', $query ) || array_key_exists( 'operator', $query ) );
   710 	}
   858 	}
   711 
   859 
   712 	/**
   860 	/**
   713 	 * Generates SQL clauses to be appended to a main query.
   861 	 * Generates SQL clauses to be appended to a main query.
   714 	 *
   862 	 *
   715 	 * @since 3.1.0
   863 	 * @since 3.1.0
   716 	 * @access public
   864 	 * @access public
   717 	 *
   865 	 *
   718 	 * @param string $primary_table
   866 	 * @param string $primary_table     Database table where the object being filtered is stored (eg wp_users).
   719 	 * @param string $primary_id_column
   867 	 * @param string $primary_id_column ID column for the filtered object in $primary_table.
   720 	 * @return array
   868 	 * @return array {
       
   869 	 *     Array containing JOIN and WHERE SQL clauses to append to the main query.
       
   870 	 *
       
   871 	 *     @type string $join  SQL fragment to append to the main JOIN clause.
       
   872 	 *     @type string $where SQL fragment to append to the main WHERE clause.
       
   873 	 * }
   721 	 */
   874 	 */
   722 	public function get_sql( $primary_table, $primary_id_column ) {
   875 	public function get_sql( $primary_table, $primary_id_column ) {
       
   876 		$this->primary_table = $primary_table;
       
   877 		$this->primary_id_column = $primary_id_column;
       
   878 
       
   879 		return $this->get_sql_clauses();
       
   880 	}
       
   881 
       
   882 	/**
       
   883 	 * Generate SQL clauses to be appended to a main query.
       
   884 	 *
       
   885 	 * Called by the public {@see WP_Tax_Query::get_sql()}, this method
       
   886 	 * is abstracted out to maintain parity with the other Query classes.
       
   887 	 *
       
   888 	 * @since 4.1.0
       
   889 	 * @access protected
       
   890 	 *
       
   891 	 * @return array {
       
   892 	 *     Array containing JOIN and WHERE SQL clauses to append to the main query.
       
   893 	 *
       
   894 	 *     @type string $join  SQL fragment to append to the main JOIN clause.
       
   895 	 *     @type string $where SQL fragment to append to the main WHERE clause.
       
   896 	 * }
       
   897 	 */
       
   898 	protected function get_sql_clauses() {
       
   899 		/*
       
   900 		 * $queries are passed by reference to get_sql_for_query() for recursion.
       
   901 		 * To keep $this->queries unaltered, pass a copy.
       
   902 		 */
       
   903 		$queries = $this->queries;
       
   904 		$sql = $this->get_sql_for_query( $queries );
       
   905 
       
   906 		if ( ! empty( $sql['where'] ) ) {
       
   907 			$sql['where'] = ' AND ' . $sql['where'];
       
   908 		}
       
   909 
       
   910 		return $sql;
       
   911 	}
       
   912 
       
   913 	/**
       
   914 	 * Generate SQL clauses for a single query array.
       
   915 	 *
       
   916 	 * If nested subqueries are found, this method recurses the tree to
       
   917 	 * produce the properly nested SQL.
       
   918 	 *
       
   919 	 * @since 4.1.0
       
   920 	 * @access protected
       
   921 	 *
       
   922 	 * @param array $query Query to parse, passed by reference.
       
   923 	 * @param int   $depth Optional. Number of tree levels deep we currently are.
       
   924 	 *                     Used to calculate indentation. Default 0.
       
   925 	 * @return array {
       
   926 	 *     Array containing JOIN and WHERE SQL clauses to append to a single query array.
       
   927 	 *
       
   928 	 *     @type string $join  SQL fragment to append to the main JOIN clause.
       
   929 	 *     @type string $where SQL fragment to append to the main WHERE clause.
       
   930 	 * }
       
   931 	 */
       
   932 	protected function get_sql_for_query( &$query, $depth = 0 ) {
       
   933 		$sql_chunks = array(
       
   934 			'join'  => array(),
       
   935 			'where' => array(),
       
   936 		);
       
   937 
       
   938 		$sql = array(
       
   939 			'join'  => '',
       
   940 			'where' => '',
       
   941 		);
       
   942 
       
   943 		$indent = '';
       
   944 		for ( $i = 0; $i < $depth; $i++ ) {
       
   945 			$indent .= "  ";
       
   946 		}
       
   947 
       
   948 		foreach ( $query as $key => &$clause ) {
       
   949 			if ( 'relation' === $key ) {
       
   950 				$relation = $query['relation'];
       
   951 			} elseif ( is_array( $clause ) ) {
       
   952 
       
   953 				// This is a first-order clause.
       
   954 				if ( $this->is_first_order_clause( $clause ) ) {
       
   955 					$clause_sql = $this->get_sql_for_clause( $clause, $query );
       
   956 
       
   957 					$where_count = count( $clause_sql['where'] );
       
   958 					if ( ! $where_count ) {
       
   959 						$sql_chunks['where'][] = '';
       
   960 					} elseif ( 1 === $where_count ) {
       
   961 						$sql_chunks['where'][] = $clause_sql['where'][0];
       
   962 					} else {
       
   963 						$sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )';
       
   964 					}
       
   965 
       
   966 					$sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] );
       
   967 				// This is a subquery, so we recurse.
       
   968 				} else {
       
   969 					$clause_sql = $this->get_sql_for_query( $clause, $depth + 1 );
       
   970 
       
   971 					$sql_chunks['where'][] = $clause_sql['where'];
       
   972 					$sql_chunks['join'][]  = $clause_sql['join'];
       
   973 				}
       
   974 			}
       
   975 		}
       
   976 
       
   977 		// Filter to remove empties.
       
   978 		$sql_chunks['join']  = array_filter( $sql_chunks['join'] );
       
   979 		$sql_chunks['where'] = array_filter( $sql_chunks['where'] );
       
   980 
       
   981 		if ( empty( $relation ) ) {
       
   982 			$relation = 'AND';
       
   983 		}
       
   984 
       
   985 		// Filter duplicate JOIN clauses and combine into a single string.
       
   986 		if ( ! empty( $sql_chunks['join'] ) ) {
       
   987 			$sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) );
       
   988 		}
       
   989 
       
   990 		// Generate a single WHERE clause with proper brackets and indentation.
       
   991 		if ( ! empty( $sql_chunks['where'] ) ) {
       
   992 			$sql['where'] = '( ' . "\n  " . $indent . implode( ' ' . "\n  " . $indent . $relation . ' ' . "\n  " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')';
       
   993 		}
       
   994 
       
   995 		return $sql;
       
   996 	}
       
   997 
       
   998 	/**
       
   999 	 * Generate SQL JOIN and WHERE clauses for a "first-order" query clause.
       
  1000 	 *
       
  1001 	 * @since 4.1.0
       
  1002 	 * @access public
       
  1003 	 *
       
  1004 	 * @param array $clause       Query clause, passed by reference
       
  1005 	 * @param array $parent_query Parent query array.
       
  1006 	 * @return array {
       
  1007 	 *     Array containing JOIN and WHERE SQL clauses to append to a first-order query.
       
  1008 	 *
       
  1009 	 *     @type string $join  SQL fragment to append to the main JOIN clause.
       
  1010 	 *     @type string $where SQL fragment to append to the main WHERE clause.
       
  1011 	 * }
       
  1012 	 */
       
  1013 	public function get_sql_for_clause( &$clause, $parent_query ) {
   723 		global $wpdb;
  1014 		global $wpdb;
   724 
  1015 
       
  1016 		$sql = array(
       
  1017 			'where' => array(),
       
  1018 			'join'  => array(),
       
  1019 		);
       
  1020 
   725 		$join = '';
  1021 		$join = '';
   726 		$where = array();
  1022 
   727 		$i = 0;
  1023 		$this->clean_query( $clause );
   728 		$count = count( $this->queries );
  1024 
   729 
  1025 		if ( is_wp_error( $clause ) ) {
   730 		foreach ( $this->queries as $index => $query ) {
  1026 			return self::$no_results;
   731 			$this->clean_query( $query );
  1027 		}
   732 
  1028 
   733 			if ( is_wp_error( $query ) )
  1029 		$terms = $clause['terms'];
       
  1030 		$operator = strtoupper( $clause['operator'] );
       
  1031 
       
  1032 		if ( 'IN' == $operator ) {
       
  1033 
       
  1034 			if ( empty( $terms ) ) {
   734 				return self::$no_results;
  1035 				return self::$no_results;
   735 
  1036 			}
   736 			extract( $query );
  1037 
   737 
  1038 			$terms = implode( ',', $terms );
   738 			if ( 'IN' == $operator ) {
  1039 
   739 
  1040 			/*
   740 				if ( empty( $terms ) ) {
  1041 			 * Before creating another table join, see if this clause has a
   741 					if ( 'OR' == $this->relation ) {
  1042 			 * sibling with an existing join that can be shared.
   742 						if ( ( $index + 1 === $count ) && empty( $where ) )
  1043 			 */
   743 							return self::$no_results;
  1044 			$alias = $this->find_compatible_table_alias( $clause, $parent_query );
   744 						continue;
  1045 			if ( false === $alias ) {
   745 					} else {
  1046 				$i = count( $this->table_aliases );
   746 						return self::$no_results;
       
   747 					}
       
   748 				}
       
   749 
       
   750 				$terms = implode( ',', $terms );
       
   751 
       
   752 				$alias = $i ? 'tt' . $i : $wpdb->term_relationships;
  1047 				$alias = $i ? 'tt' . $i : $wpdb->term_relationships;
       
  1048 
       
  1049 				// Store the alias as part of a flat array to build future iterators.
       
  1050 				$this->table_aliases[] = $alias;
       
  1051 
       
  1052 				// Store the alias with this clause, so later siblings can use it.
       
  1053 				$clause['alias'] = $alias;
   753 
  1054 
   754 				$join .= " INNER JOIN $wpdb->term_relationships";
  1055 				$join .= " INNER JOIN $wpdb->term_relationships";
   755 				$join .= $i ? " AS $alias" : '';
  1056 				$join .= $i ? " AS $alias" : '';
   756 				$join .= " ON ($primary_table.$primary_id_column = $alias.object_id)";
  1057 				$join .= " ON ($this->primary_table.$this->primary_id_column = $alias.object_id)";
   757 
       
   758 				$where[] = "$alias.term_taxonomy_id $operator ($terms)";
       
   759 			} elseif ( 'NOT IN' == $operator ) {
       
   760 
       
   761 				if ( empty( $terms ) )
       
   762 					continue;
       
   763 
       
   764 				$terms = implode( ',', $terms );
       
   765 
       
   766 				$where[] = "$primary_table.$primary_id_column NOT IN (
       
   767 					SELECT object_id
       
   768 					FROM $wpdb->term_relationships
       
   769 					WHERE term_taxonomy_id IN ($terms)
       
   770 				)";
       
   771 			} elseif ( 'AND' == $operator ) {
       
   772 
       
   773 				if ( empty( $terms ) )
       
   774 					continue;
       
   775 
       
   776 				$num_terms = count( $terms );
       
   777 
       
   778 				$terms = implode( ',', $terms );
       
   779 
       
   780 				$where[] = "(
       
   781 					SELECT COUNT(1)
       
   782 					FROM $wpdb->term_relationships
       
   783 					WHERE term_taxonomy_id IN ($terms)
       
   784 					AND object_id = $primary_table.$primary_id_column
       
   785 				) = $num_terms";
       
   786 			}
  1058 			}
   787 
  1059 
   788 			$i++;
  1060 
   789 		}
  1061 			$where = "$alias.term_taxonomy_id $operator ($terms)";
   790 
  1062 
   791 		if ( ! empty( $where ) )
  1063 		} elseif ( 'NOT IN' == $operator ) {
   792 			$where = ' AND ( ' . implode( " $this->relation ", $where ) . ' )';
  1064 
   793 		else
  1065 			if ( empty( $terms ) ) {
   794 			$where = '';
  1066 				return $sql;
   795 
  1067 			}
   796 		return compact( 'join', 'where' );
  1068 
       
  1069 			$terms = implode( ',', $terms );
       
  1070 
       
  1071 			$where = "$this->primary_table.$this->primary_id_column NOT IN (
       
  1072 				SELECT object_id
       
  1073 				FROM $wpdb->term_relationships
       
  1074 				WHERE term_taxonomy_id IN ($terms)
       
  1075 			)";
       
  1076 
       
  1077 		} elseif ( 'AND' == $operator ) {
       
  1078 
       
  1079 			if ( empty( $terms ) ) {
       
  1080 				return $sql;
       
  1081 			}
       
  1082 
       
  1083 			$num_terms = count( $terms );
       
  1084 
       
  1085 			$terms = implode( ',', $terms );
       
  1086 
       
  1087 			$where = "(
       
  1088 				SELECT COUNT(1)
       
  1089 				FROM $wpdb->term_relationships
       
  1090 				WHERE term_taxonomy_id IN ($terms)
       
  1091 				AND object_id = $this->primary_table.$this->primary_id_column
       
  1092 			) = $num_terms";
       
  1093 
       
  1094 		} elseif ( 'NOT EXISTS' === $operator || 'EXISTS' === $operator ) {
       
  1095 
       
  1096 			$where = $wpdb->prepare( "$operator (
       
  1097 				SELECT 1
       
  1098 				FROM $wpdb->term_relationships
       
  1099 				INNER JOIN $wpdb->term_taxonomy
       
  1100 				ON $wpdb->term_taxonomy.term_taxonomy_id = $wpdb->term_relationships.term_taxonomy_id
       
  1101 				WHERE $wpdb->term_taxonomy.taxonomy = %s
       
  1102 				AND $wpdb->term_relationships.object_id = $this->primary_table.$this->primary_id_column
       
  1103 			)", $clause['taxonomy'] );
       
  1104 
       
  1105 		}
       
  1106 
       
  1107 		$sql['join'][]  = $join;
       
  1108 		$sql['where'][] = $where;
       
  1109 		return $sql;
       
  1110 	}
       
  1111 
       
  1112 	/**
       
  1113 	 * Identify an existing table alias that is compatible with the current query clause.
       
  1114 	 *
       
  1115 	 * We avoid unnecessary table joins by allowing each clause to look for
       
  1116 	 * an existing table alias that is compatible with the query that it
       
  1117 	 * needs to perform.
       
  1118 	 *
       
  1119 	 * An existing alias is compatible if (a) it is a sibling of `$clause`
       
  1120 	 * (ie, it's under the scope of the same relation), and (b) the combination
       
  1121 	 * of operator and relation between the clauses allows for a shared table
       
  1122 	 * join. In the case of {@see WP_Tax_Query}, this only applies to 'IN'
       
  1123 	 * clauses that are connected by the relation 'OR'.
       
  1124 	 *
       
  1125 	 * @since 4.1.0
       
  1126 	 * @access protected
       
  1127 	 *
       
  1128 	 * @param array       $clause       Query clause.
       
  1129 	 * @param array       $parent_query Parent query of $clause.
       
  1130 	 * @return string|bool Table alias if found, otherwise false.
       
  1131 	 */
       
  1132 	protected function find_compatible_table_alias( $clause, $parent_query ) {
       
  1133 		$alias = false;
       
  1134 
       
  1135 		// Sanity check. Only IN queries use the JOIN syntax .
       
  1136 		if ( ! isset( $clause['operator'] ) || 'IN' !== $clause['operator'] ) {
       
  1137 			return $alias;
       
  1138 		}
       
  1139 
       
  1140 		// Since we're only checking IN queries, we're only concerned with OR relations.
       
  1141 		if ( ! isset( $parent_query['relation'] ) || 'OR' !== $parent_query['relation'] ) {
       
  1142 			return $alias;
       
  1143 		}
       
  1144 
       
  1145 		$compatible_operators = array( 'IN' );
       
  1146 
       
  1147 		foreach ( $parent_query as $sibling ) {
       
  1148 			if ( ! is_array( $sibling ) || ! $this->is_first_order_clause( $sibling ) ) {
       
  1149 				continue;
       
  1150 			}
       
  1151 
       
  1152 			if ( empty( $sibling['alias'] ) || empty( $sibling['operator'] ) ) {
       
  1153 				continue;
       
  1154 			}
       
  1155 
       
  1156 			// The sibling must both have compatible operator to share its alias.
       
  1157 			if ( in_array( strtoupper( $sibling['operator'] ), $compatible_operators ) ) {
       
  1158 				$alias = $sibling['alias'];
       
  1159 				break;
       
  1160 			}
       
  1161 		}
       
  1162 
       
  1163 		return $alias;
   797 	}
  1164 	}
   798 
  1165 
   799 	/**
  1166 	/**
   800 	 * Validates a single query.
  1167 	 * Validates a single query.
   801 	 *
  1168 	 *
   802 	 * @since 3.2.0
  1169 	 * @since 3.2.0
   803 	 * @access private
  1170 	 * @access private
   804 	 *
  1171 	 *
   805 	 * @param array &$query The single query
  1172 	 * @param array &$query The single query.
   806 	 */
  1173 	 */
   807 	private function clean_query( &$query ) {
  1174 	private function clean_query( &$query ) {
   808 		if ( ! taxonomy_exists( $query['taxonomy'] ) ) {
  1175 		if ( empty( $query['taxonomy'] ) ) {
       
  1176 			if ( 'term_taxonomy_id' !== $query['field'] ) {
       
  1177 				$query = new WP_Error( 'Invalid taxonomy' );
       
  1178 				return;
       
  1179 			}
       
  1180 
       
  1181 			// so long as there are shared terms, include_children requires that a taxonomy is set
       
  1182 			$query['include_children'] = false;
       
  1183 		} elseif ( ! taxonomy_exists( $query['taxonomy'] ) ) {
   809 			$query = new WP_Error( 'Invalid taxonomy' );
  1184 			$query = new WP_Error( 'Invalid taxonomy' );
   810 			return;
  1185 			return;
   811 		}
  1186 		}
   812 
  1187 
   813 		$query['terms'] = array_unique( (array) $query['terms'] );
  1188 		$query['terms'] = array_unique( (array) $query['terms'] );
   832 	/**
  1207 	/**
   833 	 * Transforms a single query, from one field to another.
  1208 	 * Transforms a single query, from one field to another.
   834 	 *
  1209 	 *
   835 	 * @since 3.2.0
  1210 	 * @since 3.2.0
   836 	 *
  1211 	 *
   837 	 * @param array &$query The single query
  1212 	 * @param array  &$query          The single query.
   838 	 * @param string $resulting_field The resulting field
  1213 	 * @param string $resulting_field The resulting field. Accepts 'slug', 'name', 'term_taxonomy_id',
       
  1214 	 *                                or 'term_id'. Default: 'term_id'.
   839 	 */
  1215 	 */
   840 	public function transform_query( &$query, $resulting_field ) {
  1216 	public function transform_query( &$query, $resulting_field ) {
   841 		global $wpdb;
  1217 		global $wpdb;
   842 
  1218 
   843 		if ( empty( $query['terms'] ) )
  1219 		if ( empty( $query['terms'] ) )
   849 		$resulting_field = sanitize_key( $resulting_field );
  1225 		$resulting_field = sanitize_key( $resulting_field );
   850 
  1226 
   851 		switch ( $query['field'] ) {
  1227 		switch ( $query['field'] ) {
   852 			case 'slug':
  1228 			case 'slug':
   853 			case 'name':
  1229 			case 'name':
   854 				$terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $query['terms'] ) ) . "'";
  1230 				foreach ( $query['terms'] as &$term ) {
       
  1231 					/*
       
  1232 					 * 0 is the $term_id parameter. We don't have a term ID yet, but it doesn't
       
  1233 					 * matter because `sanitize_term_field()` ignores the $term_id param when the
       
  1234 					 * context is 'db'.
       
  1235 					 */
       
  1236 					$term = "'" . esc_sql( sanitize_term_field( $query['field'], $term, 0, $query['taxonomy'], 'db' ) ) . "'";
       
  1237 				}
       
  1238 
       
  1239 				$terms = implode( ",", $query['terms'] );
       
  1240 
   855 				$terms = $wpdb->get_col( "
  1241 				$terms = $wpdb->get_col( "
   856 					SELECT $wpdb->term_taxonomy.$resulting_field
  1242 					SELECT $wpdb->term_taxonomy.$resulting_field
   857 					FROM $wpdb->term_taxonomy
  1243 					FROM $wpdb->term_taxonomy
   858 					INNER JOIN $wpdb->terms USING (term_id)
  1244 					INNER JOIN $wpdb->terms USING (term_id)
   859 					WHERE taxonomy = '{$query['taxonomy']}'
  1245 					WHERE taxonomy = '{$query['taxonomy']}'
   911  * 'get_$taxonomy' hook - Takes two parameters the term Object and the taxonomy
  1297  * 'get_$taxonomy' hook - Takes two parameters the term Object and the taxonomy
   912  * name. Must return term object. $taxonomy will be the taxonomy name, so for
  1298  * name. Must return term object. $taxonomy will be the taxonomy name, so for
   913  * example, if 'category', it would be 'get_category' as the filter name. Useful
  1299  * example, if 'category', it would be 'get_category' as the filter name. Useful
   914  * for custom taxonomies or plugging into default taxonomies.
  1300  * for custom taxonomies or plugging into default taxonomies.
   915  *
  1301  *
   916  * @package WordPress
       
   917  * @subpackage Taxonomy
       
   918  * @since 2.3.0
  1302  * @since 2.3.0
   919  *
  1303  *
   920  * @uses $wpdb
  1304  * @global wpdb $wpdb WordPress database abstraction object.
   921  * @uses sanitize_term() Cleanses the term based on $filter context before returning.
       
   922  * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
  1305  * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
   923  *
  1306  *
   924  * @param int|object $term If integer, will get from database. If object will apply filters and return $term.
  1307  * @param int|object $term If integer, will get from database. If object will apply filters and return $term.
   925  * @param string $taxonomy Taxonomy name that $term is part of.
  1308  * @param string $taxonomy Taxonomy name that $term is part of.
   926  * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
  1309  * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
   928  * @return mixed|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
  1311  * @return mixed|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
   929  * exist then WP_Error will be returned.
  1312  * exist then WP_Error will be returned.
   930  */
  1313  */
   931 function get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') {
  1314 function get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') {
   932 	global $wpdb;
  1315 	global $wpdb;
   933 	$null = null;
       
   934 
  1316 
   935 	if ( empty($term) ) {
  1317 	if ( empty($term) ) {
   936 		$error = new WP_Error('invalid_term', __('Empty Term'));
  1318 		$error = new WP_Error('invalid_term', __('Empty Term'));
   937 		return $error;
  1319 		return $error;
   938 	}
  1320 	}
   941 		$error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
  1323 		$error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
   942 		return $error;
  1324 		return $error;
   943 	}
  1325 	}
   944 
  1326 
   945 	if ( is_object($term) && empty($term->filter) ) {
  1327 	if ( is_object($term) && empty($term->filter) ) {
   946 		wp_cache_add($term->term_id, $term, $taxonomy);
  1328 		wp_cache_add( $term->term_id, $term, $taxonomy );
   947 		$_term = $term;
  1329 		$_term = $term;
   948 	} else {
  1330 	} else {
   949 		if ( is_object($term) )
  1331 		if ( is_object($term) )
   950 			$term = $term->term_id;
  1332 			$term = $term->term_id;
   951 		if ( !$term = (int) $term )
  1333 		if ( !$term = (int) $term )
   952 			return $null;
  1334 			return null;
   953 		if ( ! $_term = wp_cache_get($term, $taxonomy) ) {
  1335 		if ( ! $_term = wp_cache_get( $term, $taxonomy ) ) {
   954 			$_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND t.term_id = %d LIMIT 1", $taxonomy, $term) );
  1336 			$_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND t.term_id = %d LIMIT 1", $taxonomy, $term) );
   955 			if ( ! $_term )
  1337 			if ( ! $_term )
   956 				return $null;
  1338 				return null;
   957 			wp_cache_add($term, $_term, $taxonomy);
  1339 			wp_cache_add( $term, $_term, $taxonomy );
   958 		}
  1340 		}
   959 	}
  1341 	}
   960 
  1342 
   961 	$_term = apply_filters('get_term', $_term, $taxonomy);
  1343 	/**
   962 	$_term = apply_filters("get_$taxonomy", $_term, $taxonomy);
  1344 	 * Filter a term.
       
  1345 	 *
       
  1346 	 * @since 2.3.0
       
  1347 	 *
       
  1348 	 * @param int|object $_term    Term object or ID.
       
  1349 	 * @param string     $taxonomy The taxonomy slug.
       
  1350 	 */
       
  1351 	$_term = apply_filters( 'get_term', $_term, $taxonomy );
       
  1352 
       
  1353 	/**
       
  1354 	 * Filter a taxonomy.
       
  1355 	 *
       
  1356 	 * The dynamic portion of the filter name, `$taxonomy`, refers
       
  1357 	 * to the taxonomy slug.
       
  1358 	 *
       
  1359 	 * @since 2.3.0
       
  1360 	 *
       
  1361 	 * @param int|object $_term    Term object or ID.
       
  1362 	 * @param string     $taxonomy The taxonomy slug.
       
  1363 	 */
       
  1364 	$_term = apply_filters( "get_$taxonomy", $_term, $taxonomy );
   963 	$_term = sanitize_term($_term, $taxonomy, $filter);
  1365 	$_term = sanitize_term($_term, $taxonomy, $filter);
   964 
  1366 
   965 	if ( $output == OBJECT ) {
  1367 	if ( $output == OBJECT ) {
   966 		return $_term;
  1368 		return $_term;
   967 	} elseif ( $output == ARRAY_A ) {
  1369 	} elseif ( $output == ARRAY_A ) {
   985  * field, but not recommended that you do so.
  1387  * field, but not recommended that you do so.
   986  *
  1388  *
   987  * If $value does not exist, the return value will be false. If $taxonomy exists
  1389  * If $value does not exist, the return value will be false. If $taxonomy exists
   988  * and $field and $value combinations exist, the Term will be returned.
  1390  * and $field and $value combinations exist, the Term will be returned.
   989  *
  1391  *
   990  * @package WordPress
       
   991  * @subpackage Taxonomy
       
   992  * @since 2.3.0
  1392  * @since 2.3.0
   993  *
  1393  *
   994  * @uses $wpdb
  1394  * @global wpdb $wpdb WordPress database abstraction object.
   995  * @uses sanitize_term() Cleanses the term based on $filter context before returning.
       
   996  * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
  1395  * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
   997  *
  1396  *
   998  * @param string $field Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
  1397  * @param string $field Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
   999  * @param string|int $value Search for this term value
  1398  * @param string|int $value Search for this term value
  1000  * @param string $taxonomy Taxonomy Name
  1399  * @param string $taxonomy Taxonomy Name
  1011 	if ( 'slug' == $field ) {
  1410 	if ( 'slug' == $field ) {
  1012 		$field = 't.slug';
  1411 		$field = 't.slug';
  1013 		$value = sanitize_title($value);
  1412 		$value = sanitize_title($value);
  1014 		if ( empty($value) )
  1413 		if ( empty($value) )
  1015 			return false;
  1414 			return false;
  1016 	} else if ( 'name' == $field ) {
  1415 	} elseif ( 'name' == $field ) {
  1017 		// Assume already escaped
  1416 		// Assume already escaped
  1018 		$value = wp_unslash($value);
  1417 		$value = wp_unslash($value);
  1019 		$field = 't.name';
  1418 		$field = 't.name';
  1020 	} else if ( 'term_taxonomy_id' == $field ) {
  1419 	} elseif ( 'term_taxonomy_id' == $field ) {
  1021 		$value = (int) $value;
  1420 		$value = (int) $value;
  1022 		$field = 'tt.term_taxonomy_id';
  1421 		$field = 'tt.term_taxonomy_id';
  1023 	} else {
  1422 	} else {
  1024 		$term = get_term( (int) $value, $taxonomy, $output, $filter);
  1423 		$term = get_term( (int) $value, $taxonomy, $output, $filter );
  1025 		if ( is_wp_error( $term ) )
  1424 		if ( is_wp_error( $term ) )
  1026 			$term = false;
  1425 			$term = false;
  1027 		return $term;
  1426 		return $term;
  1028 	}
  1427 	}
  1029 
  1428 
  1030 	$term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value) );
  1429 	$term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value ) );
  1031 	if ( !$term )
  1430 	if ( ! $term )
  1032 		return false;
  1431 		return false;
  1033 
  1432 
  1034 	wp_cache_add($term->term_id, $term, $taxonomy);
  1433 	wp_cache_add( $term->term_id, $term, $taxonomy );
  1035 
  1434 
  1036 	$term = apply_filters('get_term', $term, $taxonomy);
  1435 	/** This filter is documented in wp-includes/taxonomy.php */
  1037 	$term = apply_filters("get_$taxonomy", $term, $taxonomy);
  1436 	$term = apply_filters( 'get_term', $term, $taxonomy );
       
  1437 
       
  1438 	/** This filter is documented in wp-includes/taxonomy.php */
       
  1439 	$term = apply_filters( "get_$taxonomy", $term, $taxonomy );
       
  1440 
  1038 	$term = sanitize_term($term, $taxonomy, $filter);
  1441 	$term = sanitize_term($term, $taxonomy, $filter);
  1039 
  1442 
  1040 	if ( $output == OBJECT ) {
  1443 	if ( $output == OBJECT ) {
  1041 		return $term;
  1444 		return $term;
  1042 	} elseif ( $output == ARRAY_A ) {
  1445 	} elseif ( $output == ARRAY_A ) {
  1054  * This recursive function will merge all of the children of $term into the same
  1457  * This recursive function will merge all of the children of $term into the same
  1055  * array of term IDs. Only useful for taxonomies which are hierarchical.
  1458  * array of term IDs. Only useful for taxonomies which are hierarchical.
  1056  *
  1459  *
  1057  * Will return an empty array if $term does not exist in $taxonomy.
  1460  * Will return an empty array if $term does not exist in $taxonomy.
  1058  *
  1461  *
  1059  * @package WordPress
       
  1060  * @subpackage Taxonomy
       
  1061  * @since 2.3.0
  1462  * @since 2.3.0
  1062  *
  1463  *
  1063  * @uses $wpdb
  1464  * @global wpdb $wpdb WordPress database abstraction object.
  1064  * @uses _get_term_hierarchy()
       
  1065  * @uses get_term_children() Used to get the children of both $taxonomy and the parent $term
       
  1066  *
  1465  *
  1067  * @param string $term_id ID of Term to get children
  1466  * @param string $term_id ID of Term to get children
  1068  * @param string $taxonomy Taxonomy Name
  1467  * @param string $taxonomy Taxonomy Name
  1069  * @return array|WP_Error List of Term Objects. WP_Error returned if $taxonomy does not exist
  1468  * @return array|WP_Error List of Term IDs. WP_Error returned if $taxonomy does not exist
  1070  */
  1469  */
  1071 function get_term_children( $term_id, $taxonomy ) {
  1470 function get_term_children( $term_id, $taxonomy ) {
  1072 	if ( ! taxonomy_exists($taxonomy) )
  1471 	if ( ! taxonomy_exists($taxonomy) )
  1073 		return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
  1472 		return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
  1074 
  1473 
  1080 		return array();
  1479 		return array();
  1081 
  1480 
  1082 	$children = $terms[$term_id];
  1481 	$children = $terms[$term_id];
  1083 
  1482 
  1084 	foreach ( (array) $terms[$term_id] as $child ) {
  1483 	foreach ( (array) $terms[$term_id] as $child ) {
       
  1484 		if ( $term_id == $child ) {
       
  1485 			continue;
       
  1486 		}
       
  1487 
  1085 		if ( isset($terms[$child]) )
  1488 		if ( isset($terms[$child]) )
  1086 			$children = array_merge($children, get_term_children($child, $taxonomy));
  1489 			$children = array_merge($children, get_term_children($child, $taxonomy));
  1087 	}
  1490 	}
  1088 
  1491 
  1089 	return $children;
  1492 	return $children;
  1094  *
  1497  *
  1095  * Does checks for $term, based on the $taxonomy. The function is for contextual
  1498  * Does checks for $term, based on the $taxonomy. The function is for contextual
  1096  * reasons and for simplicity of usage. See sanitize_term_field() for more
  1499  * reasons and for simplicity of usage. See sanitize_term_field() for more
  1097  * information.
  1500  * information.
  1098  *
  1501  *
  1099  * @package WordPress
       
  1100  * @subpackage Taxonomy
       
  1101  * @since 2.3.0
  1502  * @since 2.3.0
  1102  *
       
  1103  * @uses sanitize_term_field() Passes the return value in sanitize_term_field on success.
       
  1104  *
  1503  *
  1105  * @param string $field Term field to fetch
  1504  * @param string $field Term field to fetch
  1106  * @param int $term Term ID
  1505  * @param int $term Term ID
  1107  * @param string $taxonomy Taxonomy Name
  1506  * @param string $taxonomy Taxonomy Name
  1108  * @param string $context Optional, default is display. Look at sanitize_term_field() for available options.
  1507  * @param string $context Optional, default is display. Look at sanitize_term_field() for available options.
  1127  * Sanitizes Term for editing.
  1526  * Sanitizes Term for editing.
  1128  *
  1527  *
  1129  * Return value is sanitize_term() and usage is for sanitizing the term for
  1528  * Return value is sanitize_term() and usage is for sanitizing the term for
  1130  * editing. Function is for contextual and simplicity.
  1529  * editing. Function is for contextual and simplicity.
  1131  *
  1530  *
  1132  * @package WordPress
       
  1133  * @subpackage Taxonomy
       
  1134  * @since 2.3.0
  1531  * @since 2.3.0
  1135  *
       
  1136  * @uses sanitize_term() Passes the return value on success
       
  1137  *
  1532  *
  1138  * @param int|object $id Term ID or Object
  1533  * @param int|object $id Term ID or Object
  1139  * @param string $taxonomy Taxonomy Name
  1534  * @param string $taxonomy Taxonomy Name
  1140  * @return mixed|null|WP_Error Will return empty string if $term is not an object.
  1535  * @return mixed|null|WP_Error Will return empty string if $term is not an object.
  1141  */
  1536  */
  1166  * the $args.
  1561  * the $args.
  1167  *
  1562  *
  1168  * The 'get_terms_orderby' filter passes the ORDER BY clause for the query
  1563  * The 'get_terms_orderby' filter passes the ORDER BY clause for the query
  1169  * along with the $args array.
  1564  * along with the $args array.
  1170  *
  1565  *
  1171  * The 'get_terms_fields' filter passes the fields for the SELECT query
       
  1172  * along with the $args array.
       
  1173  *
       
  1174  * The list of arguments that $args can contain, which will overwrite the defaults:
       
  1175  *
       
  1176  * orderby - Default is 'name'. Can be name, count, term_group, slug or nothing
       
  1177  * (will use term_id), Passing a custom value other than these will cause it to
       
  1178  * order based on the custom value.
       
  1179  *
       
  1180  * order - Default is ASC. Can use DESC.
       
  1181  *
       
  1182  * hide_empty - Default is true. Will not return empty terms, which means
       
  1183  * terms whose count is 0 according to the given taxonomy.
       
  1184  *
       
  1185  * exclude - Default is an empty array. An array, comma- or space-delimited string
       
  1186  * of term ids to exclude from the return array. If 'include' is non-empty,
       
  1187  * 'exclude' is ignored.
       
  1188  *
       
  1189  * exclude_tree - Default is an empty array. An array, comma- or space-delimited
       
  1190  * string of term ids to exclude from the return array, along with all of their
       
  1191  * descendant terms according to the primary taxonomy. If 'include' is non-empty,
       
  1192  * 'exclude_tree' is ignored.
       
  1193  *
       
  1194  * include - Default is an empty array. An array, comma- or space-delimited string
       
  1195  * of term ids to include in the return array.
       
  1196  *
       
  1197  * number - The maximum number of terms to return. Default is to return them all.
       
  1198  *
       
  1199  * offset - The number by which to offset the terms query.
       
  1200  *
       
  1201  * fields - Default is 'all', which returns an array of term objects.
       
  1202  * If 'fields' is 'ids' or 'names', returns an array of
       
  1203  * integers or strings, respectively.
       
  1204  *
       
  1205  * slug - Returns terms whose "slug" matches this value. Default is empty string.
       
  1206  *
       
  1207  * hierarchical - Whether to include terms that have non-empty descendants
       
  1208  * (even if 'hide_empty' is set to true).
       
  1209  *
       
  1210  * search - Returned terms' names will contain the value of 'search',
       
  1211  * case-insensitive. Default is an empty string.
       
  1212  *
       
  1213  * name__like - Returned terms' names will contain the value of 'name__like',
       
  1214  * case-insensitive. Default is empty string.
       
  1215  *
       
  1216  * description__like - Returned terms' descriptions will contain the value of
       
  1217  *  'description__like', case-insensitive. Default is empty string.
       
  1218  *
       
  1219  * The argument 'pad_counts', if set to true will include the quantity of a term's
       
  1220  * children in the quantity of each term's "count" object variable.
       
  1221  *
       
  1222  * The 'get' argument, if set to 'all' instead of its default empty string,
       
  1223  * returns terms regardless of ancestry or whether the terms are empty.
       
  1224  *
       
  1225  * The 'child_of' argument, when used, should be set to the integer of a term ID. Its default
       
  1226  * is 0. If set to a non-zero value, all returned terms will be descendants
       
  1227  * of that term according to the given taxonomy. Hence 'child_of' is set to 0
       
  1228  * if more than one taxonomy is passed in $taxonomies, because multiple taxonomies
       
  1229  * make term ancestry ambiguous.
       
  1230  *
       
  1231  * The 'parent' argument, when used, should be set to the integer of a term ID. Its default is
       
  1232  * the empty string '', which has a different meaning from the integer 0.
       
  1233  * If set to an integer value, all returned terms will have as an immediate
       
  1234  * ancestor the term whose ID is specified by that integer according to the given taxonomy.
       
  1235  * The 'parent' argument is different from 'child_of' in that a term X is considered a 'parent'
       
  1236  * of term Y only if term X is the father of term Y, not its grandfather or great-grandfather, etc.
       
  1237  *
       
  1238  * The 'cache_domain' argument enables a unique cache key to be produced when this query is stored
       
  1239  * in object cache. For instance, if you are using one of this function's filters to modify the
       
  1240  * query (such as 'terms_clauses'), setting 'cache_domain' to a unique value will not overwrite
       
  1241  * the cache for similar queries. Default value is 'core'.
       
  1242  *
       
  1243  * @package WordPress
       
  1244  * @subpackage Taxonomy
       
  1245  * @since 2.3.0
  1566  * @since 2.3.0
  1246  *
  1567  * @since 4.2.0 Introduced 'name' and 'childless' parameters.
  1247  * @uses $wpdb
  1568  *
  1248  * @uses wp_parse_args() Merges the defaults with those defined by $args and allows for strings.
  1569  * @global wpdb $wpdb WordPress database abstraction object.
  1249  *
  1570  *
  1250  * @param string|array $taxonomies Taxonomy name or list of Taxonomy names
  1571  * @param string|array $taxonomies Taxonomy name or list of Taxonomy names.
  1251  * @param string|array $args The values of what to search for when returning terms
  1572  * @param array|string $args {
  1252  * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies do not exist.
  1573  *     Optional. Array or string of arguments to get terms.
  1253  */
  1574  *
  1254 function get_terms($taxonomies, $args = '') {
  1575  *     @type string       $orderby           Field(s) to order terms by. Accepts term fields ('name', 'slug',
       
  1576  *                                           'term_group', 'term_id', 'id', 'description'), 'count' for term
       
  1577  *                                           taxonomy count, 'include' to match the 'order' of the $include param,
       
  1578  *                                           or 'none' to skip ORDER BY. Defaults to 'name'.
       
  1579  *     @type string       $order             Whether to order terms in ascending or descending order.
       
  1580  *                                           Accepts 'ASC' (ascending) or 'DESC' (descending).
       
  1581  *                                           Default 'ASC'.
       
  1582  *     @type bool|int     $hide_empty        Whether to hide terms not assigned to any posts. Accepts
       
  1583  *                                           1|true or 0|false. Default 1|true.
       
  1584  *     @type array|string $include           Array or comma/space-separated string of term ids to include.
       
  1585  *                                           Default empty array.
       
  1586  *     @type array|string $exclude           Array or comma/space-separated string of term ids to exclude.
       
  1587  *                                           If $include is non-empty, $exclude is ignored.
       
  1588  *                                           Default empty array.
       
  1589  *     @type array|string $exclude_tree      Array or comma/space-separated string of term ids to exclude
       
  1590  *                                           along with all of their descendant terms. If $include is
       
  1591  *                                           non-empty, $exclude_tree is ignored. Default empty array.
       
  1592  *     @type int|string   $number            Maximum number of terms to return. Accepts ''|0 (all) or any
       
  1593  *                                           positive number. Default ''|0 (all).
       
  1594  *     @type int          $offset            The number by which to offset the terms query. Default empty.
       
  1595  *     @type string       $fields            Term fields to query for. Accepts 'all' (returns an array of
       
  1596  *                                           term objects), 'ids' or 'names' (returns an array of integers
       
  1597  *                                           or strings, respectively. Default 'all'.
       
  1598  *     @type string|array $name              Optional. Name or array of names to return term(s) for. Default empty.
       
  1599  *     @type string|array $slug              Optional. Slug or array of slugs to return term(s) for. Default empty.
       
  1600  *     @type bool         $hierarchical      Whether to include terms that have non-empty descendants (even
       
  1601  *                                           if $hide_empty is set to true). Default true.
       
  1602  *     @type string       $search            Search criteria to match terms. Will be SQL-formatted with
       
  1603  *                                           wildcards before and after. Default empty.
       
  1604  *     @type string       $name__like        Retrieve terms with criteria by which a term is LIKE $name__like.
       
  1605  *                                           Default empty.
       
  1606  *     @type string       $description__like Retrieve terms where the description is LIKE $description__like.
       
  1607  *                                           Default empty.
       
  1608  *     @type bool         $pad_counts        Whether to pad the quantity of a term's children in the quantity
       
  1609  *                                           of each term's "count" object variable. Default false.
       
  1610  *     @type string       $get               Whether to return terms regardless of ancestry or whether the terms
       
  1611  *                                           are empty. Accepts 'all' or empty (disabled). Default empty.
       
  1612  *     @type int          $child_of          Term ID to retrieve child terms of. If multiple taxonomies
       
  1613  *                                           are passed, $child_of is ignored. Default 0.
       
  1614  *     @type int|string   $parent            Parent term ID to retrieve direct-child terms of. Default empty.
       
  1615  *     @type bool         $childless         True to limit results to terms that have no children. This parameter has
       
  1616  *                                           no effect on non-hierarchical taxonomies. Default false.
       
  1617  *     @type string       $cache_domain      Unique cache key to be produced when this query is stored in an
       
  1618  *                                           object cache. Default is 'core'.
       
  1619  * }
       
  1620  * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies
       
  1621  *                        do not exist.
       
  1622  */
       
  1623 function get_terms( $taxonomies, $args = '' ) {
  1255 	global $wpdb;
  1624 	global $wpdb;
  1256 	$empty_array = array();
  1625 	$empty_array = array();
  1257 
  1626 
  1258 	$single_taxonomy = ! is_array( $taxonomies ) || 1 === count( $taxonomies );
  1627 	$single_taxonomy = ! is_array( $taxonomies ) || 1 === count( $taxonomies );
  1259 	if ( ! is_array( $taxonomies ) )
  1628 	if ( ! is_array( $taxonomies ) ) {
  1260 		$taxonomies = array( $taxonomies );
  1629 		$taxonomies = array( $taxonomies );
       
  1630 	}
  1261 
  1631 
  1262 	foreach ( $taxonomies as $taxonomy ) {
  1632 	foreach ( $taxonomies as $taxonomy ) {
  1263 		if ( ! taxonomy_exists($taxonomy) ) {
  1633 		if ( ! taxonomy_exists($taxonomy) ) {
  1264 			$error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
  1634 			$error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
  1265 			return $error;
  1635 			return $error;
  1266 		}
  1636 		}
  1267 	}
  1637 	}
  1268 
  1638 
  1269 	$defaults = array('orderby' => 'name', 'order' => 'ASC',
  1639 	$defaults = array('orderby' => 'name', 'order' => 'ASC',
  1270 		'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(),
  1640 		'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(),
  1271 		'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '',
  1641 		'number' => '', 'fields' => 'all', 'name' => '', 'slug' => '', 'parent' => '', 'childless' => false,
  1272 		'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'description__like' => '',
  1642 		'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'description__like' => '',
  1273 		'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' );
  1643 		'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' );
  1274 	$args = wp_parse_args( $args, $defaults );
  1644 	$args = wp_parse_args( $args, $defaults );
  1275 	$args['number'] = absint( $args['number'] );
  1645 	$args['number'] = absint( $args['number'] );
  1276 	$args['offset'] = absint( $args['offset'] );
  1646 	$args['offset'] = absint( $args['offset'] );
  1277 	if ( !$single_taxonomy || ! is_taxonomy_hierarchical( reset( $taxonomies ) ) ||
  1647 
  1278 		'' !== $args['parent'] ) {
  1648 	// Save queries by not crawling the tree in the case of multiple taxes or a flat tax.
  1279 		$args['child_of'] = 0;
  1649 	$has_hierarchical_tax = false;
       
  1650 	foreach ( $taxonomies as $_tax ) {
       
  1651 		if ( is_taxonomy_hierarchical( $_tax ) ) {
       
  1652 			$has_hierarchical_tax = true;
       
  1653 		}
       
  1654 	}
       
  1655 
       
  1656 	if ( ! $has_hierarchical_tax ) {
  1280 		$args['hierarchical'] = false;
  1657 		$args['hierarchical'] = false;
  1281 		$args['pad_counts'] = false;
  1658 		$args['pad_counts'] = false;
  1282 	}
  1659 	}
  1283 
  1660 
       
  1661 	// 'parent' overrides 'child_of'.
       
  1662 	if ( 0 < intval( $args['parent'] ) ) {
       
  1663 		$args['child_of'] = false;
       
  1664 	}
       
  1665 
  1284 	if ( 'all' == $args['get'] ) {
  1666 	if ( 'all' == $args['get'] ) {
       
  1667 		$args['childless'] = false;
  1285 		$args['child_of'] = 0;
  1668 		$args['child_of'] = 0;
  1286 		$args['hide_empty'] = 0;
  1669 		$args['hide_empty'] = 0;
  1287 		$args['hierarchical'] = false;
  1670 		$args['hierarchical'] = false;
  1288 		$args['pad_counts'] = false;
  1671 		$args['pad_counts'] = false;
  1289 	}
  1672 	}
  1290 
  1673 
       
  1674 	/**
       
  1675 	 * Filter the terms query arguments.
       
  1676 	 *
       
  1677 	 * @since 3.1.0
       
  1678 	 *
       
  1679 	 * @param array $args       An array of arguments.
       
  1680 	 * @param array $taxonomies An array of taxonomies.
       
  1681 	 */
  1291 	$args = apply_filters( 'get_terms_args', $args, $taxonomies );
  1682 	$args = apply_filters( 'get_terms_args', $args, $taxonomies );
  1292 
  1683 
  1293 	extract($args, EXTR_SKIP);
  1684 	// Avoid the query if the queried parent/child_of term has no descendants.
       
  1685 	$child_of = $args['child_of'];
       
  1686 	$parent   = $args['parent'];
  1294 
  1687 
  1295 	if ( $child_of ) {
  1688 	if ( $child_of ) {
  1296 		$hierarchy = _get_term_hierarchy( reset( $taxonomies ) );
  1689 		$_parent = $child_of;
  1297 		if ( ! isset( $hierarchy[ $child_of ] ) )
  1690 	} elseif ( $parent ) {
       
  1691 		$_parent = $parent;
       
  1692 	} else {
       
  1693 		$_parent = false;
       
  1694 	}
       
  1695 
       
  1696 	if ( $_parent ) {
       
  1697 		$in_hierarchy = false;
       
  1698 		foreach ( $taxonomies as $_tax ) {
       
  1699 			$hierarchy = _get_term_hierarchy( $_tax );
       
  1700 
       
  1701 			if ( isset( $hierarchy[ $_parent ] ) ) {
       
  1702 				$in_hierarchy = true;
       
  1703 			}
       
  1704 		}
       
  1705 
       
  1706 		if ( ! $in_hierarchy ) {
  1298 			return $empty_array;
  1707 			return $empty_array;
  1299 	}
  1708 		}
  1300 
       
  1301 	if ( $parent ) {
       
  1302 		$hierarchy = _get_term_hierarchy( reset( $taxonomies ) );
       
  1303 		if ( ! isset( $hierarchy[ $parent ] ) )
       
  1304 			return $empty_array;
       
  1305 	}
  1709 	}
  1306 
  1710 
  1307 	// $args can be whatever, only use the args defined in defaults to compute the key
  1711 	// $args can be whatever, only use the args defined in defaults to compute the key
  1308 	$filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
  1712 	$filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
  1309 	$key = md5( serialize( compact(array_keys($defaults)) ) . serialize( $taxonomies ) . $filter_key );
  1713 	$key = md5( serialize( wp_array_slice_assoc( $args, array_keys( $defaults ) ) ) . serialize( $taxonomies ) . $filter_key );
  1310 	$last_changed = wp_cache_get( 'last_changed', 'terms' );
  1714 	$last_changed = wp_cache_get( 'last_changed', 'terms' );
  1311 	if ( ! $last_changed ) {
  1715 	if ( ! $last_changed ) {
  1312 		$last_changed = microtime();
  1716 		$last_changed = microtime();
  1313 		wp_cache_set( 'last_changed', $last_changed, 'terms' );
  1717 		wp_cache_set( 'last_changed', $last_changed, 'terms' );
  1314 	}
  1718 	}
  1315 	$cache_key = "get_terms:$key:$last_changed";
  1719 	$cache_key = "get_terms:$key:$last_changed";
  1316 	$cache = wp_cache_get( $cache_key, 'terms' );
  1720 	$cache = wp_cache_get( $cache_key, 'terms' );
  1317 	if ( false !== $cache ) {
  1721 	if ( false !== $cache ) {
  1318 		$cache = apply_filters('get_terms', $cache, $taxonomies, $args);
  1722 
       
  1723 		/**
       
  1724 		 * Filter the given taxonomy's terms cache.
       
  1725 		 *
       
  1726 		 * @since 2.3.0
       
  1727 		 *
       
  1728 		 * @param array $cache      Cached array of terms for the given taxonomy.
       
  1729 		 * @param array $taxonomies An array of taxonomies.
       
  1730 		 * @param array $args       An array of arguments to get terms.
       
  1731 		 */
       
  1732 		$cache = apply_filters( 'get_terms', $cache, $taxonomies, $args );
  1319 		return $cache;
  1733 		return $cache;
  1320 	}
  1734 	}
  1321 
  1735 
  1322 	$_orderby = strtolower($orderby);
  1736 	$_orderby = strtolower( $args['orderby'] );
  1323 	if ( 'count' == $_orderby )
  1737 	if ( 'count' == $_orderby ) {
  1324 		$orderby = 'tt.count';
  1738 		$orderby = 'tt.count';
  1325 	else if ( 'name' == $_orderby )
  1739 	} elseif ( 'name' == $_orderby ) {
  1326 		$orderby = 't.name';
  1740 		$orderby = 't.name';
  1327 	else if ( 'slug' == $_orderby )
  1741 	} elseif ( 'slug' == $_orderby ) {
  1328 		$orderby = 't.slug';
  1742 		$orderby = 't.slug';
  1329 	else if ( 'term_group' == $_orderby )
  1743 	} elseif ( 'include' == $_orderby && ! empty( $args['include'] ) ) {
       
  1744 		$include = implode( ',', array_map( 'absint', $args['include'] ) );
       
  1745 		$orderby = "FIELD( t.term_id, $include )";
       
  1746 	} elseif ( 'term_group' == $_orderby ) {
  1330 		$orderby = 't.term_group';
  1747 		$orderby = 't.term_group';
  1331 	else if ( 'none' == $_orderby )
  1748 	} elseif ( 'description' == $_orderby ) {
       
  1749 		$orderby = 'tt.description';
       
  1750 	} elseif ( 'none' == $_orderby ) {
  1332 		$orderby = '';
  1751 		$orderby = '';
  1333 	elseif ( empty($_orderby) || 'id' == $_orderby )
  1752 	} elseif ( empty($_orderby) || 'id' == $_orderby ) {
  1334 		$orderby = 't.term_id';
  1753 		$orderby = 't.term_id';
  1335 	else
  1754 	} else {
  1336 		$orderby = 't.name';
  1755 		$orderby = 't.name';
  1337 
  1756 	}
       
  1757 	/**
       
  1758 	 * Filter the ORDERBY clause of the terms query.
       
  1759 	 *
       
  1760 	 * @since 2.8.0
       
  1761 	 *
       
  1762 	 * @param string $orderby    ORDERBY clause of the terms query.
       
  1763 	 * @param array  $args       An array of terms query arguments.
       
  1764 	 * @param array  $taxonomies An array of taxonomies.
       
  1765 	 */
  1338 	$orderby = apply_filters( 'get_terms_orderby', $orderby, $args, $taxonomies );
  1766 	$orderby = apply_filters( 'get_terms_orderby', $orderby, $args, $taxonomies );
  1339 
  1767 
  1340 	if ( !empty($orderby) )
  1768 	$order = strtoupper( $args['order'] );
       
  1769 	if ( ! empty( $orderby ) ) {
  1341 		$orderby = "ORDER BY $orderby";
  1770 		$orderby = "ORDER BY $orderby";
  1342 	else
  1771 	} else {
  1343 		$order = '';
  1772 		$order = '';
  1344 
  1773 	}
  1345 	$order = strtoupper( $order );
  1774 
  1346 	if ( '' !== $order && !in_array( $order, array( 'ASC', 'DESC' ) ) )
  1775 	if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) ) {
  1347 		$order = 'ASC';
  1776 		$order = 'ASC';
       
  1777 	}
  1348 
  1778 
  1349 	$where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')";
  1779 	$where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')";
       
  1780 
       
  1781 	$exclude = $args['exclude'];
       
  1782 	$exclude_tree = $args['exclude_tree'];
       
  1783 	$include = $args['include'];
       
  1784 
  1350 	$inclusions = '';
  1785 	$inclusions = '';
  1351 	if ( ! empty( $include ) ) {
  1786 	if ( ! empty( $include ) ) {
  1352 		$exclude = '';
  1787 		$exclude = '';
  1353 		$exclude_tree = '';
  1788 		$exclude_tree = '';
  1354 		$inclusions = implode( ',', wp_parse_id_list( $include ) );
  1789 		$inclusions = implode( ',', wp_parse_id_list( $include ) );
  1357 	if ( ! empty( $inclusions ) ) {
  1792 	if ( ! empty( $inclusions ) ) {
  1358 		$inclusions = ' AND t.term_id IN ( ' . $inclusions . ' )';
  1793 		$inclusions = ' AND t.term_id IN ( ' . $inclusions . ' )';
  1359 		$where .= $inclusions;
  1794 		$where .= $inclusions;
  1360 	}
  1795 	}
  1361 
  1796 
  1362 	$exclusions = '';
  1797 	$exclusions = array();
  1363 	if ( ! empty( $exclude_tree ) ) {
  1798 	if ( ! empty( $exclude_tree ) ) {
  1364 		$exclude_tree = wp_parse_id_list( $exclude_tree );
  1799 		$exclude_tree = wp_parse_id_list( $exclude_tree );
  1365 		$excluded_children = $exclude_tree;
  1800 		$excluded_children = $exclude_tree;
  1366 		foreach ( $exclude_tree as $extrunk ) {
  1801 		foreach ( $exclude_tree as $extrunk ) {
  1367 			$excluded_children = array_merge(
  1802 			$excluded_children = array_merge(
  1368 				$excluded_children,
  1803 				$excluded_children,
  1369 				(array) get_terms( $taxonomies[0], array( 'child_of' => intval( $extrunk ), 'fields' => 'ids', 'hide_empty' => 0 ) )
  1804 				(array) get_terms( $taxonomies[0], array( 'child_of' => intval( $extrunk ), 'fields' => 'ids', 'hide_empty' => 0 ) )
  1370 			);
  1805 			);
  1371 		}
  1806 		}
  1372 		$exclusions = implode( ',', array_map( 'intval', $excluded_children ) );
  1807 		$exclusions = array_merge( $excluded_children, $exclusions );
  1373 	}
  1808 	}
  1374 
  1809 
  1375 	if ( ! empty( $exclude ) ) {
  1810 	if ( ! empty( $exclude ) ) {
  1376 		$exterms = wp_parse_id_list( $exclude );
  1811 		$exclusions = array_merge( wp_parse_id_list( $exclude ), $exclusions );
  1377 		if ( empty( $exclusions ) )
  1812 	}
  1378 			$exclusions = implode( ',', $exterms );
  1813 
  1379 		else
  1814 	// 'childless' terms are those without an entry in the flattened term hierarchy.
  1380 			$exclusions .= ', ' . implode( ',', $exterms );
  1815 	$childless = (bool) $args['childless'];
  1381 	}
  1816 	if ( $childless ) {
  1382 
  1817 		foreach ( $taxonomies as $_tax ) {
  1383 	if ( ! empty( $exclusions ) )
  1818 			$term_hierarchy = _get_term_hierarchy( $_tax );
  1384 		$exclusions = ' AND t.term_id NOT IN (' . $exclusions . ')';
  1819 			$exclusions = array_merge( array_keys( $term_hierarchy ), $exclusions );
  1385 
  1820 		}
       
  1821 	}
       
  1822 
       
  1823 	if ( ! empty( $exclusions ) ) {
       
  1824 		$exclusions = ' AND t.term_id NOT IN (' . implode( ',', array_map( 'intval', $exclusions ) ) . ')';
       
  1825 	} else {
       
  1826 		$exclusions = '';
       
  1827 	}
       
  1828 
       
  1829 	/**
       
  1830 	 * Filter the terms to exclude from the terms query.
       
  1831 	 *
       
  1832 	 * @since 2.3.0
       
  1833 	 *
       
  1834 	 * @param string $exclusions NOT IN clause of the terms query.
       
  1835 	 * @param array  $args       An array of terms query arguments.
       
  1836 	 * @param array  $taxonomies An array of taxonomies.
       
  1837 	 */
  1386 	$exclusions = apply_filters( 'list_terms_exclusions', $exclusions, $args, $taxonomies );
  1838 	$exclusions = apply_filters( 'list_terms_exclusions', $exclusions, $args, $taxonomies );
  1387 
  1839 
  1388 	if ( ! empty( $exclusions ) )
  1840 	if ( ! empty( $exclusions ) ) {
  1389 		$where .= $exclusions;
  1841 		$where .= $exclusions;
  1390 
  1842 	}
  1391 	if ( !empty($slug) ) {
  1843 
  1392 		$slug = sanitize_title($slug);
  1844 	if ( ! empty( $args['name'] ) ) {
  1393 		$where .= " AND t.slug = '$slug'";
  1845 		if ( is_array( $args['name'] ) ) {
  1394 	}
  1846 			$name = array_map( 'sanitize_text_field', $args['name'] );
  1395 
  1847 			$where .= " AND t.name IN ('" . implode( "', '", array_map( 'esc_sql', $name ) ) . "')";
  1396 	if ( !empty($name__like) ) {
  1848 		} else {
  1397 		$name__like = like_escape( $name__like );
  1849 			$name = sanitize_text_field( $args['name'] );
  1398 		$where .= $wpdb->prepare( " AND t.name LIKE %s", '%' . $name__like . '%' );
  1850 			$where .= $wpdb->prepare( " AND t.name = %s", $name );
  1399 	}
  1851 		}
  1400 
  1852 	}
  1401 	if ( ! empty( $description__like ) ) {
  1853 
  1402 		$description__like = like_escape( $description__like );
  1854 	if ( ! empty( $args['slug'] ) ) {
  1403 		$where .= $wpdb->prepare( " AND tt.description LIKE %s", '%' . $description__like . '%' );
  1855 		if ( is_array( $args['slug'] ) ) {
       
  1856 			$slug = array_map( 'sanitize_title', $args['slug'] );
       
  1857 			$where .= " AND t.slug IN ('" . implode( "', '", $slug ) . "')";
       
  1858 		} else {
       
  1859 			$slug = sanitize_title( $args['slug'] );
       
  1860 			$where .= " AND t.slug = '$slug'";
       
  1861 		}
       
  1862 	}
       
  1863 
       
  1864 	if ( ! empty( $args['name__like'] ) ) {
       
  1865 		$where .= $wpdb->prepare( " AND t.name LIKE %s", '%' . $wpdb->esc_like( $args['name__like'] ) . '%' );
       
  1866 	}
       
  1867 
       
  1868 	if ( ! empty( $args['description__like'] ) ) {
       
  1869 		$where .= $wpdb->prepare( " AND tt.description LIKE %s", '%' . $wpdb->esc_like( $args['description__like'] ) . '%' );
  1404 	}
  1870 	}
  1405 
  1871 
  1406 	if ( '' !== $parent ) {
  1872 	if ( '' !== $parent ) {
  1407 		$parent = (int) $parent;
  1873 		$parent = (int) $parent;
  1408 		$where .= " AND tt.parent = '$parent'";
  1874 		$where .= " AND tt.parent = '$parent'";
  1409 	}
  1875 	}
  1410 
  1876 
  1411 	if ( 'count' == $fields )
  1877 	$hierarchical = $args['hierarchical'];
       
  1878 	if ( 'count' == $args['fields'] ) {
  1412 		$hierarchical = false;
  1879 		$hierarchical = false;
  1413 
  1880 	}
  1414 	if ( $hide_empty && !$hierarchical )
  1881 	if ( $args['hide_empty'] && !$hierarchical ) {
  1415 		$where .= ' AND tt.count > 0';
  1882 		$where .= ' AND tt.count > 0';
       
  1883 	}
       
  1884 
       
  1885 	$number = $args['number'];
       
  1886 	$offset = $args['offset'];
  1416 
  1887 
  1417 	// don't limit the query results when we have to descend the family tree
  1888 	// don't limit the query results when we have to descend the family tree
  1418 	if ( $number && ! $hierarchical && ! $child_of && '' === $parent ) {
  1889 	if ( $number && ! $hierarchical && ! $child_of && '' === $parent ) {
  1419 		if ( $offset )
  1890 		if ( $offset ) {
  1420 			$limits = 'LIMIT ' . $offset . ',' . $number;
  1891 			$limits = 'LIMIT ' . $offset . ',' . $number;
  1421 		else
  1892 		} else {
  1422 			$limits = 'LIMIT ' . $number;
  1893 			$limits = 'LIMIT ' . $number;
       
  1894 		}
  1423 	} else {
  1895 	} else {
  1424 		$limits = '';
  1896 		$limits = '';
  1425 	}
  1897 	}
  1426 
  1898 
  1427 	if ( ! empty( $search ) ) {
  1899 	if ( ! empty( $args['search'] ) ) {
  1428 		$search = like_escape( $search );
  1900 		$like = '%' . $wpdb->esc_like( $args['search'] ) . '%';
  1429 		$where .= $wpdb->prepare( ' AND ((t.name LIKE %s) OR (t.slug LIKE %s))', '%' . $search . '%', '%' . $search . '%' );
  1901 		$where .= $wpdb->prepare( ' AND ((t.name LIKE %s) OR (t.slug LIKE %s))', $like, $like );
  1430 	}
  1902 	}
  1431 
  1903 
  1432 	$selects = array();
  1904 	$selects = array();
  1433 	switch ( $fields ) {
  1905 	switch ( $args['fields'] ) {
  1434 		case 'all':
  1906 		case 'all':
  1435 			$selects = array( 't.*', 'tt.*' );
  1907 			$selects = array( 't.*', 'tt.*' );
  1436 			break;
  1908 			break;
  1437 		case 'ids':
  1909 		case 'ids':
  1438 		case 'id=>parent':
  1910 		case 'id=>parent':
  1439 			$selects = array( 't.term_id', 'tt.parent', 'tt.count' );
  1911 			$selects = array( 't.term_id', 'tt.parent', 'tt.count', 'tt.taxonomy' );
  1440 			break;
  1912 			break;
  1441 		case 'names':
  1913 		case 'names':
  1442 			$selects = array( 't.term_id', 'tt.parent', 'tt.count', 't.name' );
  1914 			$selects = array( 't.term_id', 'tt.parent', 'tt.count', 't.name', 'tt.taxonomy' );
  1443 			break;
  1915 			break;
  1444 		case 'count':
  1916 		case 'count':
  1445 			$orderby = '';
  1917 			$orderby = '';
  1446 			$order = '';
  1918 			$order = '';
  1447 			$selects = array( 'COUNT(*)' );
  1919 			$selects = array( 'COUNT(*)' );
  1448 			break;
  1920 			break;
  1449 		case 'id=>name':
  1921 		case 'id=>name':
  1450 			$selects = array( 't.term_id', 't.name' );
  1922 			$selects = array( 't.term_id', 't.name', 'tt.count', 'tt.taxonomy' );
  1451 			break;
  1923 			break;
  1452 		case 'id=>slug':
  1924 		case 'id=>slug':
  1453 			$selects = array( 't.term_id', 't.slug' );
  1925 			$selects = array( 't.term_id', 't.slug', 'tt.count', 'tt.taxonomy' );
  1454 			break;
  1926 			break;
  1455 	}
  1927 	}
  1456 
  1928 
  1457 	$_fields = $fields;
  1929 	$_fields = $args['fields'];
  1458 
  1930 
       
  1931 	/**
       
  1932 	 * Filter the fields to select in the terms query.
       
  1933 	 *
       
  1934 	 * Field lists modified using this filter will only modify the term fields returned
       
  1935 	 * by the function when the `$fields` parameter set to 'count' or 'all'. In all other
       
  1936 	 * cases, the term fields in the results array will be determined by the `$fields`
       
  1937 	 * parameter alone.
       
  1938 	 *
       
  1939 	 * Use of this filter can result in unpredictable behavior, and is not recommended.
       
  1940 	 *
       
  1941 	 * @since 2.8.0
       
  1942 	 *
       
  1943 	 * @param array $selects    An array of fields to select for the terms query.
       
  1944 	 * @param array $args       An array of term query arguments.
       
  1945 	 * @param array $taxonomies An array of taxonomies.
       
  1946 	 */
  1459 	$fields = implode( ', ', apply_filters( 'get_terms_fields', $selects, $args, $taxonomies ) );
  1947 	$fields = implode( ', ', apply_filters( 'get_terms_fields', $selects, $args, $taxonomies ) );
  1460 
  1948 
  1461 	$join = "INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
  1949 	$join = "INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
  1462 
  1950 
  1463 	$pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' );
  1951 	$pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' );
       
  1952 
       
  1953 	/**
       
  1954 	 * Filter the terms query SQL clauses.
       
  1955 	 *
       
  1956 	 * @since 3.1.0
       
  1957 	 *
       
  1958 	 * @param array $pieces     Terms query SQL clauses.
       
  1959 	 * @param array $taxonomies An array of taxonomies.
       
  1960 	 * @param array $args       An array of terms query arguments.
       
  1961 	 */
  1464 	$clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args );
  1962 	$clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args );
  1465 	foreach ( $pieces as $piece )
  1963 	$fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
  1466 		$$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
  1964 	$join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
       
  1965 	$where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
       
  1966 	$orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : '';
       
  1967 	$order = isset( $clauses[ 'order' ] ) ? $clauses[ 'order' ] : '';
       
  1968 	$limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : '';
  1467 
  1969 
  1468 	$query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits";
  1970 	$query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits";
  1469 
  1971 
  1470 	$fields = $_fields;
  1972 	if ( 'count' == $_fields ) {
  1471 
       
  1472 	if ( 'count' == $fields ) {
       
  1473 		$term_count = $wpdb->get_var($query);
  1973 		$term_count = $wpdb->get_var($query);
  1474 		return $term_count;
  1974 		return $term_count;
  1475 	}
  1975 	}
  1476 
  1976 
  1477 	$terms = $wpdb->get_results($query);
  1977 	$terms = $wpdb->get_results($query);
  1478 	if ( 'all' == $fields ) {
  1978 	if ( 'all' == $_fields ) {
  1479 		update_term_cache($terms);
  1979 		update_term_cache( $terms );
  1480 	}
  1980 	}
  1481 
  1981 
  1482 	if ( empty($terms) ) {
  1982 	if ( empty($terms) ) {
  1483 		wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS );
  1983 		wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS );
  1484 		$terms = apply_filters('get_terms', array(), $taxonomies, $args);
  1984 
       
  1985 		/** This filter is documented in wp-includes/taxonomy.php */
       
  1986 		$terms = apply_filters( 'get_terms', array(), $taxonomies, $args );
  1485 		return $terms;
  1987 		return $terms;
  1486 	}
  1988 	}
  1487 
  1989 
  1488 	if ( $child_of ) {
  1990 	if ( $child_of ) {
  1489 		$children = _get_term_hierarchy( reset( $taxonomies ) );
  1991 		foreach ( $taxonomies as $_tax ) {
  1490 		if ( ! empty( $children ) )
  1992 			$children = _get_term_hierarchy( $_tax );
  1491 			$terms = _get_term_children( $child_of, $terms, reset( $taxonomies ) );
  1993 			if ( ! empty( $children ) ) {
       
  1994 				$terms = _get_term_children( $child_of, $terms, $_tax );
       
  1995 			}
       
  1996 		}
  1492 	}
  1997 	}
  1493 
  1998 
  1494 	// Update term counts to include children.
  1999 	// Update term counts to include children.
  1495 	if ( $pad_counts && 'all' == $fields )
  2000 	if ( $args['pad_counts'] && 'all' == $_fields ) {
  1496 		_pad_term_counts( $terms, reset( $taxonomies ) );
  2001 		foreach ( $taxonomies as $_tax ) {
       
  2002 			_pad_term_counts( $terms, $_tax );
       
  2003 		}
       
  2004 	}
  1497 
  2005 
  1498 	// Make sure we show empty categories that have children.
  2006 	// Make sure we show empty categories that have children.
  1499 	if ( $hierarchical && $hide_empty && is_array( $terms ) ) {
  2007 	if ( $hierarchical && $args['hide_empty'] && is_array( $terms ) ) {
  1500 		foreach ( $terms as $k => $term ) {
  2008 		foreach ( $terms as $k => $term ) {
  1501 			if ( ! $term->count ) {
  2009 			if ( ! $term->count ) {
  1502 				$children = _get_term_children( $term->term_id, $terms, reset( $taxonomies ) );
  2010 				$children = get_term_children( $term->term_id, $term->taxonomy );
  1503 				if ( is_array( $children ) )
  2011 				if ( is_array( $children ) ) {
  1504 					foreach ( $children as $child )
  2012 					foreach ( $children as $child_id ) {
  1505 						if ( $child->count )
  2013 						$child = get_term( $child_id, $term->taxonomy );
       
  2014 						if ( $child->count ) {
  1506 							continue 2;
  2015 							continue 2;
       
  2016 						}
       
  2017 					}
       
  2018 				}
  1507 
  2019 
  1508 				// It really is empty
  2020 				// It really is empty
  1509 				unset($terms[$k]);
  2021 				unset($terms[$k]);
  1510 			}
  2022 			}
  1511 		}
  2023 		}
  1512 	}
  2024 	}
  1513 	reset( $terms );
       
  1514 
  2025 
  1515 	$_terms = array();
  2026 	$_terms = array();
  1516 	if ( 'id=>parent' == $fields ) {
  2027 	if ( 'id=>parent' == $_fields ) {
  1517 		while ( $term = array_shift( $terms ) )
  2028 		foreach ( $terms as $term ) {
  1518 			$_terms[$term->term_id] = $term->parent;
  2029 			$_terms[ $term->term_id ] = $term->parent;
  1519 	} elseif ( 'ids' == $fields ) {
  2030 		}
  1520 		while ( $term = array_shift( $terms ) )
  2031 	} elseif ( 'ids' == $_fields ) {
       
  2032 		foreach ( $terms as $term ) {
  1521 			$_terms[] = $term->term_id;
  2033 			$_terms[] = $term->term_id;
  1522 	} elseif ( 'names' == $fields ) {
  2034 		}
  1523 		while ( $term = array_shift( $terms ) )
  2035 	} elseif ( 'names' == $_fields ) {
       
  2036 		foreach ( $terms as $term ) {
  1524 			$_terms[] = $term->name;
  2037 			$_terms[] = $term->name;
  1525 	} elseif ( 'id=>name' == $fields ) {
  2038 		}
  1526 		while ( $term = array_shift( $terms ) )
  2039 	} elseif ( 'id=>name' == $_fields ) {
  1527 			$_terms[$term->term_id] = $term->name;
  2040 		foreach ( $terms as $term ) {
  1528 	} elseif ( 'id=>slug' == $fields ) {
  2041 			$_terms[ $term->term_id ] = $term->name;
  1529 		while ( $term = array_shift( $terms ) )
  2042 		}
  1530 			$_terms[$term->term_id] = $term->slug;
  2043 	} elseif ( 'id=>slug' == $_fields ) {
  1531 	}
  2044 		foreach ( $terms as $term ) {
  1532 
  2045 			$_terms[ $term->term_id ] = $term->slug;
  1533 	if ( ! empty( $_terms ) )
  2046 		}
       
  2047 	}
       
  2048 
       
  2049 	if ( ! empty( $_terms ) ) {
  1534 		$terms = $_terms;
  2050 		$terms = $_terms;
  1535 
  2051 	}
  1536 	if ( $number && is_array( $terms ) && count( $terms ) > $number )
  2052 
       
  2053 	if ( $number && is_array( $terms ) && count( $terms ) > $number ) {
  1537 		$terms = array_slice( $terms, $offset, $number );
  2054 		$terms = array_slice( $terms, $offset, $number );
       
  2055 	}
  1538 
  2056 
  1539 	wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS );
  2057 	wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS );
  1540 
  2058 
       
  2059 	/** This filter is documented in wp-includes/taxonomy */
  1541 	$terms = apply_filters( 'get_terms', $terms, $taxonomies, $args );
  2060 	$terms = apply_filters( 'get_terms', $terms, $taxonomies, $args );
  1542 	return $terms;
  2061 	return $terms;
  1543 }
  2062 }
  1544 
  2063 
  1545 /**
  2064 /**
  1546  * Check if Term exists.
  2065  * Check if Term exists.
  1547  *
  2066  *
  1548  * Formerly is_term(), introduced in 2.3.0.
  2067  * Formerly is_term(), introduced in 2.3.0.
  1549  *
  2068  *
  1550  * @package WordPress
       
  1551  * @subpackage Taxonomy
       
  1552  * @since 3.0.0
  2069  * @since 3.0.0
  1553  *
  2070  *
  1554  * @uses $wpdb
  2071  * @global wpdb $wpdb WordPress database abstraction object.
  1555  *
  2072  *
  1556  * @param int|string $term The term to check
  2073  * @param int|string $term The term to check
  1557  * @param string $taxonomy The taxonomy name to use
  2074  * @param string $taxonomy The taxonomy name to use
  1558  * @param int $parent ID of parent term under which to confine the exists search.
  2075  * @param int $parent Optional. ID of parent term under which to confine the exists search.
  1559  * @return mixed Returns 0 if the term does not exist. Returns the term ID if no taxonomy is specified
  2076  * @return mixed Returns null if the term does not exist. Returns the term ID
  1560  * 	and the term ID exists. Returns an array of the term ID and the taxonomy if the pairing exists.
  2077  *               if no taxonomy is specified and the term ID exists. Returns
  1561  */
  2078  *               an array of the term ID and the term taxonomy ID the taxonomy
  1562 function term_exists($term, $taxonomy = '', $parent = 0) {
  2079  *               is specified and the pairing exists.
       
  2080  */
       
  2081 function term_exists( $term, $taxonomy = '', $parent = null ) {
  1563 	global $wpdb;
  2082 	global $wpdb;
  1564 
  2083 
  1565 	$select = "SELECT term_id FROM $wpdb->terms as t WHERE ";
  2084 	$select = "SELECT term_id FROM $wpdb->terms as t WHERE ";
  1566 	$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 ";
  2085 	$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 ";
  1567 
  2086 
  1574 		else
  2093 		else
  1575 			return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
  2094 			return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
  1576 	}
  2095 	}
  1577 
  2096 
  1578 	$term = trim( wp_unslash( $term ) );
  2097 	$term = trim( wp_unslash( $term ) );
  1579 
  2098 	$slug = sanitize_title( $term );
  1580 	if ( '' === $slug = sanitize_title($term) )
       
  1581 		return 0;
       
  1582 
  2099 
  1583 	$where = 't.slug = %s';
  2100 	$where = 't.slug = %s';
  1584 	$else_where = 't.name = %s';
  2101 	$else_where = 't.name = %s';
  1585 	$where_fields = array($slug);
  2102 	$where_fields = array($slug);
  1586 	$else_where_fields = array($term);
  2103 	$else_where_fields = array($term);
       
  2104 	$orderby = 'ORDER BY t.term_id ASC';
       
  2105 	$limit = 'LIMIT 1';
  1587 	if ( !empty($taxonomy) ) {
  2106 	if ( !empty($taxonomy) ) {
  1588 		$parent = (int) $parent;
  2107 		if ( is_numeric( $parent ) ) {
  1589 		if ( $parent > 0 ) {
  2108 			$parent = (int) $parent;
  1590 			$where_fields[] = $parent;
  2109 			$where_fields[] = $parent;
  1591 			$else_where_fields[] = $parent;
  2110 			$else_where_fields[] = $parent;
  1592 			$where .= ' AND tt.parent = %d';
  2111 			$where .= ' AND tt.parent = %d';
  1593 			$else_where .= ' AND tt.parent = %d';
  2112 			$else_where .= ' AND tt.parent = %d';
  1594 		}
  2113 		}
  1595 
  2114 
  1596 		$where_fields[] = $taxonomy;
  2115 		$where_fields[] = $taxonomy;
  1597 		$else_where_fields[] = $taxonomy;
  2116 		$else_where_fields[] = $taxonomy;
  1598 
  2117 
  1599 		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", $where_fields), ARRAY_A) )
  2118 		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) )
  1600 			return $result;
  2119 			return $result;
  1601 
  2120 
  1602 		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", $else_where_fields), ARRAY_A);
  2121 		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);
  1603 	}
  2122 	}
  1604 
  2123 
  1605 	if ( $result = $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $where", $where_fields) ) )
  2124 	if ( $result = $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $where $orderby $limit", $where_fields) ) )
  1606 		return $result;
  2125 		return $result;
  1607 
  2126 
  1608 	return $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $else_where", $else_where_fields) );
  2127 	return $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $else_where $orderby $limit", $else_where_fields) );
  1609 }
  2128 }
  1610 
  2129 
  1611 /**
  2130 /**
  1612  * Check if a term is an ancestor of another term.
  2131  * Check if a term is an ancestor of another term.
  1613  *
  2132  *
  1641  * this function will sanitize <strong>all</strong> fields. The context is based
  2160  * this function will sanitize <strong>all</strong> fields. The context is based
  1642  * on sanitize_term_field().
  2161  * on sanitize_term_field().
  1643  *
  2162  *
  1644  * The $term is expected to be either an array or an object.
  2163  * The $term is expected to be either an array or an object.
  1645  *
  2164  *
  1646  * @package WordPress
       
  1647  * @subpackage Taxonomy
       
  1648  * @since 2.3.0
  2165  * @since 2.3.0
  1649  *
       
  1650  * @uses sanitize_term_field Used to sanitize all fields in a term
       
  1651  *
  2166  *
  1652  * @param array|object $term The term to check
  2167  * @param array|object $term The term to check
  1653  * @param string $taxonomy The taxonomy name to use
  2168  * @param string $taxonomy The taxonomy name to use
  1654  * @param string $context Default is 'display'.
  2169  * @param string $context Default is 'display'.
  1655  * @return array|object Term with all fields sanitized
  2170  * @return array|object Term with all fields sanitized
  1656  */
  2171  */
  1657 function sanitize_term($term, $taxonomy, $context = 'display') {
  2172 function sanitize_term($term, $taxonomy, $context = 'display') {
  1658 
  2173 
  1659 	if ( 'raw' == $context )
  2174 	$fields = array( 'term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group', 'term_taxonomy_id', 'object_id' );
  1660 		return $term;
  2175 
  1661 
  2176 	$do_object = is_object( $term );
  1662 	$fields = array('term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group');
       
  1663 
       
  1664 	$do_object = false;
       
  1665 	if ( is_object($term) )
       
  1666 		$do_object = true;
       
  1667 
  2177 
  1668 	$term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0);
  2178 	$term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0);
  1669 
  2179 
  1670 	foreach ( (array) $fields as $field ) {
  2180 	foreach ( (array) $fields as $field ) {
  1671 		if ( $do_object ) {
  2181 		if ( $do_object ) {
  1696  *
  2206  *
  1697  * There are enough filters for each context to support a custom filtering
  2207  * There are enough filters for each context to support a custom filtering
  1698  * without creating your own filter function. Simply create a function that
  2208  * without creating your own filter function. Simply create a function that
  1699  * hooks into the filter you need.
  2209  * hooks into the filter you need.
  1700  *
  2210  *
  1701  * @package WordPress
       
  1702  * @subpackage Taxonomy
       
  1703  * @since 2.3.0
  2211  * @since 2.3.0
  1704  *
  2212  *
  1705  * @uses $wpdb
  2213  * @global wpdb $wpdb WordPress database abstraction object.
  1706  *
  2214  *
  1707  * @param string $field Term field to sanitize
  2215  * @param string $field Term field to sanitize
  1708  * @param string $value Search for this term value
  2216  * @param string $value Search for this term value
  1709  * @param int $term_id Term ID
  2217  * @param int $term_id Term ID
  1710  * @param string $taxonomy Taxonomy Name
  2218  * @param string $taxonomy Taxonomy Name
  1711  * @param string $context Either edit, db, display, attribute, or js.
  2219  * @param string $context Either edit, db, display, attribute, or js.
  1712  * @return mixed sanitized field
  2220  * @return mixed sanitized field
  1713  */
  2221  */
  1714 function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) {
  2222 function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) {
  1715 	if ( 'parent' == $field  || 'term_id' == $field || 'count' == $field || 'term_group' == $field ) {
  2223 	$int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' );
       
  2224 	if ( in_array( $field, $int_fields ) ) {
  1716 		$value = (int) $value;
  2225 		$value = (int) $value;
  1717 		if ( $value < 0 )
  2226 		if ( $value < 0 )
  1718 			$value = 0;
  2227 			$value = 0;
  1719 	}
  2228 	}
  1720 
  2229 
  1721 	if ( 'raw' == $context )
  2230 	if ( 'raw' == $context )
  1722 		return $value;
  2231 		return $value;
  1723 
  2232 
  1724 	if ( 'edit' == $context ) {
  2233 	if ( 'edit' == $context ) {
  1725 		$value = apply_filters("edit_term_{$field}", $value, $term_id, $taxonomy);
  2234 
  1726 		$value = apply_filters("edit_{$taxonomy}_{$field}", $value, $term_id);
  2235 		/**
       
  2236 		 * Filter a term field to edit before it is sanitized.
       
  2237 		 *
       
  2238 		 * The dynamic portion of the filter name, `$field`, refers to the term field.
       
  2239 		 *
       
  2240 		 * @since 2.3.0
       
  2241 		 *
       
  2242 		 * @param mixed $value     Value of the term field.
       
  2243 		 * @param int   $term_id   Term ID.
       
  2244 		 * @param string $taxonomy Taxonomy slug.
       
  2245 		 */
       
  2246 		$value = apply_filters( "edit_term_{$field}", $value, $term_id, $taxonomy );
       
  2247 
       
  2248 		/**
       
  2249 		 * Filter the taxonomy field to edit before it is sanitized.
       
  2250 		 *
       
  2251 		 * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer
       
  2252 		 * to the taxonomy slug and taxonomy field, respectively.
       
  2253 		 *
       
  2254 		 * @since 2.3.0
       
  2255 		 *
       
  2256 		 * @param mixed $value   Value of the taxonomy field to edit.
       
  2257 		 * @param int   $term_id Term ID.
       
  2258 		 */
       
  2259 		$value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id );
  1727 		if ( 'description' == $field )
  2260 		if ( 'description' == $field )
  1728 			$value = esc_html($value); // textarea_escaped
  2261 			$value = esc_html($value); // textarea_escaped
  1729 		else
  2262 		else
  1730 			$value = esc_attr($value);
  2263 			$value = esc_attr($value);
  1731 	} else if ( 'db' == $context ) {
  2264 	} elseif ( 'db' == $context ) {
  1732 		$value = apply_filters("pre_term_{$field}", $value, $taxonomy);
  2265 
  1733 		$value = apply_filters("pre_{$taxonomy}_{$field}", $value);
  2266 		/**
       
  2267 		 * Filter a term field value before it is sanitized.
       
  2268 		 *
       
  2269 		 * The dynamic portion of the filter name, `$field`, refers to the term field.
       
  2270 		 *
       
  2271 		 * @since 2.3.0
       
  2272 		 *
       
  2273 		 * @param mixed  $value    Value of the term field.
       
  2274 		 * @param string $taxonomy Taxonomy slug.
       
  2275 		 */
       
  2276 		$value = apply_filters( "pre_term_{$field}", $value, $taxonomy );
       
  2277 
       
  2278 		/**
       
  2279 		 * Filter a taxonomy field before it is sanitized.
       
  2280 		 *
       
  2281 		 * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer
       
  2282 		 * to the taxonomy slug and field name, respectively.
       
  2283 		 *
       
  2284 		 * @since 2.3.0
       
  2285 		 *
       
  2286 		 * @param mixed $value Value of the taxonomy field.
       
  2287 		 */
       
  2288 		$value = apply_filters( "pre_{$taxonomy}_{$field}", $value );
  1734 		// Back compat filters
  2289 		// Back compat filters
  1735 		if ( 'slug' == $field )
  2290 		if ( 'slug' == $field ) {
  1736 			$value = apply_filters('pre_category_nicename', $value);
  2291 			/**
  1737 
  2292 			 * Filter the category nicename before it is sanitized.
  1738 	} else if ( 'rss' == $context ) {
  2293 			 *
  1739 		$value = apply_filters("term_{$field}_rss", $value, $taxonomy);
  2294 			 * Use the pre_{$taxonomy}_{$field} hook instead.
  1740 		$value = apply_filters("{$taxonomy}_{$field}_rss", $value);
  2295 			 *
       
  2296 			 * @since 2.0.3
       
  2297 			 *
       
  2298 			 * @param string $value The category nicename.
       
  2299 			 */
       
  2300 			$value = apply_filters( 'pre_category_nicename', $value );
       
  2301 		}
       
  2302 
       
  2303 	} elseif ( 'rss' == $context ) {
       
  2304 
       
  2305 		/**
       
  2306 		 * Filter the term field for use in RSS.
       
  2307 		 *
       
  2308 		 * The dynamic portion of the filter name, `$field`, refers to the term field.
       
  2309 		 *
       
  2310 		 * @since 2.3.0
       
  2311 		 *
       
  2312 		 * @param mixed  $value    Value of the term field.
       
  2313 		 * @param string $taxonomy Taxonomy slug.
       
  2314 		 */
       
  2315 		$value = apply_filters( "term_{$field}_rss", $value, $taxonomy );
       
  2316 
       
  2317 		/**
       
  2318 		 * Filter the taxonomy field for use in RSS.
       
  2319 		 *
       
  2320 		 * The dynamic portions of the hook name, `$taxonomy`, and $field, refer
       
  2321 		 * to the taxonomy slug and field name, respectively.
       
  2322 		 *
       
  2323 		 * @since 2.3.0
       
  2324 		 *
       
  2325 		 * @param mixed $value Value of the taxonomy field.
       
  2326 		 */
       
  2327 		$value = apply_filters( "{$taxonomy}_{$field}_rss", $value );
  1741 	} else {
  2328 	} else {
  1742 		// Use display filters by default.
  2329 		// Use display filters by default.
  1743 		$value = apply_filters("term_{$field}", $value, $term_id, $taxonomy, $context);
  2330 
  1744 		$value = apply_filters("{$taxonomy}_{$field}", $value, $term_id, $context);
  2331 		/**
  1745 	}
  2332 		 * Filter the term field sanitized for display.
  1746 
  2333 		 *
  1747 	if ( 'attribute' == $context )
  2334 		 * The dynamic portion of the filter name, `$field`, refers to the term field name.
       
  2335 		 *
       
  2336 		 * @since 2.3.0
       
  2337 		 *
       
  2338 		 * @param mixed  $value    Value of the term field.
       
  2339 		 * @param int    $term_id  Term ID.
       
  2340 		 * @param string $taxonomy Taxonomy slug.
       
  2341 		 * @param string $context  Context to retrieve the term field value.
       
  2342 		 */
       
  2343 		$value = apply_filters( "term_{$field}", $value, $term_id, $taxonomy, $context );
       
  2344 
       
  2345 		/**
       
  2346 		 * Filter the taxonomy field sanitized for display.
       
  2347 		 *
       
  2348 		 * The dynamic portions of the filter name, `$taxonomy`, and $field, refer
       
  2349 		 * to the taxonomy slug and taxonomy field, respectively.
       
  2350 		 *
       
  2351 		 * @since 2.3.0
       
  2352 		 *
       
  2353 		 * @param mixed  $value   Value of the taxonomy field.
       
  2354 		 * @param int    $term_id Term ID.
       
  2355 		 * @param string $context Context to retrieve the taxonomy field value.
       
  2356 		 */
       
  2357 		$value = apply_filters( "{$taxonomy}_{$field}", $value, $term_id, $context );
       
  2358 	}
       
  2359 
       
  2360 	if ( 'attribute' == $context ) {
  1748 		$value = esc_attr($value);
  2361 		$value = esc_attr($value);
  1749 	else if ( 'js' == $context )
  2362 	} elseif ( 'js' == $context ) {
  1750 		$value = esc_js($value);
  2363 		$value = esc_js($value);
  1751 
  2364 	}
  1752 	return $value;
  2365 	return $value;
  1753 }
  2366 }
  1754 
  2367 
  1755 /**
  2368 /**
  1756  * Count how many terms are in Taxonomy.
  2369  * Count how many terms are in Taxonomy.
  1757  *
  2370  *
  1758  * Default $args is 'hide_empty' which can be 'hide_empty=true' or array('hide_empty' => true).
  2371  * Default $args is 'hide_empty' which can be 'hide_empty=true' or array('hide_empty' => true).
  1759  *
  2372  *
  1760  * @package WordPress
       
  1761  * @subpackage Taxonomy
       
  1762  * @since 2.3.0
  2373  * @since 2.3.0
  1763  *
       
  1764  * @uses get_terms()
       
  1765  * @uses wp_parse_args() Turns strings into arrays and merges defaults into an array.
       
  1766  *
  2374  *
  1767  * @param string $taxonomy Taxonomy name
  2375  * @param string $taxonomy Taxonomy name
  1768  * @param array|string $args Overwrite defaults. See get_terms()
  2376  * @param array|string $args Overwrite defaults. See get_terms()
  1769  * @return int|WP_Error How many terms are in $taxonomy. WP_Error if $taxonomy does not exist.
  2377  * @return int|WP_Error How many terms are in $taxonomy. WP_Error if $taxonomy does not exist.
  1770  */
  2378  */
  1788  *
  2396  *
  1789  * Will remove all relationships between the object and any terms in
  2397  * Will remove all relationships between the object and any terms in
  1790  * a particular taxonomy or taxonomies. Does not remove the term or
  2398  * a particular taxonomy or taxonomies. Does not remove the term or
  1791  * taxonomy itself.
  2399  * taxonomy itself.
  1792  *
  2400  *
  1793  * @package WordPress
       
  1794  * @subpackage Taxonomy
       
  1795  * @since 2.3.0
  2401  * @since 2.3.0
  1796  * @uses wp_remove_object_terms()
       
  1797  *
  2402  *
  1798  * @param int $object_id The term Object Id that refers to the term
  2403  * @param int $object_id The term Object Id that refers to the term
  1799  * @param string|array $taxonomies List of Taxonomy Names or single Taxonomy name.
  2404  * @param string|array $taxonomies List of Taxonomy Names or single Taxonomy name.
  1800  */
  2405  */
  1801 function wp_delete_object_term_relationships( $object_id, $taxonomies ) {
  2406 function wp_delete_object_term_relationships( $object_id, $taxonomies ) {
  1820  * The $args 'default' will only override the terms found, if there is only one
  2425  * The $args 'default' will only override the terms found, if there is only one
  1821  * term found. Any other and the found terms are used.
  2426  * term found. Any other and the found terms are used.
  1822  *
  2427  *
  1823  * The $args 'force_default' will force the term supplied as default to be
  2428  * The $args 'force_default' will force the term supplied as default to be
  1824  * assigned even if the object was not going to be termless
  2429  * assigned even if the object was not going to be termless
  1825  * @package WordPress
  2430  *
  1826  * @subpackage Taxonomy
       
  1827  * @since 2.3.0
  2431  * @since 2.3.0
  1828  *
  2432  *
  1829  * @uses $wpdb
  2433  * @global wpdb $wpdb WordPress database abstraction object.
  1830  * @uses do_action() Calls both 'delete_term' and 'delete_$taxonomy' action
       
  1831  *	hooks, passing term ID, term taxonomy ID, and deleted term object. 'delete_term'
       
  1832  *	also gets taxonomy as the third parameter.
       
  1833  *
  2434  *
  1834  * @param int $term Term ID
  2435  * @param int $term Term ID
  1835  * @param string $taxonomy Taxonomy Name
  2436  * @param string $taxonomy Taxonomy Name
  1836  * @param array|string $args Optional. Change 'default' term id and override found term ids.
  2437  * @param array|string $args Optional. Change 'default' term id and override found term ids.
  1837  * @return bool|WP_Error Returns false if not term; true if completes delete action.
  2438  * @return bool|WP_Error Returns false if not term; true if completes delete action.
  1855 		if ( $defaults['default'] == $term )
  2456 		if ( $defaults['default'] == $term )
  1856 			return 0; // Don't delete the default category
  2457 			return 0; // Don't delete the default category
  1857 	}
  2458 	}
  1858 
  2459 
  1859 	$args = wp_parse_args($args, $defaults);
  2460 	$args = wp_parse_args($args, $defaults);
  1860 	extract($args, EXTR_SKIP);
  2461 
  1861 
  2462 	if ( isset( $args['default'] ) ) {
  1862 	if ( isset( $default ) ) {
  2463 		$default = (int) $args['default'];
  1863 		$default = (int) $default;
  2464 		if ( ! term_exists( $default, $taxonomy ) ) {
  1864 		if ( ! term_exists($default, $taxonomy) )
  2465 			unset( $default );
  1865 			unset($default);
  2466 		}
  1866 	}
  2467 	}
       
  2468 
       
  2469 	if ( isset( $args['force_default'] ) ) {
       
  2470 		$force_default = $args['force_default'];
       
  2471 	}
       
  2472 
       
  2473 	/**
       
  2474 	 * Fires when deleting a term, before any modifications are made to posts or terms.
       
  2475 	 *
       
  2476 	 * @since 4.1.0
       
  2477 	 *
       
  2478 	 * @param int    $term     Term ID.
       
  2479 	 * @param string $taxonomy Taxonomy Name.
       
  2480 	 */
       
  2481 	do_action( 'pre_delete_term', $term, $taxonomy );
  1867 
  2482 
  1868 	// Update children to point to new parent
  2483 	// Update children to point to new parent
  1869 	if ( is_taxonomy_hierarchical($taxonomy) ) {
  2484 	if ( is_taxonomy_hierarchical($taxonomy) ) {
  1870 		$term_obj = get_term($term, $taxonomy);
  2485 		$term_obj = get_term($term, $taxonomy);
  1871 		if ( is_wp_error( $term_obj ) )
  2486 		if ( is_wp_error( $term_obj ) )
  1872 			return $term_obj;
  2487 			return $term_obj;
  1873 		$parent = $term_obj->parent;
  2488 		$parent = $term_obj->parent;
  1874 
  2489 
  1875 		$edit_tt_ids = $wpdb->get_col( "SELECT `term_taxonomy_id` FROM $wpdb->term_taxonomy WHERE `parent` = " . (int)$term_obj->term_id );
  2490 		$edit_ids = $wpdb->get_results( "SELECT term_id, term_taxonomy_id FROM $wpdb->term_taxonomy WHERE `parent` = " . (int)$term_obj->term_id );
       
  2491 		$edit_tt_ids = wp_list_pluck( $edit_ids, 'term_taxonomy_id' );
       
  2492 
       
  2493 		/**
       
  2494 		 * Fires immediately before a term to delete's children are reassigned a parent.
       
  2495 		 *
       
  2496 		 * @since 2.9.0
       
  2497 		 *
       
  2498 		 * @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
       
  2499 		 */
  1876 		do_action( 'edit_term_taxonomies', $edit_tt_ids );
  2500 		do_action( 'edit_term_taxonomies', $edit_tt_ids );
  1877 		$wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id) + compact( 'taxonomy' ) );
  2501 		$wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id) + compact( 'taxonomy' ) );
       
  2502 
       
  2503 		// Clean the cache for all child terms.
       
  2504 		$edit_term_ids = wp_list_pluck( $edit_ids, 'term_id' );
       
  2505 		clean_term_cache( $edit_term_ids, $taxonomy );
       
  2506 
       
  2507 		/**
       
  2508 		 * Fires immediately after a term to delete's children are reassigned a parent.
       
  2509 		 *
       
  2510 		 * @since 2.9.0
       
  2511 		 *
       
  2512 		 * @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
       
  2513 		 */
  1878 		do_action( 'edited_term_taxonomies', $edit_tt_ids );
  2514 		do_action( 'edited_term_taxonomies', $edit_tt_ids );
  1879 	}
  2515 	}
  1880 
  2516 
  1881 	$objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
  2517 	$objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
  1882 
  2518 
  1899 		clean_object_term_cache( $objects, $object_type );
  2535 		clean_object_term_cache( $objects, $object_type );
  1900 
  2536 
  1901 	// Get the object before deletion so we can pass to actions below
  2537 	// Get the object before deletion so we can pass to actions below
  1902 	$deleted_term = get_term( $term, $taxonomy );
  2538 	$deleted_term = get_term( $term, $taxonomy );
  1903 
  2539 
       
  2540 	/**
       
  2541 	 * Fires immediately before a term taxonomy ID is deleted.
       
  2542 	 *
       
  2543 	 * @since 2.9.0
       
  2544 	 *
       
  2545 	 * @param int $tt_id Term taxonomy ID.
       
  2546 	 */
  1904 	do_action( 'delete_term_taxonomy', $tt_id );
  2547 	do_action( 'delete_term_taxonomy', $tt_id );
  1905 	$wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
  2548 	$wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
       
  2549 
       
  2550 	/**
       
  2551 	 * Fires immediately after a term taxonomy ID is deleted.
       
  2552 	 *
       
  2553 	 * @since 2.9.0
       
  2554 	 *
       
  2555 	 * @param int $tt_id Term taxonomy ID.
       
  2556 	 */
  1906 	do_action( 'deleted_term_taxonomy', $tt_id );
  2557 	do_action( 'deleted_term_taxonomy', $tt_id );
  1907 
  2558 
  1908 	// Delete the term if no taxonomies use it.
  2559 	// Delete the term if no taxonomies use it.
  1909 	if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term) ) )
  2560 	if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term) ) )
  1910 		$wpdb->delete( $wpdb->terms, array( 'term_id' => $term ) );
  2561 		$wpdb->delete( $wpdb->terms, array( 'term_id' => $term ) );
  1911 
  2562 
  1912 	clean_term_cache($term, $taxonomy);
  2563 	clean_term_cache($term, $taxonomy);
  1913 
  2564 
       
  2565 	/**
       
  2566 	 * Fires after a term is deleted from the database and the cache is cleaned.
       
  2567 	 *
       
  2568 	 * @since 2.5.0
       
  2569 	 *
       
  2570 	 * @param int     $term         Term ID.
       
  2571 	 * @param int     $tt_id        Term taxonomy ID.
       
  2572 	 * @param string  $taxonomy     Taxonomy slug.
       
  2573 	 * @param mixed   $deleted_term Copy of the already-deleted term, in the form specified
       
  2574 	 *                              by the parent function. WP_Error otherwise.
       
  2575 	 */
  1914 	do_action( 'delete_term', $term, $tt_id, $taxonomy, $deleted_term );
  2576 	do_action( 'delete_term', $term, $tt_id, $taxonomy, $deleted_term );
       
  2577 
       
  2578 	/**
       
  2579 	 * Fires after a term in a specific taxonomy is deleted.
       
  2580 	 *
       
  2581 	 * The dynamic portion of the hook name, `$taxonomy`, refers to the specific
       
  2582 	 * taxonomy the term belonged to.
       
  2583 	 *
       
  2584 	 * @since 2.3.0
       
  2585 	 *
       
  2586 	 * @param int     $term         Term ID.
       
  2587 	 * @param int     $tt_id        Term taxonomy ID.
       
  2588 	 * @param mixed   $deleted_term Copy of the already-deleted term, in the form specified
       
  2589 	 *                              by the parent function. {@see WP_Error} otherwise.
       
  2590 	 */
  1915 	do_action( "delete_$taxonomy", $term, $tt_id, $deleted_term );
  2591 	do_action( "delete_$taxonomy", $term, $tt_id, $deleted_term );
  1916 
  2592 
  1917 	return true;
  2593 	return true;
  1918 }
  2594 }
  1919 
  2595 
  1920 /**
  2596 /**
  1921  * Deletes one existing category.
  2597  * Deletes one existing category.
  1922  *
  2598  *
  1923  * @since 2.0.0
  2599  * @since 2.0.0
  1924  * @uses wp_delete_term()
       
  1925  *
  2600  *
  1926  * @param int $cat_ID
  2601  * @param int $cat_ID
  1927  * @return mixed Returns true if completes delete action; false if term doesn't exist;
  2602  * @return mixed Returns true if completes delete action; false if term doesn't exist;
  1928  * 	Zero on attempted deletion of default Category; WP_Error object is also a possibility.
  2603  * 	Zero on attempted deletion of default Category; WP_Error object is also a possibility.
  1929  */
  2604  */
  1932 }
  2607 }
  1933 
  2608 
  1934 /**
  2609 /**
  1935  * Retrieves the terms associated with the given object(s), in the supplied taxonomies.
  2610  * Retrieves the terms associated with the given object(s), in the supplied taxonomies.
  1936  *
  2611  *
  1937  * The following information has to do the $args parameter and for what can be
       
  1938  * contained in the string or array of that parameter, if it exists.
       
  1939  *
       
  1940  * The first argument is called, 'orderby' and has the default value of 'name'.
       
  1941  * The other value that is supported is 'count'.
       
  1942  *
       
  1943  * The second argument is called, 'order' and has the default value of 'ASC'.
       
  1944  * The only other value that will be acceptable is 'DESC'.
       
  1945  *
       
  1946  * The final argument supported is called, 'fields' and has the default value of
       
  1947  * 'all'. There are multiple other options that can be used instead. Supported
       
  1948  * values are as follows: 'all', 'ids', 'names', and finally
       
  1949  * 'all_with_object_id'.
       
  1950  *
       
  1951  * The fields argument also decides what will be returned. If 'all' or
       
  1952  * 'all_with_object_id' is chosen or the default kept intact, then all matching
       
  1953  * terms objects will be returned. If either 'ids' or 'names' is used, then an
       
  1954  * array of all matching term ids or term names will be returned respectively.
       
  1955  *
       
  1956  * @package WordPress
       
  1957  * @subpackage Taxonomy
       
  1958  * @since 2.3.0
  2612  * @since 2.3.0
  1959  * @uses $wpdb
  2613  * @since 4.2.0 Added support for 'taxonomy', 'parent', and 'term_taxonomy_id' values of `$orderby`.
  1960  *
  2614  *              Introduced `$parent` argument.
  1961  * @param int|array $object_ids The ID(s) of the object(s) to retrieve.
  2615  *
       
  2616  * @global wpdb $wpdb WordPress database abstraction object.
       
  2617  *
       
  2618  * @param int|array    $object_ids The ID(s) of the object(s) to retrieve.
  1962  * @param string|array $taxonomies The taxonomies to retrieve terms from.
  2619  * @param string|array $taxonomies The taxonomies to retrieve terms from.
  1963  * @param array|string $args Change what is returned
  2620  * @param array|string $args {
  1964  * @return array|WP_Error The requested term data or empty array if no terms found. WP_Error if any of the $taxonomies don't exist.
  2621  *     Array of arguments.
       
  2622  *     @type string $orderby Field by which results should be sorted. Accepts 'name', 'count', 'slug', 'term_group',
       
  2623  *                           'term_order', 'taxonomy', 'parent', or 'term_taxonomy_id'. Default 'name'.
       
  2624  *     @type string $order   Sort order. Accepts 'ASC' or 'DESC'. Default 'ASC'.
       
  2625  *     @type string $fields  Fields to return for matched terms. Accepts 'all', 'ids', 'names', and
       
  2626  *                           'all_with_object_id'. Note that 'all' or 'all_with_object_id' will result in an array of
       
  2627  *                           term objects being returned, 'ids' will return an array of integers, and 'names' an array
       
  2628  *                           of strings.
       
  2629  *     @type int    $parent  Optional. Limit results to the direct children of a given term ID.
       
  2630  * }
       
  2631  * @return array|WP_Error The requested term data or empty array if no terms found.
       
  2632  *                        WP_Error if any of the $taxonomies don't exist.
  1965  */
  2633  */
  1966 function wp_get_object_terms($object_ids, $taxonomies, $args = array()) {
  2634 function wp_get_object_terms($object_ids, $taxonomies, $args = array()) {
  1967 	global $wpdb;
  2635 	global $wpdb;
  1968 
  2636 
  1969 	if ( empty( $object_ids ) || empty( $taxonomies ) )
  2637 	if ( empty( $object_ids ) || empty( $taxonomies ) )
  1970 		return array();
  2638 		return array();
  1971 
  2639 
  1972 	if ( !is_array($taxonomies) )
  2640 	if ( !is_array($taxonomies) )
  1973 		$taxonomies = array($taxonomies);
  2641 		$taxonomies = array($taxonomies);
  1974 
  2642 
  1975 	foreach ( (array) $taxonomies as $taxonomy ) {
  2643 	foreach ( $taxonomies as $taxonomy ) {
  1976 		if ( ! taxonomy_exists($taxonomy) )
  2644 		if ( ! taxonomy_exists($taxonomy) )
  1977 			return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
  2645 			return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
  1978 	}
  2646 	}
  1979 
  2647 
  1980 	if ( !is_array($object_ids) )
  2648 	if ( !is_array($object_ids) )
  1981 		$object_ids = array($object_ids);
  2649 		$object_ids = array($object_ids);
  1982 	$object_ids = array_map('intval', $object_ids);
  2650 	$object_ids = array_map('intval', $object_ids);
  1983 
  2651 
  1984 	$defaults = array('orderby' => 'name', 'order' => 'ASC', 'fields' => 'all');
  2652 	$defaults = array(
       
  2653 		'orderby' => 'name',
       
  2654 		'order'   => 'ASC',
       
  2655 		'fields'  => 'all',
       
  2656 		'parent'  => '',
       
  2657 	);
  1985 	$args = wp_parse_args( $args, $defaults );
  2658 	$args = wp_parse_args( $args, $defaults );
  1986 
  2659 
  1987 	$terms = array();
  2660 	$terms = array();
  1988 	if ( count($taxonomies) > 1 ) {
  2661 	if ( count($taxonomies) > 1 ) {
  1989 		foreach ( $taxonomies as $index => $taxonomy ) {
  2662 		foreach ( $taxonomies as $index => $taxonomy ) {
  1997 		$t = get_taxonomy($taxonomies[0]);
  2670 		$t = get_taxonomy($taxonomies[0]);
  1998 		if ( isset($t->args) && is_array($t->args) )
  2671 		if ( isset($t->args) && is_array($t->args) )
  1999 			$args = array_merge($args, $t->args);
  2672 			$args = array_merge($args, $t->args);
  2000 	}
  2673 	}
  2001 
  2674 
  2002 	extract($args, EXTR_SKIP);
  2675 	$orderby = $args['orderby'];
  2003 
  2676 	$order = $args['order'];
  2004 	if ( 'count' == $orderby )
  2677 	$fields = $args['fields'];
  2005 		$orderby = 'tt.count';
  2678 
  2006 	else if ( 'name' == $orderby )
  2679 	if ( in_array( $orderby, array( 'term_id', 'name', 'slug', 'term_group' ) ) ) {
  2007 		$orderby = 't.name';
  2680 		$orderby = "t.$orderby";
  2008 	else if ( 'slug' == $orderby )
  2681 	} else if ( in_array( $orderby, array( 'count', 'parent', 'taxonomy', 'term_taxonomy_id' ) ) ) {
  2009 		$orderby = 't.slug';
  2682 		$orderby = "tt.$orderby";
  2010 	else if ( 'term_group' == $orderby )
  2683 	} else if ( 'term_order' === $orderby ) {
  2011 		$orderby = 't.term_group';
       
  2012 	else if ( 'term_order' == $orderby )
       
  2013 		$orderby = 'tr.term_order';
  2684 		$orderby = 'tr.term_order';
  2014 	else if ( 'none' == $orderby ) {
  2685 	} else if ( 'none' === $orderby ) {
  2015 		$orderby = '';
  2686 		$orderby = '';
  2016 		$order = '';
  2687 		$order = '';
  2017 	} else {
  2688 	} else {
  2018 		$orderby = 't.term_id';
  2689 		$orderby = 't.term_id';
  2019 	}
  2690 	}
  2027 
  2698 
  2028 	$order = strtoupper( $order );
  2699 	$order = strtoupper( $order );
  2029 	if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) )
  2700 	if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) )
  2030 		$order = 'ASC';
  2701 		$order = 'ASC';
  2031 
  2702 
       
  2703 	$taxonomy_array = $taxonomies;
       
  2704 	$object_id_array = $object_ids;
  2032 	$taxonomies = "'" . implode("', '", $taxonomies) . "'";
  2705 	$taxonomies = "'" . implode("', '", $taxonomies) . "'";
  2033 	$object_ids = implode(', ', $object_ids);
  2706 	$object_ids = implode(', ', $object_ids);
  2034 
  2707 
  2035 	$select_this = '';
  2708 	$select_this = '';
  2036 	if ( 'all' == $fields )
  2709 	if ( 'all' == $fields ) {
  2037 		$select_this = 't.*, tt.*';
  2710 		$select_this = 't.*, tt.*';
  2038 	else if ( 'ids' == $fields )
  2711 	} elseif ( 'ids' == $fields ) {
  2039 		$select_this = 't.term_id';
  2712 		$select_this = 't.term_id';
  2040 	else if ( 'names' == $fields )
  2713 	} elseif ( 'names' == $fields ) {
  2041 		$select_this = 't.name';
  2714 		$select_this = 't.name';
  2042 	else if ( 'slugs' == $fields )
  2715 	} elseif ( 'slugs' == $fields ) {
  2043 		$select_this = 't.slug';
  2716 		$select_this = 't.slug';
  2044 	else if ( 'all_with_object_id' == $fields )
  2717 	} elseif ( 'all_with_object_id' == $fields ) {
  2045 		$select_this = 't.*, tt.*, tr.object_id';
  2718 		$select_this = 't.*, tt.*, tr.object_id';
  2046 
  2719 	}
  2047 	$query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tr.object_id IN ($object_ids) $orderby $order";
  2720 
  2048 
  2721 	$where = array(
       
  2722 		"tt.taxonomy IN ($taxonomies)",
       
  2723 		"tr.object_id IN ($object_ids)",
       
  2724 	);
       
  2725 
       
  2726 	if ( '' !== $args['parent'] ) {
       
  2727 		$where[] = $wpdb->prepare( 'tt.parent = %d', $args['parent'] );
       
  2728 	}
       
  2729 
       
  2730 	$where = implode( ' AND ', $where );
       
  2731 
       
  2732 	$query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE $where $orderby $order";
       
  2733 
       
  2734 	$objects = false;
  2049 	if ( 'all' == $fields || 'all_with_object_id' == $fields ) {
  2735 	if ( 'all' == $fields || 'all_with_object_id' == $fields ) {
  2050 		$terms = array_merge($terms, $wpdb->get_results($query));
  2736 		$_terms = $wpdb->get_results( $query );
  2051 		update_term_cache($terms);
  2737 		foreach ( $_terms as $key => $term ) {
  2052 	} else if ( 'ids' == $fields || 'names' == $fields || 'slugs' == $fields ) {
  2738 			$_terms[$key] = sanitize_term( $term, $taxonomy, 'raw' );
  2053 		$terms = array_merge($terms, $wpdb->get_col($query));
  2739 		}
  2054 	} else if ( 'tt_ids' == $fields ) {
  2740 		$terms = array_merge( $terms, $_terms );
       
  2741 		update_term_cache( $terms );
       
  2742 		$objects = true;
       
  2743 	} elseif ( 'ids' == $fields || 'names' == $fields || 'slugs' == $fields ) {
       
  2744 		$_terms = $wpdb->get_col( $query );
       
  2745 		$_field = ( 'ids' == $fields ) ? 'term_id' : 'name';
       
  2746 		foreach ( $_terms as $key => $term ) {
       
  2747 			$_terms[$key] = sanitize_term_field( $_field, $term, $term, $taxonomy, 'raw' );
       
  2748 		}
       
  2749 		$terms = array_merge( $terms, $_terms );
       
  2750 	} elseif ( 'tt_ids' == $fields ) {
  2055 		$terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id IN ($object_ids) AND tt.taxonomy IN ($taxonomies) $orderby $order");
  2751 		$terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id IN ($object_ids) AND tt.taxonomy IN ($taxonomies) $orderby $order");
  2056 	}
  2752 		foreach ( $terms as $key => $tt_id ) {
  2057 
  2753 			$terms[$key] = sanitize_term_field( 'term_taxonomy_id', $tt_id, 0, $taxonomy, 'raw' ); // 0 should be the term id, however is not needed when using raw context.
  2058 	if ( ! $terms )
  2754 		}
       
  2755 	}
       
  2756 
       
  2757 	if ( ! $terms ) {
  2059 		$terms = array();
  2758 		$terms = array();
  2060 
  2759 	} elseif ( $objects && 'all_with_object_id' !== $fields ) {
  2061 	return apply_filters('wp_get_object_terms', $terms, $object_ids, $taxonomies, $args);
  2760 		$_tt_ids = array();
       
  2761 		$_terms = array();
       
  2762 		foreach ( $terms as $term ) {
       
  2763 			if ( in_array( $term->term_taxonomy_id, $_tt_ids ) ) {
       
  2764 				continue;
       
  2765 			}
       
  2766 
       
  2767 			$_tt_ids[] = $term->term_taxonomy_id;
       
  2768 			$_terms[] = $term;
       
  2769 		}
       
  2770 		$terms = $_terms;
       
  2771 	} elseif ( ! $objects ) {
       
  2772 		$terms = array_values( array_unique( $terms ) );
       
  2773 	}
       
  2774 
       
  2775 	/**
       
  2776 	 * Filter the terms for a given object or objects.
       
  2777 	 *
       
  2778 	 * @since 4.2.0
       
  2779 	 *
       
  2780 	 * @param array $terms           An array of terms for the given object or objects.
       
  2781 	 * @param array $object_id_array Array of object IDs for which `$terms` were retrieved.
       
  2782 	 * @param array $taxonomy_array  Array of taxonomies from which `$terms` were retrieved.
       
  2783 	 * @param array $args            An array of arguments for retrieving terms for the given
       
  2784 	 *                               object(s). See wp_get_object_terms() for details.
       
  2785 	 */
       
  2786 	$terms = apply_filters( 'get_object_terms', $terms, $object_id_array, $taxonomy_array, $args );
       
  2787 
       
  2788 	/**
       
  2789 	 * Filter the terms for a given object or objects.
       
  2790 	 *
       
  2791 	 * The `$taxonomies` parameter passed to this filter is formatted as a SQL fragment. The
       
  2792 	 * {@see 'get_object_terms'} filter is recommended as an alternative.
       
  2793 	 *
       
  2794 	 * @since 2.8.0
       
  2795 	 *
       
  2796 	 * @param array     $terms      An array of terms for the given object or objects.
       
  2797 	 * @param int|array $object_ids Object ID or array of IDs.
       
  2798 	 * @param string    $taxonomies SQL-formatted (comma-separated and quoted) list of taxonomy names.
       
  2799 	 * @param array     $args       An array of arguments for retrieving terms for the given object(s).
       
  2800 	 *                              See {@see wp_get_object_terms()} for details.
       
  2801 	 */
       
  2802 	return apply_filters( 'wp_get_object_terms', $terms, $object_ids, $taxonomies, $args );
  2062 }
  2803 }
  2063 
  2804 
  2064 /**
  2805 /**
  2065  * Add a new term to the database.
  2806  * Add a new term to the database.
  2066  *
  2807  *
  2084  * a WP_Error object will be returned.
  2825  * a WP_Error object will be returned.
  2085  *
  2826  *
  2086  * If the term already exists on the same hierarchical level,
  2827  * If the term already exists on the same hierarchical level,
  2087  * or the term slug and name are not unique, a WP_Error object will be returned.
  2828  * or the term slug and name are not unique, a WP_Error object will be returned.
  2088  *
  2829  *
  2089  * @global wpdb $wpdb The WordPress database object.
  2830  * @global wpdb $wpdb WordPress database abstraction object.
  2090 
  2831 
  2091  * @since 2.3.0
  2832  * @since 2.3.0
  2092  *
  2833  *
  2093  * @param string       $term     The term to add or update.
  2834  * @param string       $term     The term to add or update.
  2094  * @param string       $taxonomy The taxonomy to which to add the term
  2835  * @param string       $taxonomy The taxonomy to which to add the term.
  2095  * @param array|string $args {
  2836  * @param array|string $args {
  2096  *     Arguments to change values of the inserted term.
  2837  *     Optional. Array or string of arguments for inserting a term.
  2097  *
  2838  *
  2098  *     @type string 'alias_of'    Slug of the term to make this term an alias of.
  2839  *     @type string $alias_of    Slug of the term to make this term an alias of.
  2099  *                                Default empty string. Accepts a term slug.
  2840  *                               Default empty string. Accepts a term slug.
  2100  *     @type string 'description' The term description.
  2841  *     @type string $description The term description. Default empty string.
  2101  *                                Default empty string.
  2842  *     @type int    $parent      The id of the parent term. Default 0.
  2102  *     @type int    'parent'      The id of the parent term.
  2843  *     @type string $slug        The term slug to use. Default empty string.
  2103  *                                Default 0.
       
  2104  *     @type string 'slug'        The term slug to use.
       
  2105  *                                Default empty string.
       
  2106  * }
  2844  * }
  2107  * @return array|WP_Error An array containing the term_id and term_taxonomy_id, WP_Error otherwise.
  2845  * @return array|WP_Error An array containing the `term_id` and `term_taxonomy_id`,
       
  2846  *                        {@see WP_Error} otherwise.
  2108  */
  2847  */
  2109 function wp_insert_term( $term, $taxonomy, $args = array() ) {
  2848 function wp_insert_term( $term, $taxonomy, $args = array() ) {
  2110 	global $wpdb;
  2849 	global $wpdb;
  2111 
  2850 
  2112 	if ( ! taxonomy_exists($taxonomy) )
  2851 	if ( ! taxonomy_exists($taxonomy) ) {
  2113 		return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
  2852 		return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
  2114 
  2853 	}
       
  2854 	/**
       
  2855 	 * Filter a term before it is sanitized and inserted into the database.
       
  2856 	 *
       
  2857 	 * @since 3.0.0
       
  2858 	 *
       
  2859 	 * @param string $term     The term to add or update.
       
  2860 	 * @param string $taxonomy Taxonomy slug.
       
  2861 	 */
  2115 	$term = apply_filters( 'pre_insert_term', $term, $taxonomy );
  2862 	$term = apply_filters( 'pre_insert_term', $term, $taxonomy );
  2116 		if ( is_wp_error( $term ) )
  2863 	if ( is_wp_error( $term ) ) {
  2117 			return $term;
  2864 		return $term;
  2118 
  2865 	}
  2119 	if ( is_int($term) && 0 == $term )
  2866 	if ( is_int($term) && 0 == $term ) {
  2120 		return new WP_Error('invalid_term_id', __('Invalid term ID'));
  2867 		return new WP_Error('invalid_term_id', __('Invalid term ID'));
  2121 
  2868 	}
  2122 	if ( '' == trim($term) )
  2869 	if ( '' == trim($term) ) {
  2123 		return new WP_Error('empty_term_name', __('A name is required for this term'));
  2870 		return new WP_Error('empty_term_name', __('A name is required for this term'));
  2124 
  2871 	}
  2125 	$defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
  2872 	$defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
  2126 	$args = wp_parse_args($args, $defaults);
  2873 	$args = wp_parse_args( $args, $defaults );
       
  2874 
       
  2875 	if ( $args['parent'] > 0 && ! term_exists( (int) $args['parent'] ) ) {
       
  2876 		return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
       
  2877 	}
  2127 	$args['name'] = $term;
  2878 	$args['name'] = $term;
  2128 	$args['taxonomy'] = $taxonomy;
  2879 	$args['taxonomy'] = $taxonomy;
  2129 	$args = sanitize_term($args, $taxonomy, 'db');
  2880 	$args = sanitize_term($args, $taxonomy, 'db');
  2130 	extract($args, EXTR_SKIP);
       
  2131 
  2881 
  2132 	// expected_slashed ($name)
  2882 	// expected_slashed ($name)
  2133 	$name = wp_unslash($name);
  2883 	$name = wp_unslash( $args['name'] );
  2134 	$description = wp_unslash($description);
  2884 	$description = wp_unslash( $args['description'] );
  2135 
  2885 	$parent = (int) $args['parent'];
  2136 	if ( empty($slug) )
  2886 
  2137 		$slug = sanitize_title($name);
  2887 	$slug_provided = ! empty( $args['slug'] );
       
  2888 	if ( ! $slug_provided ) {
       
  2889 		$slug = sanitize_title( $name );
       
  2890 	} else {
       
  2891 		$slug = $args['slug'];
       
  2892 	}
  2138 
  2893 
  2139 	$term_group = 0;
  2894 	$term_group = 0;
  2140 	if ( $alias_of ) {
  2895 	if ( $args['alias_of'] ) {
  2141 		$alias = $wpdb->get_row( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $alias_of) );
  2896 		$alias = get_term_by( 'slug', $args['alias_of'], $taxonomy );
  2142 		if ( $alias->term_group ) {
  2897 		if ( ! empty( $alias->term_group ) ) {
  2143 			// The alias we want is already in a group, so let's use that one.
  2898 			// The alias we want is already in a group, so let's use that one.
  2144 			$term_group = $alias->term_group;
  2899 			$term_group = $alias->term_group;
  2145 		} else {
  2900 		} elseif ( ! empty( $alias->term_id ) ) {
  2146 			// The alias isn't in a group, so let's create a new one and firstly add the alias term to it.
  2901 			/*
       
  2902 			 * The alias is not in a group, so we create a new one
       
  2903 			 * and add the alias to it.
       
  2904 			 */
  2147 			$term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
  2905 			$term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
  2148 			do_action( 'edit_terms', $alias->term_id, $taxonomy );
  2906 
  2149 			$wpdb->update($wpdb->terms, compact('term_group'), array('term_id' => $alias->term_id) );
  2907 			wp_update_term( $alias->term_id, $taxonomy, array(
  2150 			do_action( 'edited_terms', $alias->term_id, $taxonomy );
  2908 				'term_group' => $term_group,
  2151 		}
  2909 			) );
  2152 	}
  2910 		}
  2153 
  2911 	}
  2154 	if ( $term_id = term_exists($slug) ) {
  2912 
  2155 		$existing_term = $wpdb->get_row( $wpdb->prepare( "SELECT name FROM $wpdb->terms WHERE term_id = %d", $term_id), ARRAY_A );
  2913 	/*
  2156 		// We've got an existing term in the same taxonomy, which matches the name of the new term:
  2914 	 * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy,
  2157 		if ( is_taxonomy_hierarchical($taxonomy) && $existing_term['name'] == $name && $exists = term_exists( (int) $term_id, $taxonomy ) ) {
  2915 	 * unless a unique slug has been explicitly provided.
  2158 			// Hierarchical, and it matches an existing term, Do not allow same "name" in the same level.
  2916 	 */
  2159 			$siblings = get_terms($taxonomy, array('fields' => 'names', 'get' => 'all', 'parent' => (int)$parent) );
  2917 	if ( $name_match = get_term_by( 'name', $name, $taxonomy ) ) {
  2160 			if ( in_array($name, $siblings) ) {
  2918 		$slug_match = get_term_by( 'slug', $slug, $taxonomy );
  2161 				return new WP_Error('term_exists', __('A term with the name provided already exists with this parent.'), $exists['term_id']);
  2919 		if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) {
       
  2920 			if ( is_taxonomy_hierarchical( $taxonomy ) ) {
       
  2921 				$siblings = get_terms( $taxonomy, array( 'get' => 'all', 'parent' => $parent ) );
       
  2922 
       
  2923 				$existing_term = null;
       
  2924 				if ( $name_match->slug === $slug && in_array( $name, wp_list_pluck( $siblings, 'name' ) ) ) {
       
  2925 					$existing_term = $name_match;
       
  2926 				} elseif ( $slug_match && in_array( $slug, wp_list_pluck( $siblings, 'slug' ) ) ) {
       
  2927 					$existing_term = $slug_match;
       
  2928 				}
       
  2929 
       
  2930 				if ( $existing_term ) {
       
  2931 					return new WP_Error( 'term_exists', __( 'A term with the name already exists with this parent.' ), $existing_term->term_id );
       
  2932 				}
  2162 			} else {
  2933 			} else {
  2163 				$slug = wp_unique_term_slug($slug, (object) $args);
  2934 				return new WP_Error( 'term_exists', __( 'A term with the name already exists in this taxonomy.' ), $name_match->term_id );
  2164 				if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) )
       
  2165 					return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error);
       
  2166 				$term_id = (int) $wpdb->insert_id;
       
  2167 			}
  2935 			}
  2168 		} elseif ( $existing_term['name'] != $name ) {
  2936 		}
  2169 			// We've got an existing term, with a different name, Create the new term.
  2937 	}
  2170 			$slug = wp_unique_term_slug($slug, (object) $args);
  2938 
  2171 			if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) )
  2939 	$slug = wp_unique_term_slug( $slug, (object) $args );
  2172 				return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error);
  2940 
  2173 			$term_id = (int) $wpdb->insert_id;
  2941 	if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) {
  2174 		} elseif ( $exists = term_exists( (int) $term_id, $taxonomy ) )  {
  2942 		return new WP_Error( 'db_insert_error', __( 'Could not insert term into the database' ), $wpdb->last_error );
  2175 			// Same name, same slug.
  2943 	}
  2176 			return new WP_Error('term_exists', __('A term with the name provided already exists.'), $exists['term_id']);
  2944 
  2177 		}
  2945 	$term_id = (int) $wpdb->insert_id;
  2178 	} else {
       
  2179 		// This term does not exist at all in the database, Create it.
       
  2180 		$slug = wp_unique_term_slug($slug, (object) $args);
       
  2181 		if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) )
       
  2182 			return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error);
       
  2183 		$term_id = (int) $wpdb->insert_id;
       
  2184 	}
       
  2185 
  2946 
  2186 	// Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string.
  2947 	// Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string.
  2187 	if ( empty($slug) ) {
  2948 	if ( empty($slug) ) {
  2188 		$slug = sanitize_title($slug, $term_id);
  2949 		$slug = sanitize_title($slug, $term_id);
       
  2950 
       
  2951 		/** This action is documented in wp-includes/taxonomy.php */
  2189 		do_action( 'edit_terms', $term_id, $taxonomy );
  2952 		do_action( 'edit_terms', $term_id, $taxonomy );
  2190 		$wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
  2953 		$wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
       
  2954 
       
  2955 		/** This action is documented in wp-includes/taxonomy.php */
  2191 		do_action( 'edited_terms', $term_id, $taxonomy );
  2956 		do_action( 'edited_terms', $term_id, $taxonomy );
  2192 	}
  2957 	}
  2193 
  2958 
  2194 	$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 ) );
  2959 	$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 ) );
  2195 
  2960 
  2196 	if ( !empty($tt_id) )
  2961 	if ( !empty($tt_id) ) {
  2197 		return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
  2962 		return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
  2198 
  2963 	}
  2199 	$wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) );
  2964 	$wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) );
  2200 	$tt_id = (int) $wpdb->insert_id;
  2965 	$tt_id = (int) $wpdb->insert_id;
  2201 
  2966 
  2202 	do_action("create_term", $term_id, $tt_id, $taxonomy);
  2967 	/*
  2203 	do_action("create_$taxonomy", $term_id, $tt_id);
  2968 	 * Sanity check: if we just created a term with the same parent + taxonomy + slug but a higher term_id than
  2204 
  2969 	 * an existing term, then we have unwittingly created a duplicate term. Delete the dupe, and use the term_id
  2205 	$term_id = apply_filters('term_id_filter', $term_id, $tt_id);
  2970 	 * and term_taxonomy_id of the older term instead. Then return out of the function so that the "create" hooks
       
  2971 	 * are not fired.
       
  2972 	 */
       
  2973 	$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 ) );
       
  2974 	if ( $duplicate_term ) {
       
  2975 		$wpdb->delete( $wpdb->terms, array( 'term_id' => $term_id ) );
       
  2976 		$wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
       
  2977 
       
  2978 		$term_id = (int) $duplicate_term->term_id;
       
  2979 		$tt_id   = (int) $duplicate_term->term_taxonomy_id;
       
  2980 
       
  2981 		clean_term_cache( $term_id, $taxonomy );
       
  2982 		return array( 'term_id' => $term_id, 'term_taxonomy_id' => $tt_id );
       
  2983 	}
       
  2984 
       
  2985 	/**
       
  2986 	 * Fires immediately after a new term is created, before the term cache is cleaned.
       
  2987 	 *
       
  2988 	 * @since 2.3.0
       
  2989 	 *
       
  2990 	 * @param int    $term_id  Term ID.
       
  2991 	 * @param int    $tt_id    Term taxonomy ID.
       
  2992 	 * @param string $taxonomy Taxonomy slug.
       
  2993 	 */
       
  2994 	do_action( "create_term", $term_id, $tt_id, $taxonomy );
       
  2995 
       
  2996 	/**
       
  2997 	 * Fires after a new term is created for a specific taxonomy.
       
  2998 	 *
       
  2999 	 * The dynamic portion of the hook name, `$taxonomy`, refers
       
  3000 	 * to the slug of the taxonomy the term was created for.
       
  3001 	 *
       
  3002 	 * @since 2.3.0
       
  3003 	 *
       
  3004 	 * @param int $term_id Term ID.
       
  3005 	 * @param int $tt_id   Term taxonomy ID.
       
  3006 	 */
       
  3007 	do_action( "create_$taxonomy", $term_id, $tt_id );
       
  3008 
       
  3009 	/**
       
  3010 	 * Filter the term ID after a new term is created.
       
  3011 	 *
       
  3012 	 * @since 2.3.0
       
  3013 	 *
       
  3014 	 * @param int $term_id Term ID.
       
  3015 	 * @param int $tt_id   Taxonomy term ID.
       
  3016 	 */
       
  3017 	$term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
  2206 
  3018 
  2207 	clean_term_cache($term_id, $taxonomy);
  3019 	clean_term_cache($term_id, $taxonomy);
  2208 
  3020 
  2209 	do_action("created_term", $term_id, $tt_id, $taxonomy);
  3021 	/**
  2210 	do_action("created_$taxonomy", $term_id, $tt_id);
  3022 	 * Fires after a new term is created, and after the term cache has been cleaned.
       
  3023 	 *
       
  3024 	 * @since 2.3.0
       
  3025 	 */
       
  3026 	do_action( "created_term", $term_id, $tt_id, $taxonomy );
       
  3027 
       
  3028 	/**
       
  3029 	 * Fires after a new term in a specific taxonomy is created, and after the term
       
  3030 	 * cache has been cleaned.
       
  3031 	 *
       
  3032 	 * @since 2.3.0
       
  3033 	 *
       
  3034 	 * @param int $term_id Term ID.
       
  3035 	 * @param int $tt_id   Term taxonomy ID.
       
  3036 	 */
       
  3037 	do_action( "created_$taxonomy", $term_id, $tt_id );
  2211 
  3038 
  2212 	return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
  3039 	return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
  2213 }
  3040 }
  2214 
  3041 
  2215 /**
  3042 /**
  2221  *
  3048  *
  2222  * A relationship means that the term is grouped in or belongs to the taxonomy.
  3049  * A relationship means that the term is grouped in or belongs to the taxonomy.
  2223  * A term has no meaning until it is given context by defining which taxonomy it
  3050  * A term has no meaning until it is given context by defining which taxonomy it
  2224  * exists under.
  3051  * exists under.
  2225  *
  3052  *
  2226  * @package WordPress
       
  2227  * @subpackage Taxonomy
       
  2228  * @since 2.3.0
  3053  * @since 2.3.0
  2229  * @uses wp_remove_object_terms()
  3054  *
  2230  *
  3055  * @param int              $object_id The object to relate to.
  2231  * @param int $object_id The object to relate to.
  3056  * @param array|int|string $terms     A single term slug, single term id, or array of either term slugs or ids.
  2232  * @param array|int|string $terms The slug or id of the term, will replace all existing
  3057  *                                    Will replace all existing related terms in this taxonomy.
  2233  * related terms in this taxonomy.
  3058  * @param string           $taxonomy  The context in which to relate the term to the object.
  2234  * @param array|string $taxonomy The context in which to relate the term to the object.
  3059  * @param bool             $append    Optional. If false will delete difference of terms. Default false.
  2235  * @param bool $append If false will delete difference of terms.
  3060  * @return array|WP_Error Affected Term IDs.
  2236  * @return array|WP_Error Affected Term IDs
  3061  */
  2237  */
  3062 function wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false ) {
  2238 function wp_set_object_terms($object_id, $terms, $taxonomy, $append = false) {
       
  2239 	global $wpdb;
  3063 	global $wpdb;
  2240 
  3064 
  2241 	$object_id = (int) $object_id;
  3065 	$object_id = (int) $object_id;
  2242 
  3066 
  2243 	if ( ! taxonomy_exists($taxonomy) )
  3067 	if ( ! taxonomy_exists($taxonomy) )
  2271 		$tt_id = $term_info['term_taxonomy_id'];
  3095 		$tt_id = $term_info['term_taxonomy_id'];
  2272 		$tt_ids[] = $tt_id;
  3096 		$tt_ids[] = $tt_id;
  2273 
  3097 
  2274 		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 ) ) )
  3098 		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 ) ) )
  2275 			continue;
  3099 			continue;
       
  3100 
       
  3101 		/**
       
  3102 		 * Fires immediately before an object-term relationship is added.
       
  3103 		 *
       
  3104 		 * @since 2.9.0
       
  3105 		 *
       
  3106 		 * @param int $object_id Object ID.
       
  3107 		 * @param int $tt_id     Term taxonomy ID.
       
  3108 		 */
  2276 		do_action( 'add_term_relationship', $object_id, $tt_id );
  3109 		do_action( 'add_term_relationship', $object_id, $tt_id );
  2277 		$wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $tt_id ) );
  3110 		$wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $tt_id ) );
       
  3111 
       
  3112 		/**
       
  3113 		 * Fires immediately after an object-term relationship is added.
       
  3114 		 *
       
  3115 		 * @since 2.9.0
       
  3116 		 *
       
  3117 		 * @param int $object_id Object ID.
       
  3118 		 * @param int $tt_id     Term taxonomy ID.
       
  3119 		 */
  2278 		do_action( 'added_term_relationship', $object_id, $tt_id );
  3120 		do_action( 'added_term_relationship', $object_id, $tt_id );
  2279 		$new_tt_ids[] = $tt_id;
  3121 		$new_tt_ids[] = $tt_id;
  2280 	}
  3122 	}
  2281 
  3123 
  2282 	if ( $new_tt_ids )
  3124 	if ( $new_tt_ids )
  2310 				return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database' ), $wpdb->last_error );
  3152 				return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database' ), $wpdb->last_error );
  2311 	}
  3153 	}
  2312 
  3154 
  2313 	wp_cache_delete( $object_id, $taxonomy . '_relationships' );
  3155 	wp_cache_delete( $object_id, $taxonomy . '_relationships' );
  2314 
  3156 
  2315 	do_action('set_object_terms', $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids);
  3157 	/**
       
  3158 	 * Fires after an object's terms have been set.
       
  3159 	 *
       
  3160 	 * @since 2.8.0
       
  3161 	 *
       
  3162 	 * @param int    $object_id  Object ID.
       
  3163 	 * @param array  $terms      An array of object terms.
       
  3164 	 * @param array  $tt_ids     An array of term taxonomy IDs.
       
  3165 	 * @param string $taxonomy   Taxonomy slug.
       
  3166 	 * @param bool   $append     Whether to append new terms to the old terms.
       
  3167 	 * @param array  $old_tt_ids Old array of term taxonomy IDs.
       
  3168 	 */
       
  3169 	do_action( 'set_object_terms', $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids );
  2316 	return $tt_ids;
  3170 	return $tt_ids;
  2317 }
  3171 }
  2318 
  3172 
  2319 /**
  3173 /**
  2320  * Add term(s) associated with a given object.
  3174  * Add term(s) associated with a given object.
  2321  *
  3175  *
  2322  * @package WordPress
  3176  * @since 3.6.0
  2323  * @subpackage Taxonomy
       
  2324  * @since 3.6
       
  2325  * @uses wp_set_object_terms()
       
  2326  *
  3177  *
  2327  * @param int $object_id The ID of the object to which the terms will be added.
  3178  * @param int $object_id The ID of the object to which the terms will be added.
  2328  * @param array|int|string $terms The slug(s) or ID(s) of the term(s) to add.
  3179  * @param array|int|string $terms The slug(s) or ID(s) of the term(s) to add.
  2329  * @param array|string $taxonomy Taxonomy name.
  3180  * @param array|string $taxonomy Taxonomy name.
  2330  * @return array|WP_Error Affected Term IDs
  3181  * @return array|WP_Error Affected Term IDs
  2334 }
  3185 }
  2335 
  3186 
  2336 /**
  3187 /**
  2337  * Remove term(s) associated with a given object.
  3188  * Remove term(s) associated with a given object.
  2338  *
  3189  *
  2339  * @package WordPress
  3190  * @since 3.6.0
  2340  * @subpackage Taxonomy
  3191  *
  2341  * @since 3.6
  3192  * @global wpdb $wpdb WordPress database abstraction object.
  2342  * @uses $wpdb
       
  2343  *
       
  2344  * @uses apply_filters() Calls 'delete_term_relationships' hook with object_id and tt_ids as parameters.
       
  2345  * @uses apply_filters() Calls 'deleted_term_relationships' hook with object_id and tt_ids as parameters.
       
  2346  *
  3193  *
  2347  * @param int $object_id The ID of the object from which the terms will be removed.
  3194  * @param int $object_id The ID of the object from which the terms will be removed.
  2348  * @param array|int|string $terms The slug(s) or ID(s) of the term(s) to remove.
  3195  * @param array|int|string $terms The slug(s) or ID(s) of the term(s) to remove.
  2349  * @param array|string $taxonomy Taxonomy name.
  3196  * @param array|string $taxonomy Taxonomy name.
  2350  * @return bool|WP_Error True on success, false or WP_Error on failure.
  3197  * @return bool|WP_Error True on success, false or WP_Error on failure.
  2383 		$tt_ids[] = $term_info['term_taxonomy_id'];
  3230 		$tt_ids[] = $term_info['term_taxonomy_id'];
  2384 	}
  3231 	}
  2385 
  3232 
  2386 	if ( $tt_ids ) {
  3233 	if ( $tt_ids ) {
  2387 		$in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'";
  3234 		$in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'";
       
  3235 
       
  3236 		/**
       
  3237 		 * Fires immediately before an object-term relationship is deleted.
       
  3238 		 *
       
  3239 		 * @since 2.9.0
       
  3240 		 *
       
  3241 		 * @param int   $object_id Object ID.
       
  3242 		 * @param array $tt_ids    An array of term taxonomy IDs.
       
  3243 		 */
  2388 		do_action( 'delete_term_relationships', $object_id, $tt_ids );
  3244 		do_action( 'delete_term_relationships', $object_id, $tt_ids );
  2389 		$deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
  3245 		$deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
       
  3246 
       
  3247 		/**
       
  3248 		 * Fires immediately after an object-term relationship is deleted.
       
  3249 		 *
       
  3250 		 * @since 2.9.0
       
  3251 		 *
       
  3252 		 * @param int   $object_id Object ID.
       
  3253 		 * @param array $tt_ids    An array of term taxonomy IDs.
       
  3254 		 */
  2390 		do_action( 'deleted_term_relationships', $object_id, $tt_ids );
  3255 		do_action( 'deleted_term_relationships', $object_id, $tt_ids );
  2391 		wp_update_term_count( $tt_ids, $taxonomy );
  3256 		wp_update_term_count( $tt_ids, $taxonomy );
  2392 
  3257 
  2393 		return (bool) $deleted;
  3258 		return (bool) $deleted;
  2394 	}
  3259 	}
  2409  * If that still doesn't return an unique slug, then it try to append a number
  3274  * If that still doesn't return an unique slug, then it try to append a number
  2410  * until it finds a number that is truly unique.
  3275  * until it finds a number that is truly unique.
  2411  *
  3276  *
  2412  * The only purpose for $term is for appending a parent, if one exists.
  3277  * The only purpose for $term is for appending a parent, if one exists.
  2413  *
  3278  *
  2414  * @package WordPress
       
  2415  * @subpackage Taxonomy
       
  2416  * @since 2.3.0
  3279  * @since 2.3.0
  2417  * @uses $wpdb
  3280  *
       
  3281  * @global wpdb $wpdb WordPress database abstraction object.
  2418  *
  3282  *
  2419  * @param string $slug The string that will be tried for a unique slug
  3283  * @param string $slug The string that will be tried for a unique slug
  2420  * @param object $term The term object that the $slug will belong too
  3284  * @param object $term The term object that the $slug will belong too
  2421  * @return string Will return a true unique slug.
  3285  * @return string Will return a true unique slug.
  2422  */
  3286  */
  2423 function wp_unique_term_slug($slug, $term) {
  3287 function wp_unique_term_slug($slug, $term) {
  2424 	global $wpdb;
  3288 	global $wpdb;
  2425 
  3289 
  2426 	if ( ! term_exists( $slug ) )
  3290 	if ( ! term_exists( $slug ) )
  2427 		return $slug;
  3291 		return $slug;
       
  3292 
       
  3293 	// As of 4.1, duplicate slugs are allowed as long as they're in different taxonomies.
       
  3294 	if ( get_option( 'db_version' ) >= 30133 && ! get_term_by( 'slug', $slug, $term->taxonomy ) ) {
       
  3295 		return $slug;
       
  3296 	}
  2428 
  3297 
  2429 	// If the taxonomy supports hierarchy and the term has a parent, make the slug unique
  3298 	// If the taxonomy supports hierarchy and the term has a parent, make the slug unique
  2430 	// by incorporating parent slugs.
  3299 	// by incorporating parent slugs.
  2431 	if ( is_taxonomy_hierarchical($term->taxonomy) && !empty($term->parent) ) {
  3300 	if ( is_taxonomy_hierarchical($term->taxonomy) && !empty($term->parent) ) {
  2432 		$the_parent = $term->parent;
  3301 		$the_parent = $term->parent;
  2482  * will be created for you.
  3351  * will be created for you.
  2483  *
  3352  *
  2484  * For what can be overrode in $args, check the term scheme can contain and stay
  3353  * For what can be overrode in $args, check the term scheme can contain and stay
  2485  * away from the term keys.
  3354  * away from the term keys.
  2486  *
  3355  *
  2487  * @package WordPress
       
  2488  * @subpackage Taxonomy
       
  2489  * @since 2.3.0
  3356  * @since 2.3.0
  2490  *
  3357  *
  2491  * @uses $wpdb
  3358  * @global wpdb $wpdb WordPress database abstraction object.
  2492  * @uses do_action() Will call both 'edit_term' and 'edit_$taxonomy' twice.
       
  2493  * @uses apply_filters() Will call the 'term_id_filter' filter and pass the term
       
  2494  *	id and taxonomy id.
       
  2495  *
  3359  *
  2496  * @param int $term_id The ID of the term
  3360  * @param int $term_id The ID of the term
  2497  * @param string $taxonomy The context in which to relate the term to the object.
  3361  * @param string $taxonomy The context in which to relate the term to the object.
  2498  * @param array|string $args Overwrite term field values
  3362  * @param array|string $args Overwrite term field values
  2499  * @return array|WP_Error Returns Term ID and Taxonomy Term ID
  3363  * @return array|WP_Error Returns Term ID and Taxonomy Term ID
  2500  */
  3364  */
  2501 function wp_update_term( $term_id, $taxonomy, $args = array() ) {
  3365 function wp_update_term( $term_id, $taxonomy, $args = array() ) {
  2502 	global $wpdb;
  3366 	global $wpdb;
  2503 
  3367 
  2504 	if ( ! taxonomy_exists($taxonomy) )
  3368 	if ( ! taxonomy_exists( $taxonomy ) ) {
  2505 		return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
  3369 		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
       
  3370 	}
  2506 
  3371 
  2507 	$term_id = (int) $term_id;
  3372 	$term_id = (int) $term_id;
  2508 
  3373 
  2509 	// First, get all of the original args
  3374 	// First, get all of the original args
  2510 	$term = get_term ($term_id, $taxonomy, ARRAY_A);
  3375 	$term = get_term( $term_id, $taxonomy, ARRAY_A );
  2511 
  3376 
  2512 	if ( is_wp_error( $term ) )
  3377 	if ( is_wp_error( $term ) ) {
  2513 		return $term;
  3378 		return $term;
       
  3379 	}
       
  3380 
       
  3381 	if ( ! $term ) {
       
  3382 		return new WP_Error( 'invalid_term', __( 'Empty Term' ) );
       
  3383 	}
  2514 
  3384 
  2515 	// Escape data pulled from DB.
  3385 	// Escape data pulled from DB.
  2516 	$term = wp_slash($term);
  3386 	$term = wp_slash($term);
  2517 
  3387 
  2518 	// Merge old and new args with new args overwriting old ones.
  3388 	// Merge old and new args with new args overwriting old ones.
  2519 	$args = array_merge($term, $args);
  3389 	$args = array_merge($term, $args);
  2520 
  3390 
  2521 	$defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
  3391 	$defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
  2522 	$args = wp_parse_args($args, $defaults);
  3392 	$args = wp_parse_args($args, $defaults);
  2523 	$args = sanitize_term($args, $taxonomy, 'db');
  3393 	$args = sanitize_term($args, $taxonomy, 'db');
  2524 	extract($args, EXTR_SKIP);
  3394 	$parsed_args = $args;
  2525 
  3395 
  2526 	// expected_slashed ($name)
  3396 	// expected_slashed ($name)
  2527 	$name = wp_unslash($name);
  3397 	$name = wp_unslash( $args['name'] );
  2528 	$description = wp_unslash($description);
  3398 	$description = wp_unslash( $args['description'] );
       
  3399 
       
  3400 	$parsed_args['name'] = $name;
       
  3401 	$parsed_args['description'] = $description;
  2529 
  3402 
  2530 	if ( '' == trim($name) )
  3403 	if ( '' == trim($name) )
  2531 		return new WP_Error('empty_term_name', __('A name is required for this term'));
  3404 		return new WP_Error('empty_term_name', __('A name is required for this term'));
  2532 
  3405 
       
  3406 	if ( $parsed_args['parent'] > 0 && ! term_exists( (int) $parsed_args['parent'] ) ) {
       
  3407 		return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) );
       
  3408 	}
       
  3409 
  2533 	$empty_slug = false;
  3410 	$empty_slug = false;
  2534 	if ( empty($slug) ) {
  3411 	if ( empty( $args['slug'] ) ) {
  2535 		$empty_slug = true;
  3412 		$empty_slug = true;
  2536 		$slug = sanitize_title($name);
  3413 		$slug = sanitize_title($name);
  2537 	}
  3414 	} else {
  2538 
  3415 		$slug = $args['slug'];
  2539 	if ( $alias_of ) {
  3416 	}
  2540 		$alias = $wpdb->get_row( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $alias_of) );
  3417 
  2541 		if ( $alias->term_group ) {
  3418 	$parsed_args['slug'] = $slug;
       
  3419 
       
  3420 	$term_group = isset( $parsed_args['term_group'] ) ? $parsed_args['term_group'] : 0;
       
  3421 	if ( $args['alias_of'] ) {
       
  3422 		$alias = get_term_by( 'slug', $args['alias_of'], $taxonomy );
       
  3423 		if ( ! empty( $alias->term_group ) ) {
  2542 			// The alias we want is already in a group, so let's use that one.
  3424 			// The alias we want is already in a group, so let's use that one.
  2543 			$term_group = $alias->term_group;
  3425 			$term_group = $alias->term_group;
  2544 		} else {
  3426 		} elseif ( ! empty( $alias->term_id ) ) {
  2545 			// The alias isn't in a group, so let's create a new one and firstly add the alias term to it.
  3427 			/*
       
  3428 			 * The alias is not in a group, so we create a new one
       
  3429 			 * and add the alias to it.
       
  3430 			 */
  2546 			$term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
  3431 			$term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
  2547 			do_action( 'edit_terms', $alias->term_id, $taxonomy );
  3432 
  2548 			$wpdb->update( $wpdb->terms, compact('term_group'), array( 'term_id' => $alias->term_id ) );
  3433 			wp_update_term( $alias->term_id, $taxonomy, array(
  2549 			do_action( 'edited_terms', $alias->term_id, $taxonomy );
  3434 				'term_group' => $term_group,
  2550 		}
  3435 			) );
  2551 	}
  3436 		}
  2552 
  3437 
  2553 	// Check $parent to see if it will cause a hierarchy loop
  3438 		$parsed_args['term_group'] = $term_group;
  2554 	$parent = apply_filters( 'wp_update_term_parent', $parent, $term_id, $taxonomy, compact( array_keys( $args ) ), $args );
  3439 	}
       
  3440 
       
  3441 	/**
       
  3442 	 * Filter the term parent.
       
  3443 	 *
       
  3444 	 * Hook to this filter to see if it will cause a hierarchy loop.
       
  3445 	 *
       
  3446 	 * @since 3.1.0
       
  3447 	 *
       
  3448 	 * @param int    $parent      ID of the parent term.
       
  3449 	 * @param int    $term_id     Term ID.
       
  3450 	 * @param string $taxonomy    Taxonomy slug.
       
  3451 	 * @param array  $parsed_args An array of potentially altered update arguments for the given term.
       
  3452 	 * @param array  $args        An array of update arguments for the given term.
       
  3453 	 */
       
  3454 	$parent = apply_filters( 'wp_update_term_parent', $args['parent'], $term_id, $taxonomy, $parsed_args, $args );
  2555 
  3455 
  2556 	// Check for duplicate slug
  3456 	// Check for duplicate slug
  2557 	$id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE slug = %s", $slug ) );
  3457 	$duplicate = get_term_by( 'slug', $slug, $taxonomy );
  2558 	if ( $id && ($id != $term_id) ) {
  3458 	if ( $duplicate && $duplicate->term_id != $term_id ) {
  2559 		// If an empty slug was passed or the parent changed, reset the slug to something unique.
  3459 		// If an empty slug was passed or the parent changed, reset the slug to something unique.
  2560 		// Otherwise, bail.
  3460 		// Otherwise, bail.
  2561 		if ( $empty_slug || ( $parent != $term['parent']) )
  3461 		if ( $empty_slug || ( $parent != $term['parent']) )
  2562 			$slug = wp_unique_term_slug($slug, (object) $args);
  3462 			$slug = wp_unique_term_slug($slug, (object) $args);
  2563 		else
  3463 		else
  2564 			return new WP_Error('duplicate_term_slug', sprintf(__('The slug &#8220;%s&#8221; is already in use by another term'), $slug));
  3464 			return new WP_Error('duplicate_term_slug', sprintf(__('The slug &#8220;%s&#8221; is already in use by another term'), $slug));
  2565 	}
  3465 	}
       
  3466 
       
  3467 	$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) );
       
  3468 
       
  3469 	// Check whether this is a shared term that needs splitting.
       
  3470 	$_term_id = _split_shared_term( $term_id, $tt_id );
       
  3471 	if ( ! is_wp_error( $_term_id ) ) {
       
  3472 		$term_id = $_term_id;
       
  3473 	}
       
  3474 
       
  3475 	/**
       
  3476 	 * Fires immediately before the given terms are edited.
       
  3477 	 *
       
  3478 	 * @since 2.9.0
       
  3479 	 *
       
  3480 	 * @param int    $term_id  Term ID.
       
  3481 	 * @param string $taxonomy Taxonomy slug.
       
  3482 	 */
  2566 	do_action( 'edit_terms', $term_id, $taxonomy );
  3483 	do_action( 'edit_terms', $term_id, $taxonomy );
  2567 	$wpdb->update($wpdb->terms, compact( 'name', 'slug', 'term_group' ), compact( 'term_id' ) );
  3484 	$wpdb->update($wpdb->terms, compact( 'name', 'slug', 'term_group' ), compact( 'term_id' ) );
  2568 	if ( empty($slug) ) {
  3485 	if ( empty($slug) ) {
  2569 		$slug = sanitize_title($name, $term_id);
  3486 		$slug = sanitize_title($name, $term_id);
  2570 		$wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
  3487 		$wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
  2571 	}
  3488 	}
       
  3489 
       
  3490 	/**
       
  3491 	 * Fires immediately after the given terms are edited.
       
  3492 	 *
       
  3493 	 * @since 2.9.0
       
  3494 	 *
       
  3495 	 * @param int    $term_id  Term ID
       
  3496 	 * @param string $taxonomy Taxonomy slug.
       
  3497 	 */
  2572 	do_action( 'edited_terms', $term_id, $taxonomy );
  3498 	do_action( 'edited_terms', $term_id, $taxonomy );
  2573 
  3499 
  2574 	$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) );
  3500 	/**
       
  3501 	 * Fires immediate before a term-taxonomy relationship is updated.
       
  3502 	 *
       
  3503 	 * @since 2.9.0
       
  3504 	 *
       
  3505 	 * @param int    $tt_id    Term taxonomy ID.
       
  3506 	 * @param string $taxonomy Taxonomy slug.
       
  3507 	 */
  2575 	do_action( 'edit_term_taxonomy', $tt_id, $taxonomy );
  3508 	do_action( 'edit_term_taxonomy', $tt_id, $taxonomy );
  2576 	$wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) );
  3509 	$wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) );
       
  3510 
       
  3511 	/**
       
  3512 	 * Fires immediately after a term-taxonomy relationship is updated.
       
  3513 	 *
       
  3514 	 * @since 2.9.0
       
  3515 	 *
       
  3516 	 * @param int    $tt_id    Term taxonomy ID.
       
  3517 	 * @param string $taxonomy Taxonomy slug.
       
  3518 	 */
  2577 	do_action( 'edited_term_taxonomy', $tt_id, $taxonomy );
  3519 	do_action( 'edited_term_taxonomy', $tt_id, $taxonomy );
  2578 
  3520 
  2579 	do_action("edit_term", $term_id, $tt_id, $taxonomy);
  3521 	// Clean the relationship caches for all object types using this term
  2580 	do_action("edit_$taxonomy", $term_id, $tt_id);
  3522 	$objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
  2581 
  3523 	$tax_object = get_taxonomy( $taxonomy );
  2582 	$term_id = apply_filters('term_id_filter', $term_id, $tt_id);
  3524 	foreach ( $tax_object->object_type as $object_type ) {
       
  3525 		clean_object_term_cache( $objects, $object_type );
       
  3526 	}
       
  3527 
       
  3528 	/**
       
  3529 	 * Fires after a term has been updated, but before the term cache has been cleaned.
       
  3530 	 *
       
  3531 	 * @since 2.3.0
       
  3532 	 *
       
  3533 	 * @param int    $term_id  Term ID.
       
  3534 	 * @param int    $tt_id    Term taxonomy ID.
       
  3535 	 * @param string $taxonomy Taxonomy slug.
       
  3536 	 */
       
  3537 	do_action( "edit_term", $term_id, $tt_id, $taxonomy );
       
  3538 
       
  3539 	/**
       
  3540 	 * Fires after a term in a specific taxonomy has been updated, but before the term
       
  3541 	 * cache has been cleaned.
       
  3542 	 *
       
  3543 	 * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
       
  3544 	 *
       
  3545 	 * @since 2.3.0
       
  3546 	 *
       
  3547 	 * @param int $term_id Term ID.
       
  3548 	 * @param int $tt_id   Term taxonomy ID.
       
  3549 	 */
       
  3550 	do_action( "edit_$taxonomy", $term_id, $tt_id );
       
  3551 
       
  3552 	/** This filter is documented in wp-includes/taxonomy.php */
       
  3553 	$term_id = apply_filters( 'term_id_filter', $term_id, $tt_id );
  2583 
  3554 
  2584 	clean_term_cache($term_id, $taxonomy);
  3555 	clean_term_cache($term_id, $taxonomy);
  2585 
  3556 
  2586 	do_action("edited_term", $term_id, $tt_id, $taxonomy);
  3557 	/**
  2587 	do_action("edited_$taxonomy", $term_id, $tt_id);
  3558 	 * Fires after a term has been updated, and the term cache has been cleaned.
       
  3559 	 *
       
  3560 	 * @since 2.3.0
       
  3561 	 *
       
  3562 	 * @param int    $term_id  Term ID.
       
  3563 	 * @param int    $tt_id    Term taxonomy ID.
       
  3564 	 * @param string $taxonomy Taxonomy slug.
       
  3565 	 */
       
  3566 	do_action( "edited_term", $term_id, $tt_id, $taxonomy );
       
  3567 
       
  3568 	/**
       
  3569 	 * Fires after a term for a specific taxonomy has been updated, and the term
       
  3570 	 * cache has been cleaned.
       
  3571 	 *
       
  3572 	 * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
       
  3573 	 *
       
  3574 	 * @since 2.3.0
       
  3575 	 *
       
  3576 	 * @param int $term_id Term ID.
       
  3577 	 * @param int $tt_id   Term taxonomy ID.
       
  3578 	 */
       
  3579 	do_action( "edited_$taxonomy", $term_id, $tt_id );
  2588 
  3580 
  2589 	return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
  3581 	return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
  2590 }
  3582 }
  2591 
  3583 
  2592 /**
  3584 /**
  2617  * the count.
  3609  * the count.
  2618  *
  3610  *
  2619  * The default action is to count what the amount of terms have the relationship
  3611  * The default action is to count what the amount of terms have the relationship
  2620  * of term ID. Once that is done, then update the database.
  3612  * of term ID. Once that is done, then update the database.
  2621  *
  3613  *
  2622  * @package WordPress
       
  2623  * @subpackage Taxonomy
       
  2624  * @since 2.3.0
  3614  * @since 2.3.0
  2625  * @uses $wpdb
  3615  *
       
  3616  * @global wpdb $wpdb WordPress database abstraction object.
  2626  *
  3617  *
  2627  * @param int|array $terms The term_taxonomy_id of the terms
  3618  * @param int|array $terms The term_taxonomy_id of the terms
  2628  * @param string $taxonomy The context of the term.
  3619  * @param string $taxonomy The context of the term.
  2629  * @return bool If no terms will return false, and if successful will return true.
  3620  * @return bool If no terms will return false, and if successful will return true.
  2630  */
  3621  */
  2662  * @param array $terms The term_taxonomy_id of terms to update.
  3653  * @param array $terms The term_taxonomy_id of terms to update.
  2663  * @param string $taxonomy The context of the term.
  3654  * @param string $taxonomy The context of the term.
  2664  * @return bool Always true when complete.
  3655  * @return bool Always true when complete.
  2665  */
  3656  */
  2666 function wp_update_term_count_now( $terms, $taxonomy ) {
  3657 function wp_update_term_count_now( $terms, $taxonomy ) {
  2667 	global $wpdb;
       
  2668 
       
  2669 	$terms = array_map('intval', $terms);
  3658 	$terms = array_map('intval', $terms);
  2670 
  3659 
  2671 	$taxonomy = get_taxonomy($taxonomy);
  3660 	$taxonomy = get_taxonomy($taxonomy);
  2672 	if ( !empty($taxonomy->update_count_callback) ) {
  3661 	if ( !empty($taxonomy->update_count_callback) ) {
  2673 		call_user_func($taxonomy->update_count_callback, $terms, $taxonomy);
  3662 		call_user_func($taxonomy->update_count_callback, $terms, $taxonomy);
  2701  *
  3690  *
  2702  * Will remove the entire taxonomy relationship containing term $object_id. The
  3691  * Will remove the entire taxonomy relationship containing term $object_id. The
  2703  * term IDs have to exist within the taxonomy $object_type for the deletion to
  3692  * term IDs have to exist within the taxonomy $object_type for the deletion to
  2704  * take place.
  3693  * take place.
  2705  *
  3694  *
  2706  * @package WordPress
       
  2707  * @subpackage Taxonomy
       
  2708  * @since 2.3.0
  3695  * @since 2.3.0
  2709  *
  3696  *
  2710  * @see get_object_taxonomies() for more on $object_type
  3697  * @see get_object_taxonomies() for more on $object_type
  2711  * @uses do_action() Will call action hook named, 'clean_object_term_cache' after completion.
       
  2712  *	Passes, function params in same order.
       
  2713  *
  3698  *
  2714  * @param int|array $object_ids Single or list of term object ID(s)
  3699  * @param int|array $object_ids Single or list of term object ID(s)
  2715  * @param array|string $object_type The taxonomy object type
  3700  * @param array|string $object_type The taxonomy object type
  2716  */
  3701  */
  2717 function clean_object_term_cache($object_ids, $object_type) {
  3702 function clean_object_term_cache($object_ids, $object_type) {
  2718 	if ( !is_array($object_ids) )
  3703 	if ( !is_array($object_ids) )
  2719 		$object_ids = array($object_ids);
  3704 		$object_ids = array($object_ids);
  2720 
  3705 
  2721 	$taxonomies = get_object_taxonomies( $object_type );
  3706 	$taxonomies = get_object_taxonomies( $object_type );
  2722 
  3707 
  2723 	foreach ( $object_ids as $id )
  3708 	foreach ( $object_ids as $id ) {
  2724 		foreach ( $taxonomies as $taxonomy )
  3709 		foreach ( $taxonomies as $taxonomy ) {
  2725 			wp_cache_delete($id, "{$taxonomy}_relationships");
  3710 			wp_cache_delete($id, "{$taxonomy}_relationships");
  2726 
  3711 		}
  2727 	do_action('clean_object_term_cache', $object_ids, $object_type);
  3712 	}
       
  3713 
       
  3714 	/**
       
  3715 	 * Fires after the object term cache has been cleaned.
       
  3716 	 *
       
  3717 	 * @since 2.5.0
       
  3718 	 *
       
  3719 	 * @param array  $object_ids An array of object IDs.
       
  3720 	 * @param string $objet_type Object type.
       
  3721 	 */
       
  3722 	do_action( 'clean_object_term_cache', $object_ids, $object_type );
  2728 }
  3723 }
  2729 
  3724 
  2730 /**
  3725 /**
  2731  * Will remove all of the term ids from the cache.
  3726  * Will remove all of the term ids from the cache.
  2732  *
  3727  *
  2733  * @package WordPress
       
  2734  * @subpackage Taxonomy
       
  2735  * @since 2.3.0
  3728  * @since 2.3.0
  2736  * @uses $wpdb
  3729  *
       
  3730  * @global wpdb $wpdb WordPress database abstraction object.
  2737  *
  3731  *
  2738  * @param int|array $ids Single or list of Term IDs
  3732  * @param int|array $ids Single or list of Term IDs
  2739  * @param string $taxonomy Can be empty and will assume tt_ids, else will use for context.
  3733  * @param string $taxonomy Can be empty and will assume tt_ids, else will use for context.
  2740  * @param bool $clean_taxonomy Whether to clean taxonomy wide caches (true), or just individual term object caches (false). Default is true.
  3734  * @param bool $clean_taxonomy Whether to clean taxonomy wide caches (true), or just individual term object caches (false). Default is true.
  2741  */
  3735  */
  2742 function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) {
  3736 function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) {
  2743 	global $wpdb;
  3737 	global $wpdb;
  2744 	static $cleaned = array();
       
  2745 
  3738 
  2746 	if ( !is_array($ids) )
  3739 	if ( !is_array($ids) )
  2747 		$ids = array($ids);
  3740 		$ids = array($ids);
  2748 
  3741 
  2749 	$taxonomies = array();
  3742 	$taxonomies = array();
  2767 			}
  3760 			}
  2768 		}
  3761 		}
  2769 	}
  3762 	}
  2770 
  3763 
  2771 	foreach ( $taxonomies as $taxonomy ) {
  3764 	foreach ( $taxonomies as $taxonomy ) {
  2772 		if ( isset($cleaned[$taxonomy]) )
       
  2773 			continue;
       
  2774 		$cleaned[$taxonomy] = true;
       
  2775 
       
  2776 		if ( $clean_taxonomy ) {
  3765 		if ( $clean_taxonomy ) {
  2777 			wp_cache_delete('all_ids', $taxonomy);
  3766 			wp_cache_delete('all_ids', $taxonomy);
  2778 			wp_cache_delete('get', $taxonomy);
  3767 			wp_cache_delete('get', $taxonomy);
  2779 			delete_option("{$taxonomy}_children");
  3768 			delete_option("{$taxonomy}_children");
  2780 			// Regenerate {$taxonomy}_children
  3769 			// Regenerate {$taxonomy}_children
  2781 			_get_term_hierarchy($taxonomy);
  3770 			_get_term_hierarchy($taxonomy);
  2782 		}
  3771 		}
  2783 
  3772 
  2784 		do_action('clean_term_cache', $ids, $taxonomy);
  3773 		/**
       
  3774 		 * Fires once after each taxonomy's term cache has been cleaned.
       
  3775 		 *
       
  3776 		 * @since 2.5.0
       
  3777 		 *
       
  3778 		 * @param array  $ids      An array of term IDs.
       
  3779 		 * @param string $taxonomy Taxonomy slug.
       
  3780 		 */
       
  3781 		do_action( 'clean_term_cache', $ids, $taxonomy );
  2785 	}
  3782 	}
  2786 
  3783 
  2787 	wp_cache_set( 'last_changed', microtime(), 'terms' );
  3784 	wp_cache_set( 'last_changed', microtime(), 'terms' );
  2788 }
  3785 }
  2789 
  3786 
  2790 /**
  3787 /**
  2791  * Retrieves the taxonomy relationship to the term object id.
  3788  * Retrieves the taxonomy relationship to the term object id.
  2792  *
  3789  *
  2793  * @package WordPress
       
  2794  * @subpackage Taxonomy
       
  2795  * @since 2.3.0
  3790  * @since 2.3.0
  2796  *
  3791  *
  2797  * @uses wp_cache_get() Retrieves taxonomy relationship from cache
  3792  * @param int    $id       Term object ID
  2798  *
       
  2799  * @param int|array $id Term object ID
       
  2800  * @param string $taxonomy Taxonomy Name
  3793  * @param string $taxonomy Taxonomy Name
  2801  * @return bool|array Empty array if $terms found, but not $taxonomy. False if nothing is in cache for $taxonomy and $id.
  3794  * @return bool|array Empty array if $terms found, but not $taxonomy. False if nothing is in cache for $taxonomy and $id.
  2802  */
  3795  */
  2803 function get_object_term_cache($id, $taxonomy) {
  3796 function get_object_term_cache($id, $taxonomy) {
  2804 	$cache = wp_cache_get($id, "{$taxonomy}_relationships");
  3797 	$cache = wp_cache_get($id, "{$taxonomy}_relationships");
  2805 	return $cache;
  3798 	return $cache;
  2806 }
  3799 }
  2807 
  3800 
  2808 /**
  3801 /**
  2809  * Updates the cache for Term ID(s).
  3802  * Updates the cache for the given term object ID(s).
  2810  *
  3803  *
  2811  * Will only update the cache for terms not already cached.
  3804  * Note: Due to performance concerns, great care should be taken to only update
  2812  *
  3805  * term caches when necessary. Processing time can increase exponentially depending
  2813  * The $object_ids expects that the ids be separated by commas, if it is a
  3806  * on both the number of passed term IDs and the number of taxonomies those terms
  2814  * string.
  3807  * belong to.
  2815  *
  3808  *
  2816  * It should be noted that update_object_term_cache() is very time extensive. It
  3809  * Caches will only be updated for terms not already cached.
  2817  * is advised that the function is not called very often or at least not for a
  3810  *
  2818  * lot of terms that exist in a lot of taxonomies. The amount of time increases
       
  2819  * for each term and it also increases for each taxonomy the term belongs to.
       
  2820  *
       
  2821  * @package WordPress
       
  2822  * @subpackage Taxonomy
       
  2823  * @since 2.3.0
  3811  * @since 2.3.0
  2824  * @uses wp_get_object_terms() Used to get terms from the database to update
  3812  *
  2825  *
  3813  * @param string|array $object_ids  Comma-separated list or array of term object IDs..
  2826  * @param string|array $object_ids Single or list of term object ID(s)
  3814  * @param array|string $object_type The taxonomy object type.
  2827  * @param array|string $object_type The taxonomy object type
  3815  * @return null|false Null if `$object_ids` is empty, false if all of the terms in
  2828  * @return null|bool Null value is given with empty $object_ids. False if
  3816  *                    `$object_ids` are already cached.
  2829  */
  3817  */
  2830 function update_object_term_cache($object_ids, $object_type) {
  3818 function update_object_term_cache($object_ids, $object_type) {
  2831 	if ( empty($object_ids) )
  3819 	if ( empty($object_ids) )
  2832 		return;
  3820 		return;
  2833 
  3821 
  2853 
  3841 
  2854 	$terms = wp_get_object_terms($ids, $taxonomies, array('fields' => 'all_with_object_id'));
  3842 	$terms = wp_get_object_terms($ids, $taxonomies, array('fields' => 'all_with_object_id'));
  2855 
  3843 
  2856 	$object_terms = array();
  3844 	$object_terms = array();
  2857 	foreach ( (array) $terms as $term )
  3845 	foreach ( (array) $terms as $term )
  2858 		$object_terms[$term->object_id][$term->taxonomy][$term->term_id] = $term;
  3846 		$object_terms[$term->object_id][$term->taxonomy][] = $term;
  2859 
  3847 
  2860 	foreach ( $ids as $id ) {
  3848 	foreach ( $ids as $id ) {
  2861 		foreach ( $taxonomies as $taxonomy ) {
  3849 		foreach ( $taxonomies as $taxonomy ) {
  2862 			if ( ! isset($object_terms[$id][$taxonomy]) ) {
  3850 			if ( ! isset($object_terms[$id][$taxonomy]) ) {
  2863 				if ( !isset($object_terms[$id]) )
  3851 				if ( !isset($object_terms[$id]) )
  2875 }
  3863 }
  2876 
  3864 
  2877 /**
  3865 /**
  2878  * Updates Terms to Taxonomy in cache.
  3866  * Updates Terms to Taxonomy in cache.
  2879  *
  3867  *
  2880  * @package WordPress
       
  2881  * @subpackage Taxonomy
       
  2882  * @since 2.3.0
  3868  * @since 2.3.0
  2883  *
  3869  *
  2884  * @param array $terms List of Term objects to change
  3870  * @param array $terms List of Term objects to change
  2885  * @param string $taxonomy Optional. Update Term to this taxonomy in cache
  3871  * @param string $taxonomy Optional. Update Term to this taxonomy in cache
  2886  */
  3872  */
  2888 	foreach ( (array) $terms as $term ) {
  3874 	foreach ( (array) $terms as $term ) {
  2889 		$term_taxonomy = $taxonomy;
  3875 		$term_taxonomy = $taxonomy;
  2890 		if ( empty($term_taxonomy) )
  3876 		if ( empty($term_taxonomy) )
  2891 			$term_taxonomy = $term->taxonomy;
  3877 			$term_taxonomy = $term->taxonomy;
  2892 
  3878 
  2893 		wp_cache_add($term->term_id, $term, $term_taxonomy);
  3879 		wp_cache_add( $term->term_id, $term, $term_taxonomy );
  2894 	}
  3880 	}
  2895 }
  3881 }
  2896 
  3882 
  2897 //
  3883 //
  2898 // Private
  3884 // Private
  2899 //
  3885 //
  2900 
  3886 
  2901 /**
  3887 /**
  2902  * Retrieves children of taxonomy as Term IDs.
  3888  * Retrieves children of taxonomy as Term IDs.
  2903  *
  3889  *
  2904  * @package WordPress
       
  2905  * @subpackage Taxonomy
       
  2906  * @access private
  3890  * @access private
  2907  * @since 2.3.0
  3891  * @since 2.3.0
  2908  *
       
  2909  * @uses update_option() Stores all of the children in "$taxonomy_children"
       
  2910  *	 option. That is the name of the taxonomy, immediately followed by '_children'.
       
  2911  *
  3892  *
  2912  * @param string $taxonomy Taxonomy Name
  3893  * @param string $taxonomy Taxonomy Name
  2913  * @return array Empty if $taxonomy isn't hierarchical or returns children as Term IDs.
  3894  * @return array Empty if $taxonomy isn't hierarchical or returns children as Term IDs.
  2914  */
  3895  */
  2915 function _get_term_hierarchy($taxonomy) {
  3896 function _get_term_hierarchy($taxonomy) {
  2934  * Get the subset of $terms that are descendants of $term_id.
  3915  * Get the subset of $terms that are descendants of $term_id.
  2935  *
  3916  *
  2936  * If $terms is an array of objects, then _get_term_children returns an array of objects.
  3917  * If $terms is an array of objects, then _get_term_children returns an array of objects.
  2937  * If $terms is an array of IDs, then _get_term_children returns an array of IDs.
  3918  * If $terms is an array of IDs, then _get_term_children returns an array of IDs.
  2938  *
  3919  *
  2939  * @package WordPress
       
  2940  * @subpackage Taxonomy
       
  2941  * @access private
  3920  * @access private
  2942  * @since 2.3.0
  3921  * @since 2.3.0
  2943  *
  3922  *
  2944  * @param int $term_id The ancestor term: all returned terms should be descendants of $term_id.
  3923  * @param int $term_id The ancestor term: all returned terms should be descendants of $term_id.
  2945  * @param array $terms The set of terms---either an array of term objects or term IDs---from which those that are descendants of $term_id will be chosen.
  3924  * @param array  $terms     The set of terms - either an array of term objects or term IDs - from which those that
  2946  * @param string $taxonomy The taxonomy which determines the hierarchy of the terms.
  3925  *                          are descendants of $term_id will be chosen.
       
  3926  * @param string $taxonomy  The taxonomy which determines the hierarchy of the terms.
       
  3927  * @param array  $ancestors Term ancestors that have already been identified. Passed by reference, to keep track of
       
  3928  *                          found terms when recursing the hierarchy. The array of located ancestors is used to prevent
       
  3929  *                          infinite recursion loops. For performance, term_ids are used as array keys, with 1 as value.
  2947  * @return array The subset of $terms that are descendants of $term_id.
  3930  * @return array The subset of $terms that are descendants of $term_id.
  2948  */
  3931  */
  2949 function _get_term_children($term_id, $terms, $taxonomy) {
  3932 function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) {
  2950 	$empty_array = array();
  3933 	$empty_array = array();
  2951 	if ( empty($terms) )
  3934 	if ( empty($terms) )
  2952 		return $empty_array;
  3935 		return $empty_array;
  2953 
  3936 
  2954 	$term_list = array();
  3937 	$term_list = array();
  2955 	$has_children = _get_term_hierarchy($taxonomy);
  3938 	$has_children = _get_term_hierarchy($taxonomy);
  2956 
  3939 
  2957 	if  ( ( 0 != $term_id ) && ! isset($has_children[$term_id]) )
  3940 	if  ( ( 0 != $term_id ) && ! isset($has_children[$term_id]) )
  2958 		return $empty_array;
  3941 		return $empty_array;
       
  3942 
       
  3943 	// Include the term itself in the ancestors array, so we can properly detect when a loop has occurred.
       
  3944 	if ( empty( $ancestors ) ) {
       
  3945 		$ancestors[ $term_id ] = 1;
       
  3946 	}
  2959 
  3947 
  2960 	foreach ( (array) $terms as $term ) {
  3948 	foreach ( (array) $terms as $term ) {
  2961 		$use_id = false;
  3949 		$use_id = false;
  2962 		if ( !is_object($term) ) {
  3950 		if ( !is_object($term) ) {
  2963 			$term = get_term($term, $taxonomy);
  3951 			$term = get_term($term, $taxonomy);
  2964 			if ( is_wp_error( $term ) )
  3952 			if ( is_wp_error( $term ) )
  2965 				return $term;
  3953 				return $term;
  2966 			$use_id = true;
  3954 			$use_id = true;
  2967 		}
  3955 		}
  2968 
  3956 
  2969 		if ( $term->term_id == $term_id )
  3957 		// Don't recurse if we've already identified the term as a child - this indicates a loop.
       
  3958 		if ( isset( $ancestors[ $term->term_id ] ) ) {
  2970 			continue;
  3959 			continue;
       
  3960 		}
  2971 
  3961 
  2972 		if ( $term->parent == $term_id ) {
  3962 		if ( $term->parent == $term_id ) {
  2973 			if ( $use_id )
  3963 			if ( $use_id )
  2974 				$term_list[] = $term->term_id;
  3964 				$term_list[] = $term->term_id;
  2975 			else
  3965 			else
  2976 				$term_list[] = $term;
  3966 				$term_list[] = $term;
  2977 
  3967 
  2978 			if ( !isset($has_children[$term->term_id]) )
  3968 			if ( !isset($has_children[$term->term_id]) )
  2979 				continue;
  3969 				continue;
  2980 
  3970 
  2981 			if ( $children = _get_term_children($term->term_id, $terms, $taxonomy) )
  3971 			$ancestors[ $term->term_id ] = 1;
       
  3972 
       
  3973 			if ( $children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors) )
  2982 				$term_list = array_merge($term_list, $children);
  3974 				$term_list = array_merge($term_list, $children);
  2983 		}
  3975 		}
  2984 	}
  3976 	}
  2985 
  3977 
  2986 	return $term_list;
  3978 	return $term_list;
  2990  * Add count of children to parent count.
  3982  * Add count of children to parent count.
  2991  *
  3983  *
  2992  * Recalculates term counts by including items from child terms. Assumes all
  3984  * Recalculates term counts by including items from child terms. Assumes all
  2993  * relevant children are already in the $terms argument.
  3985  * relevant children are already in the $terms argument.
  2994  *
  3986  *
  2995  * @package WordPress
       
  2996  * @subpackage Taxonomy
       
  2997  * @access private
  3987  * @access private
  2998  * @since 2.3.0
  3988  * @since 2.3.0
  2999  * @uses $wpdb
  3989  *
       
  3990  * @global wpdb $wpdb WordPress database abstraction object.
  3000  *
  3991  *
  3001  * @param array $terms List of Term IDs
  3992  * @param array $terms List of Term IDs
  3002  * @param string $taxonomy Term Context
  3993  * @param string $taxonomy Term Context
  3003  * @return null Will break from function if conditions are not met.
  3994  * @return null Will break from function if conditions are not met.
  3004  */
  3995  */
  3013 
  4004 
  3014 	if ( empty($term_hier) )
  4005 	if ( empty($term_hier) )
  3015 		return;
  4006 		return;
  3016 
  4007 
  3017 	$term_items = array();
  4008 	$term_items = array();
       
  4009 	$terms_by_id = array();
       
  4010 	$term_ids = array();
  3018 
  4011 
  3019 	foreach ( (array) $terms as $key => $term ) {
  4012 	foreach ( (array) $terms as $key => $term ) {
  3020 		$terms_by_id[$term->term_id] = & $terms[$key];
  4013 		$terms_by_id[$term->term_id] = & $terms[$key];
  3021 		$term_ids[$term->term_taxonomy_id] = $term->term_id;
  4014 		$term_ids[$term->term_taxonomy_id] = $term->term_id;
  3022 	}
  4015 	}
  3031 	}
  4024 	}
  3032 
  4025 
  3033 	// Touch every ancestor's lookup row for each post in each term
  4026 	// Touch every ancestor's lookup row for each post in each term
  3034 	foreach ( $term_ids as $term_id ) {
  4027 	foreach ( $term_ids as $term_id ) {
  3035 		$child = $term_id;
  4028 		$child = $term_id;
       
  4029 		$ancestors = array();
  3036 		while ( !empty( $terms_by_id[$child] ) && $parent = $terms_by_id[$child]->parent ) {
  4030 		while ( !empty( $terms_by_id[$child] ) && $parent = $terms_by_id[$child]->parent ) {
       
  4031 			$ancestors[] = $child;
  3037 			if ( !empty( $term_items[$term_id] ) )
  4032 			if ( !empty( $term_items[$term_id] ) )
  3038 				foreach ( $term_items[$term_id] as $item_id => $touches ) {
  4033 				foreach ( $term_items[$term_id] as $item_id => $touches ) {
  3039 					$term_items[$parent][$item_id] = isset($term_items[$parent][$item_id]) ? ++$term_items[$parent][$item_id]: 1;
  4034 					$term_items[$parent][$item_id] = isset($term_items[$parent][$item_id]) ? ++$term_items[$parent][$item_id]: 1;
  3040 				}
  4035 				}
  3041 			$child = $parent;
  4036 			$child = $parent;
       
  4037 
       
  4038 			if ( in_array( $parent, $ancestors ) ) {
       
  4039 				break;
       
  4040 			}
  3042 		}
  4041 		}
  3043 	}
  4042 	}
  3044 
  4043 
  3045 	// Transfer the touched cells
  4044 	// Transfer the touched cells
  3046 	foreach ( (array) $term_items as $id => $items )
  4045 	foreach ( (array) $term_items as $id => $items )
  3056  * Will update term count based on object types of the current taxonomy.
  4055  * Will update term count based on object types of the current taxonomy.
  3057  *
  4056  *
  3058  * Private function for the default callback for post_tag and category
  4057  * Private function for the default callback for post_tag and category
  3059  * taxonomies.
  4058  * taxonomies.
  3060  *
  4059  *
  3061  * @package WordPress
       
  3062  * @subpackage Taxonomy
       
  3063  * @access private
  4060  * @access private
  3064  * @since 2.3.0
  4061  * @since 2.3.0
  3065  * @uses $wpdb
  4062  *
       
  4063  * @global wpdb $wpdb WordPress database abstraction object.
  3066  *
  4064  *
  3067  * @param array $terms List of Term taxonomy IDs
  4065  * @param array $terms List of Term taxonomy IDs
  3068  * @param object $taxonomy Current taxonomy object of terms
  4066  * @param object $taxonomy Current taxonomy object of terms
  3069  */
  4067  */
  3070 function _update_post_term_count( $terms, $taxonomy ) {
  4068 function _update_post_term_count( $terms, $taxonomy ) {
  3093 			$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 ) );
  4091 			$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 ) );
  3094 
  4092 
  3095 		if ( $object_types )
  4093 		if ( $object_types )
  3096 			$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 ) );
  4094 			$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 ) );
  3097 
  4095 
  3098 		do_action( 'edit_term_taxonomy', $term, $taxonomy );
  4096 		/** This action is documented in wp-includes/taxonomy.php */
       
  4097 		do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
  3099 		$wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
  4098 		$wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
  3100 		do_action( 'edited_term_taxonomy', $term, $taxonomy );
  4099 
       
  4100 		/** This action is documented in wp-includes/taxonomy.php */
       
  4101 		do_action( 'edited_term_taxonomy', $term, $taxonomy->name );
  3101 	}
  4102 	}
  3102 }
  4103 }
  3103 
  4104 
  3104 /**
  4105 /**
  3105  * Will update term count based on number of objects.
  4106  * Will update term count based on number of objects.
  3106  *
  4107  *
  3107  * Default callback for the link_category taxonomy.
  4108  * Default callback for the link_category taxonomy.
  3108  *
  4109  *
  3109  * @package WordPress
       
  3110  * @subpackage Taxonomy
       
  3111  * @since 3.3.0
  4110  * @since 3.3.0
  3112  * @uses $wpdb
  4111  *
       
  4112  * @global wpdb $wpdb WordPress database abstraction object.
  3113  *
  4113  *
  3114  * @param array $terms List of Term taxonomy IDs
  4114  * @param array $terms List of Term taxonomy IDs
  3115  * @param object $taxonomy Current taxonomy object of terms
  4115  * @param object $taxonomy Current taxonomy object of terms
  3116  */
  4116  */
  3117 function _update_generic_term_count( $terms, $taxonomy ) {
  4117 function _update_generic_term_count( $terms, $taxonomy ) {
  3118 	global $wpdb;
  4118 	global $wpdb;
  3119 
  4119 
  3120 	foreach ( (array) $terms as $term ) {
  4120 	foreach ( (array) $terms as $term ) {
  3121 		$count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term ) );
  4121 		$count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term ) );
  3122 
  4122 
  3123 		do_action( 'edit_term_taxonomy', $term, $taxonomy );
  4123 		/** This action is documented in wp-includes/taxonomy.php */
       
  4124 		do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
  3124 		$wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
  4125 		$wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
  3125 		do_action( 'edited_term_taxonomy', $term, $taxonomy );
  4126 
  3126 	}
  4127 		/** This action is documented in wp-includes/taxonomy.php */
  3127 }
  4128 		do_action( 'edited_term_taxonomy', $term, $taxonomy->name );
  3128 
  4129 	}
  3129 /**
  4130 }
  3130  * Generates a permalink for a taxonomy term archive.
  4131 
       
  4132 /**
       
  4133  * Create a new term for a term_taxonomy item that currently shares its term with another term_taxonomy.
       
  4134  *
       
  4135  * @ignore
       
  4136  * @since 4.2.0
       
  4137  *
       
  4138  * @param int  $term_id          ID of the shared term.
       
  4139  * @param int  $term_taxonomy_id ID of the term_taxonomy item to receive a new term.
       
  4140  * @return int|WP_Error When the current term does not need to be split (or cannot be split on the current
       
  4141  *                      database schema), `$term_id` is returned. When the term is successfully split, the
       
  4142  *                      new term_id is returned. A WP_Error is returned for miscellaneous errors.
       
  4143  */
       
  4144 function _split_shared_term( $term_id, $term_taxonomy_id ) {
       
  4145 	global $wpdb;
       
  4146 
       
  4147 	// Don't try to split terms if database schema does not support shared slugs.
       
  4148 	$current_db_version = get_option( 'db_version' );
       
  4149 	if ( $current_db_version < 30133 ) {
       
  4150 		return $term_id;
       
  4151 	}
       
  4152 
       
  4153 	// If there are no shared term_taxonomy rows, there's nothing to do here.
       
  4154 	$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 ) );
       
  4155 	if ( ! $shared_tt_count ) {
       
  4156 		return $term_id;
       
  4157 	}
       
  4158 
       
  4159 	// Pull up data about the currently shared slug, which we'll use to populate the new one.
       
  4160 	$shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->terms t WHERE t.term_id = %d", $term_id ) );
       
  4161 
       
  4162 	$new_term_data = array(
       
  4163 		'name' => $shared_term->name,
       
  4164 		'slug' => $shared_term->slug,
       
  4165 		'term_group' => $shared_term->term_group,
       
  4166 	);
       
  4167 
       
  4168 	if ( false === $wpdb->insert( $wpdb->terms, $new_term_data ) ) {
       
  4169 		return new WP_Error( 'db_insert_error', __( 'Could not split shared term.' ), $wpdb->last_error );
       
  4170 	}
       
  4171 
       
  4172 	$new_term_id = (int) $wpdb->insert_id;
       
  4173 
       
  4174 	// Update the existing term_taxonomy to point to the newly created term.
       
  4175 	$wpdb->update( $wpdb->term_taxonomy,
       
  4176 		array( 'term_id' => $new_term_id ),
       
  4177 		array( 'term_taxonomy_id' => $term_taxonomy_id )
       
  4178 	);
       
  4179 
       
  4180 	// Reassign child terms to the new parent.
       
  4181 	$term_taxonomy = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) );
       
  4182 	$children_tt_ids = $wpdb->get_col( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = %s AND parent = %d", $term_taxonomy->taxonomy, $term_id ) );
       
  4183 
       
  4184 	if ( ! empty( $children_tt_ids ) ) {
       
  4185 		foreach ( $children_tt_ids as $child_tt_id ) {
       
  4186 			$wpdb->update( $wpdb->term_taxonomy,
       
  4187 				array( 'parent' => $new_term_id ),
       
  4188 				array( 'term_taxonomy_id' => $child_tt_id )
       
  4189 			);
       
  4190 			clean_term_cache( $term_id, $term_taxonomy->taxonomy );
       
  4191 		}
       
  4192 	} else {
       
  4193 		// If the term has no children, we must force its taxonomy cache to be rebuilt separately.
       
  4194 		clean_term_cache( $new_term_id, $term_taxonomy->taxonomy );
       
  4195 	}
       
  4196 
       
  4197 	// Clean the cache for term taxonomies formerly shared with the current term.
       
  4198 	$shared_term_taxonomies = $wpdb->get_row( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) );
       
  4199 	if ( $shared_term_taxonomies ) {
       
  4200 		foreach ( $shared_term_taxonomies as $shared_term_taxonomy ) {
       
  4201 			clean_term_cache( $term_id, $shared_term_taxonomy );
       
  4202 		}
       
  4203 	}
       
  4204 
       
  4205 	// Keep a record of term_ids that have been split, keyed by old term_id. See {@see wp_get_split_term()}.
       
  4206 	$split_term_data = get_option( '_split_terms', array() );
       
  4207 	if ( ! isset( $split_term_data[ $term_id ] ) ) {
       
  4208 		$split_term_data[ $term_id ] = array();
       
  4209 	}
       
  4210 
       
  4211 	$split_term_data[ $term_id ][ $term_taxonomy->taxonomy ] = $new_term_id;
       
  4212 
       
  4213 	update_option( '_split_terms', $split_term_data );
       
  4214 
       
  4215 	/**
       
  4216 	 * Fires after a previously shared taxonomy term is split into two separate terms.
       
  4217 	 *
       
  4218 	 * @since 4.2.0
       
  4219 	 *
       
  4220 	 * @param int    $term_id          ID of the formerly shared term.
       
  4221 	 * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
       
  4222 	 * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
       
  4223 	 * @param string $taxonomy         Taxonomy for the split term.
       
  4224 	 */
       
  4225 	do_action( 'split_shared_term', $term_id, $new_term_id, $term_taxonomy_id, $term_taxonomy->taxonomy );
       
  4226 
       
  4227 	return $new_term_id;
       
  4228 }
       
  4229 
       
  4230 /**
       
  4231  * Check default categories when a term gets split to see if any of them need to be updated.
       
  4232  *
       
  4233  * @ignore
       
  4234  * @since 4.2.0
       
  4235  *
       
  4236  * @param int    $term_id          ID of the formerly shared term.
       
  4237  * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
       
  4238  * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
       
  4239  * @param string $taxonomy         Taxonomy for the split term.
       
  4240  */
       
  4241 function _wp_check_split_default_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
       
  4242 	if ( 'category' != $taxonomy ) {
       
  4243 		return;
       
  4244 	}
       
  4245 
       
  4246 	foreach ( array( 'default_category', 'default_link_category', 'default_email_category' ) as $option ) {
       
  4247 		if ( $term_id == get_option( $option, -1 ) ) {
       
  4248 			update_option( $option, $new_term_id );
       
  4249 		}
       
  4250 	}
       
  4251 }
       
  4252 
       
  4253 /**
       
  4254  * Check menu items when a term gets split to see if any of them need to be updated.
       
  4255  *
       
  4256  * @ignore
       
  4257  * @since 4.2.0
       
  4258  *
       
  4259  * @param int    $term_id          ID of the formerly shared term.
       
  4260  * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
       
  4261  * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
       
  4262  * @param string $taxonomy         Taxonomy for the split term.
       
  4263  */
       
  4264 function _wp_check_split_terms_in_menus( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
       
  4265 	global $wpdb;
       
  4266 	$post_ids = $wpdb->get_col( $wpdb->prepare(
       
  4267 		"SELECT m1.post_id
       
  4268 		FROM {$wpdb->postmeta} AS m1
       
  4269 			INNER JOIN {$wpdb->postmeta} AS m2 ON ( m2.post_id = m1.post_id )
       
  4270 			INNER JOIN {$wpdb->postmeta} AS m3 ON ( m3.post_id = m1.post_id )
       
  4271 		WHERE ( m1.meta_key = '_menu_item_type' AND m1.meta_value = 'taxonomy' )
       
  4272 			AND ( m2.meta_key = '_menu_item_object' AND m2.meta_value = '%s' )
       
  4273 			AND ( m3.meta_key = '_menu_item_object_id' AND m3.meta_value = %d )",
       
  4274 		$taxonomy,
       
  4275 		$term_id
       
  4276 	) );
       
  4277 
       
  4278 	if ( $post_ids ) {
       
  4279 		foreach ( $post_ids as $post_id ) {
       
  4280 			update_post_meta( $post_id, '_menu_item_object_id', $new_term_id, $term_id );
       
  4281 		}
       
  4282 	}
       
  4283 }
       
  4284 
       
  4285 /**
       
  4286  * Get data about terms that previously shared a single term_id, but have since been split.
       
  4287  *
       
  4288  * @since 4.2.0
       
  4289  *
       
  4290  * @param int $old_term_id Term ID. This is the old, pre-split term ID.
       
  4291  * @return array Array of new term IDs, keyed by taxonomy.
       
  4292  */
       
  4293 function wp_get_split_terms( $old_term_id ) {
       
  4294 	$split_terms = get_option( '_split_terms', array() );
       
  4295 
       
  4296 	$terms = array();
       
  4297 	if ( isset( $split_terms[ $old_term_id ] ) ) {
       
  4298 		$terms = $split_terms[ $old_term_id ];
       
  4299 	}
       
  4300 
       
  4301 	return $terms;
       
  4302 }
       
  4303 
       
  4304 /**
       
  4305  * Get the new term ID corresponding to a previously split term.
       
  4306  *
       
  4307  * @since 4.2.0
       
  4308  *
       
  4309  * @param int    $old_term_id Term ID. This is the old, pre-split term ID.
       
  4310  * @param string $taxonomy    Taxonomy that the term belongs to.
       
  4311  * @return bool|int If a previously split term is found corresponding to the old term_id and taxonomy,
       
  4312  *                  the new term_id will be returned. If no previously split term is found matching
       
  4313  *                  the parameters, returns false.
       
  4314  */
       
  4315 function wp_get_split_term( $old_term_id, $taxonomy ) {
       
  4316 	$split_terms = wp_get_split_terms( $old_term_id );
       
  4317 
       
  4318 	$term_id = false;
       
  4319 	if ( isset( $split_terms[ $taxonomy ] ) ) {
       
  4320 		$term_id = (int) $split_terms[ $taxonomy ];
       
  4321 	}
       
  4322 
       
  4323 	return $term_id;
       
  4324 }
       
  4325 
       
  4326 /**
       
  4327  * Generate a permalink for a taxonomy term archive.
  3131  *
  4328  *
  3132  * @since 2.5.0
  4329  * @since 2.5.0
  3133  *
  4330  *
  3134  * @uses apply_filters() Calls 'term_link' with term link and term object, and taxonomy parameters.
  4331  * @param object|int|string $term     The term object, ID, or slug whose link will be retrieved.
  3135  * @uses apply_filters() For the post_tag Taxonomy, Calls 'tag_link' with tag link and tag ID as parameters.
  4332  * @param string            $taxonomy Optional. Taxonomy. Default empty.
  3136  * @uses apply_filters() For the category Taxonomy, Calls 'category_link' filter on category link and category ID.
       
  3137  *
       
  3138  * @param object|int|string $term
       
  3139  * @param string $taxonomy (optional if $term is object)
       
  3140  * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
  4333  * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
  3141  */
  4334  */
  3142 function get_term_link( $term, $taxonomy = '') {
  4335 function get_term_link( $term, $taxonomy = '') {
  3143 	global $wp_rewrite;
  4336 	global $wp_rewrite;
  3144 
  4337 
  3172 			$termlink = "?taxonomy=$taxonomy&term=$slug";
  4365 			$termlink = "?taxonomy=$taxonomy&term=$slug";
  3173 		$termlink = home_url($termlink);
  4366 		$termlink = home_url($termlink);
  3174 	} else {
  4367 	} else {
  3175 		if ( $t->rewrite['hierarchical'] ) {
  4368 		if ( $t->rewrite['hierarchical'] ) {
  3176 			$hierarchical_slugs = array();
  4369 			$hierarchical_slugs = array();
  3177 			$ancestors = get_ancestors($term->term_id, $taxonomy);
  4370 			$ancestors = get_ancestors( $term->term_id, $taxonomy, 'taxonomy' );
  3178 			foreach ( (array)$ancestors as $ancestor ) {
  4371 			foreach ( (array)$ancestors as $ancestor ) {
  3179 				$ancestor_term = get_term($ancestor, $taxonomy);
  4372 				$ancestor_term = get_term($ancestor, $taxonomy);
  3180 				$hierarchical_slugs[] = $ancestor_term->slug;
  4373 				$hierarchical_slugs[] = $ancestor_term->slug;
  3181 			}
  4374 			}
  3182 			$hierarchical_slugs = array_reverse($hierarchical_slugs);
  4375 			$hierarchical_slugs = array_reverse($hierarchical_slugs);
  3186 			$termlink = str_replace("%$taxonomy%", $slug, $termlink);
  4379 			$termlink = str_replace("%$taxonomy%", $slug, $termlink);
  3187 		}
  4380 		}
  3188 		$termlink = home_url( user_trailingslashit($termlink, 'category') );
  4381 		$termlink = home_url( user_trailingslashit($termlink, 'category') );
  3189 	}
  4382 	}
  3190 	// Back Compat filters.
  4383 	// Back Compat filters.
  3191 	if ( 'post_tag' == $taxonomy )
  4384 	if ( 'post_tag' == $taxonomy ) {
       
  4385 
       
  4386 		/**
       
  4387 		 * Filter the tag link.
       
  4388 		 *
       
  4389 		 * @since 2.3.0
       
  4390 		 * @deprecated 2.5.0 Use 'term_link' instead.
       
  4391 		 *
       
  4392 		 * @param string $termlink Tag link URL.
       
  4393 		 * @param int    $term_id  Term ID.
       
  4394 		 */
  3192 		$termlink = apply_filters( 'tag_link', $termlink, $term->term_id );
  4395 		$termlink = apply_filters( 'tag_link', $termlink, $term->term_id );
  3193 	elseif ( 'category' == $taxonomy )
  4396 	} elseif ( 'category' == $taxonomy ) {
       
  4397 
       
  4398 		/**
       
  4399 		 * Filter the category link.
       
  4400 		 *
       
  4401 		 * @since 1.5.0
       
  4402 		 * @deprecated 2.5.0 Use 'term_link' instead.
       
  4403 		 *
       
  4404 		 * @param string $termlink Category link URL.
       
  4405 		 * @param int    $term_id  Term ID.
       
  4406 		 */
  3194 		$termlink = apply_filters( 'category_link', $termlink, $term->term_id );
  4407 		$termlink = apply_filters( 'category_link', $termlink, $term->term_id );
  3195 
  4408 	}
  3196 	return apply_filters('term_link', $termlink, $term, $taxonomy);
  4409 
       
  4410 	/**
       
  4411 	 * Filter the term link.
       
  4412 	 *
       
  4413 	 * @since 2.5.0
       
  4414 	 *
       
  4415 	 * @param string $termlink Term link URL.
       
  4416 	 * @param object $term     Term object.
       
  4417 	 * @param string $taxonomy Taxonomy slug.
       
  4418 	 */
       
  4419 	return apply_filters( 'term_link', $termlink, $term, $taxonomy );
  3197 }
  4420 }
  3198 
  4421 
  3199 /**
  4422 /**
  3200  * Display the taxonomies of a post with available options.
  4423  * Display the taxonomies of a post with available options.
  3201  *
  4424  *
  3202  * This function can be used within the loop to display the taxonomies for a
  4425  * This function can be used within the loop to display the taxonomies for a
  3203  * post without specifying the Post ID. You can also use it outside the Loop to
  4426  * post without specifying the Post ID. You can also use it outside the Loop to
  3204  * display the taxonomies for a specific post.
  4427  * display the taxonomies for a specific post.
  3205  *
  4428  *
  3206  * The available defaults are:
       
  3207  * 'post' : default is 0. The post ID to get taxonomies of.
       
  3208  * 'before' : default is empty string. Display before taxonomies list.
       
  3209  * 'sep' : default is empty string. Separate every taxonomy with value in this.
       
  3210  * 'after' : default is empty string. Display this after the taxonomies list.
       
  3211  * 'template' : The template to use for displaying the taxonomy terms.
       
  3212  *
       
  3213  * @since 2.5.0
  4429  * @since 2.5.0
  3214  * @uses get_the_taxonomies()
  4430  *
  3215  *
  4431  * @param array $args {
  3216  * @param array $args Override the defaults.
  4432  *     Arguments about which post to use and how to format the output. Shares all of the arguments supported by
  3217  */
  4433  *     {@link get_the_taxonomies()}, in addition to the following.
  3218 function the_taxonomies($args = array()) {
  4434  *
       
  4435  *     @type  int|WP_Post $post   Post ID or object to get taxonomies of. Default current post.
       
  4436  *     @type  string      $before Displays before the taxonomies. Default empty string.
       
  4437  *     @type  string      $sep    Separates each taxonomy. Default is a space.
       
  4438  *     @type  string      $after  Displays after the taxonomies. Default empty string.
       
  4439  * }
       
  4440  * @param array $args See {@link get_the_taxonomies()} for a description of arguments and their defaults.
       
  4441  */
       
  4442 function the_taxonomies( $args = array() ) {
  3219 	$defaults = array(
  4443 	$defaults = array(
  3220 		'post' => 0,
  4444 		'post' => 0,
  3221 		'before' => '',
  4445 		'before' => '',
  3222 		'sep' => ' ',
  4446 		'sep' => ' ',
  3223 		'after' => '',
  4447 		'after' => '',
  3224 		'template' => '%s: %l.'
       
  3225 	);
  4448 	);
  3226 
  4449 
  3227 	$r = wp_parse_args( $args, $defaults );
  4450 	$r = wp_parse_args( $args, $defaults );
  3228 	extract( $r, EXTR_SKIP );
  4451 
  3229 
  4452 	echo $r['before'] . join( $r['sep'], get_the_taxonomies( $r['post'], $r ) ) . $r['after'];
  3230 	echo $before . join($sep, get_the_taxonomies($post, $r)) . $after;
       
  3231 }
  4453 }
  3232 
  4454 
  3233 /**
  4455 /**
  3234  * Retrieve all taxonomies associated with a post.
  4456  * Retrieve all taxonomies associated with a post.
  3235  *
  4457  *
  3236  * This function can be used within the loop. It will also return an array of
  4458  * This function can be used within the loop. It will also return an array of
  3237  * the taxonomies with links to the taxonomy and name.
  4459  * the taxonomies with links to the taxonomy and name.
  3238  *
  4460  *
  3239  * @since 2.5.0
  4461  * @since 2.5.0
  3240  *
  4462  *
  3241  * @param int $post Optional. Post ID or will use Global Post ID (in loop).
  4463  * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
  3242  * @param array $args Override the defaults.
  4464  * @param array $args {
       
  4465  *     Arguments about how to format the list of taxonomies.
       
  4466  *
       
  4467  *     @type string $template      Template for displaying a taxonomy label and list of terms.
       
  4468  *                                 Default is "Label: Terms."
       
  4469  *     @type string $term_template Template for displaying a single term in the list. Default is the term name
       
  4470  *                                 linked to its archive.
       
  4471  * }
       
  4472  * @return array List of taxonomies.
       
  4473  */
       
  4474 function get_the_taxonomies( $post = 0, $args = array() ) {
       
  4475 	$post = get_post( $post );
       
  4476 
       
  4477 	$args = wp_parse_args( $args, array(
       
  4478 		/* translators: %s: taxonomy label, %l: list of terms formatted as per $term_template */
       
  4479 		'template' => __( '%s: %l.' ),
       
  4480 		'term_template' => '<a href="%1$s">%2$s</a>',
       
  4481 	) );
       
  4482 
       
  4483 	$taxonomies = array();
       
  4484 
       
  4485 	if ( ! $post ) {
       
  4486 		return $taxonomies;
       
  4487 	}
       
  4488 
       
  4489 	foreach ( get_object_taxonomies( $post ) as $taxonomy ) {
       
  4490 		$t = (array) get_taxonomy( $taxonomy );
       
  4491 		if ( empty( $t['label'] ) ) {
       
  4492 			$t['label'] = $taxonomy;
       
  4493 		}
       
  4494 		if ( empty( $t['args'] ) ) {
       
  4495 			$t['args'] = array();
       
  4496 		}
       
  4497 		if ( empty( $t['template'] ) ) {
       
  4498 			$t['template'] = $args['template'];
       
  4499 		}
       
  4500 		if ( empty( $t['term_template'] ) ) {
       
  4501 			$t['term_template'] = $args['term_template'];
       
  4502 		}
       
  4503 
       
  4504 		$terms = get_object_term_cache( $post->ID, $taxonomy );
       
  4505 		if ( false === $terms ) {
       
  4506 			$terms = wp_get_object_terms( $post->ID, $taxonomy, $t['args'] );
       
  4507 		}
       
  4508 		$links = array();
       
  4509 
       
  4510 		foreach ( $terms as $term ) {
       
  4511 			$links[] = wp_sprintf( $t['term_template'], esc_attr( get_term_link( $term ) ), $term->name );
       
  4512 		}
       
  4513 		if ( $links ) {
       
  4514 			$taxonomies[$taxonomy] = wp_sprintf( $t['template'], $t['label'], $links, $terms );
       
  4515 		}
       
  4516 	}
       
  4517 	return $taxonomies;
       
  4518 }
       
  4519 
       
  4520 /**
       
  4521  * Retrieve all taxonomies of a post with just the names.
       
  4522  *
       
  4523  * @since 2.5.0
       
  4524  *
       
  4525  * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
  3243  * @return array
  4526  * @return array
  3244  */
  4527  */
  3245 function get_the_taxonomies($post = 0, $args = array() ) {
  4528 function get_post_taxonomies( $post = 0 ) {
  3246 	$post = get_post( $post );
       
  3247 
       
  3248 	$args = wp_parse_args( $args, array(
       
  3249 		'template' => '%s: %l.',
       
  3250 	) );
       
  3251 	extract( $args, EXTR_SKIP );
       
  3252 
       
  3253 	$taxonomies = array();
       
  3254 
       
  3255 	if ( !$post )
       
  3256 		return $taxonomies;
       
  3257 
       
  3258 	foreach ( get_object_taxonomies($post) as $taxonomy ) {
       
  3259 		$t = (array) get_taxonomy($taxonomy);
       
  3260 		if ( empty($t['label']) )
       
  3261 			$t['label'] = $taxonomy;
       
  3262 		if ( empty($t['args']) )
       
  3263 			$t['args'] = array();
       
  3264 		if ( empty($t['template']) )
       
  3265 			$t['template'] = $template;
       
  3266 
       
  3267 		$terms = get_object_term_cache($post->ID, $taxonomy);
       
  3268 		if ( false === $terms )
       
  3269 			$terms = wp_get_object_terms($post->ID, $taxonomy, $t['args']);
       
  3270 
       
  3271 		$links = array();
       
  3272 
       
  3273 		foreach ( $terms as $term )
       
  3274 			$links[] = "<a href='" . esc_attr( get_term_link($term) ) . "'>$term->name</a>";
       
  3275 
       
  3276 		if ( $links )
       
  3277 			$taxonomies[$taxonomy] = wp_sprintf($t['template'], $t['label'], $links, $terms);
       
  3278 	}
       
  3279 	return $taxonomies;
       
  3280 }
       
  3281 
       
  3282 /**
       
  3283  * Retrieve all taxonomies of a post with just the names.
       
  3284  *
       
  3285  * @since 2.5.0
       
  3286  * @uses get_object_taxonomies()
       
  3287  *
       
  3288  * @param int $post Optional. Post ID
       
  3289  * @return array
       
  3290  */
       
  3291 function get_post_taxonomies($post = 0) {
       
  3292 	$post = get_post( $post );
  4529 	$post = get_post( $post );
  3293 
  4530 
  3294 	return get_object_taxonomies($post);
  4531 	return get_object_taxonomies($post);
  3295 }
  4532 }
  3296 
  4533 
  3300  * The given terms are checked against the object's terms' term_ids, names and slugs.
  4537  * The given terms are checked against the object's terms' term_ids, names and slugs.
  3301  * Terms given as integers will only be checked against the object's terms' term_ids.
  4538  * Terms given as integers will only be checked against the object's terms' term_ids.
  3302  * If no terms are given, determines if object is associated with any terms in the given taxonomy.
  4539  * If no terms are given, determines if object is associated with any terms in the given taxonomy.
  3303  *
  4540  *
  3304  * @since 2.7.0
  4541  * @since 2.7.0
  3305  * @uses get_object_term_cache()
       
  3306  * @uses wp_get_object_terms()
       
  3307  *
  4542  *
  3308  * @param int $object_id ID of the object (post ID, link ID, ...)
  4543  * @param int $object_id ID of the object (post ID, link ID, ...)
  3309  * @param string $taxonomy Single taxonomy name
  4544  * @param string $taxonomy Single taxonomy name
  3310  * @param int|string|array $terms Optional. Term term_id, name, slug or array of said
  4545  * @param int|string|array $terms Optional. Term term_id, name, slug or array of said
  3311  * @return bool|WP_Error. WP_Error on input error.
  4546  * @return bool|WP_Error WP_Error on input error.
  3312  */
  4547  */
  3313 function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
  4548 function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
  3314 	if ( !$object_id = (int) $object_id )
  4549 	if ( !$object_id = (int) $object_id )
  3315 		return new WP_Error( 'invalid_object', __( 'Invalid object ID' ) );
  4550 		return new WP_Error( 'invalid_object', __( 'Invalid object ID' ) );
  3316 
  4551 
  3331 		$strs = array_diff( $terms, $ints );
  4566 		$strs = array_diff( $terms, $ints );
  3332 	else
  4567 	else
  3333 		$strs =& $terms;
  4568 		$strs =& $terms;
  3334 
  4569 
  3335 	foreach ( $object_terms as $object_term ) {
  4570 	foreach ( $object_terms as $object_term ) {
  3336 		if ( $ints && in_array( $object_term->term_id, $ints ) ) return true; // If int, check against term_id
  4571 		// If term is an int, check against term_ids only.
       
  4572 		if ( $ints && in_array( $object_term->term_id, $ints ) ) {
       
  4573 			return true;
       
  4574 		}
       
  4575 
  3337 		if ( $strs ) {
  4576 		if ( $strs ) {
  3338 			if ( in_array( $object_term->term_id, $strs ) ) return true;
  4577 			// Only check numeric strings against term_id, to avoid false matches due to type juggling.
  3339 			if ( in_array( $object_term->name, $strs ) )    return true;
  4578 			$numeric_strs = array_map( 'intval', array_filter( $strs, 'is_numeric' ) );
  3340 			if ( in_array( $object_term->slug, $strs ) )    return true;
  4579 			if ( in_array( $object_term->term_id, $numeric_strs, true ) ) {
       
  4580 				return true;
       
  4581 			}
       
  4582 
       
  4583 			if ( in_array( $object_term->name, $strs ) ) return true;
       
  4584 			if ( in_array( $object_term->slug, $strs ) ) return true;
  3341 		}
  4585 		}
  3342 	}
  4586 	}
  3343 
  4587 
  3344 	return false;
  4588 	return false;
  3345 }
  4589 }
  3346 
  4590 
  3347 /**
  4591 /**
  3348  * Determine if the given object type is associated with the given taxonomy.
  4592  * Determine if the given object type is associated with the given taxonomy.
  3349  *
  4593  *
  3350  * @since 3.0.0
  4594  * @since 3.0.0
  3351  * @uses get_object_taxonomies()
       
  3352  *
  4595  *
  3353  * @param string $object_type Object type string
  4596  * @param string $object_type Object type string
  3354  * @param string $taxonomy Single taxonomy name
  4597  * @param string $taxonomy Single taxonomy name
  3355  * @return bool True if object is associated with the taxonomy, otherwise false.
  4598  * @return bool True if object is associated with the taxonomy, otherwise false.
  3356  */
  4599  */
  3367 }
  4610 }
  3368 
  4611 
  3369 /**
  4612 /**
  3370  * Get an array of ancestor IDs for a given object.
  4613  * Get an array of ancestor IDs for a given object.
  3371  *
  4614  *
  3372  * @param int $object_id The ID of the object
  4615  * @since 3.1.0
  3373  * @param string $object_type The type of object for which we'll be retrieving ancestors.
  4616  * @since 4.1.0 Introduced the `$resource_type` argument.
  3374  * @return array of ancestors from lowest to highest in the hierarchy.
  4617  *
  3375  */
  4618  * @param int    $object_id     Optional. The ID of the object. Default 0.
  3376 function get_ancestors($object_id = 0, $object_type = '') {
  4619  * @param string $object_type   Optional. The type of object for which we'll be retrieving
       
  4620  *                              ancestors. Accepts a post type or a taxonomy name. Default empty.
       
  4621  * @param string $resource_type Optional. Type of resource $object_type is. Accepts 'post_type'
       
  4622  *                              or 'taxonomy'. Default empty.
       
  4623  * @return array An array of ancestors from lowest to highest in the hierarchy.
       
  4624  */
       
  4625 function get_ancestors( $object_id = 0, $object_type = '', $resource_type = '' ) {
  3377 	$object_id = (int) $object_id;
  4626 	$object_id = (int) $object_id;
  3378 
  4627 
  3379 	$ancestors = array();
  4628 	$ancestors = array();
  3380 
  4629 
  3381 	if ( empty( $object_id ) ) {
  4630 	if ( empty( $object_id ) ) {
  3382 		return apply_filters('get_ancestors', $ancestors, $object_id, $object_type);
  4631 
  3383 	}
  4632 		/** This filter is documented in wp-includes/taxonomy.php */
  3384 
  4633 		return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type );
  3385 	if ( is_taxonomy_hierarchical( $object_type ) ) {
  4634 	}
       
  4635 
       
  4636 	if ( ! $resource_type ) {
       
  4637 		if ( is_taxonomy_hierarchical( $object_type ) ) {
       
  4638 			$resource_type = 'taxonomy';
       
  4639 		} elseif ( post_type_exists( $object_type ) ) {
       
  4640 			$resource_type = 'post_type';
       
  4641 		}
       
  4642 	}
       
  4643 
       
  4644 	if ( 'taxonomy' === $resource_type ) {
  3386 		$term = get_term($object_id, $object_type);
  4645 		$term = get_term($object_id, $object_type);
  3387 		while ( ! is_wp_error($term) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors ) ) {
  4646 		while ( ! is_wp_error($term) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors ) ) {
  3388 			$ancestors[] = (int) $term->parent;
  4647 			$ancestors[] = (int) $term->parent;
  3389 			$term = get_term($term->parent, $object_type);
  4648 			$term = get_term($term->parent, $object_type);
  3390 		}
  4649 		}
  3391 	} elseif ( post_type_exists( $object_type ) ) {
  4650 	} elseif ( 'post_type' === $resource_type ) {
  3392 		$ancestors = get_post_ancestors($object_id);
  4651 		$ancestors = get_post_ancestors($object_id);
  3393 	}
  4652 	}
  3394 
  4653 
  3395 	return apply_filters('get_ancestors', $ancestors, $object_id, $object_type);
  4654 	/**
       
  4655 	 * Filter a given object's ancestors.
       
  4656 	 *
       
  4657 	 * @since 3.1.0
       
  4658 	 * @since 4.1.0 Introduced the `$resource_type` parameter.
       
  4659 	 *
       
  4660 	 * @param array  $ancestors     An array of object ancestors.
       
  4661 	 * @param int    $object_id     Object ID.
       
  4662 	 * @param string $object_type   Type of object.
       
  4663 	 * @param string $resource_type Type of resource $object_type is.
       
  4664 	 */
       
  4665 	return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type );
  3396 }
  4666 }
  3397 
  4667 
  3398 /**
  4668 /**
  3399  * Returns the term's parent's term_ID
  4669  * Returns the term's parent's term_ID
  3400  *
  4670  *
  3417  * Prevents loops from forming and breaks those that it finds.
  4687  * Prevents loops from forming and breaks those that it finds.
  3418  *
  4688  *
  3419  * Attached to the wp_update_term_parent filter.
  4689  * Attached to the wp_update_term_parent filter.
  3420  *
  4690  *
  3421  * @since 3.1.0
  4691  * @since 3.1.0
  3422  * @uses wp_find_hierarchy_loop()
       
  3423  *
  4692  *
  3424  * @param int $parent term_id of the parent for the term we're checking.
  4693  * @param int $parent term_id of the parent for the term we're checking.
  3425  * @param int $term_id The term we're checking.
  4694  * @param int $term_id The term we're checking.
  3426  * @param string $taxonomy The taxonomy of the term we're checking.
  4695  * @param string $taxonomy The taxonomy of the term we're checking.
  3427  *
  4696  *