PageRenderTime 389ms CodeModel.GetById 140ms app.highlight 143ms RepoModel.GetById 59ms app.codeStats 1ms

/wp-includes/taxonomy.php

https://bitbucket.org/Wallynm/iptb
PHP | 3248 lines | 1623 code | 436 blank | 1189 comment | 477 complexity | 586835777b55c8de6197be1696170f40 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * Taxonomy API
   4 *
   5 * @package WordPress
   6 * @subpackage Taxonomy
   7 * @since 2.3.0
   8 */
   9
  10//
  11// Taxonomy Registration
  12//
  13
  14/**
  15 * Creates the initial taxonomies when 'init' action is fired.
  16 */
  17function create_initial_taxonomies() {
  18	global $wp_rewrite;
  19
  20	register_taxonomy( 'category', 'post', array(
  21		'hierarchical' => true,
  22		'query_var' => 'category_name',
  23		'rewrite' => did_action( 'init' ) ? array(
  24					'hierarchical' => true,
  25					'slug' => get_option('category_base') ? get_option('category_base') : 'category',
  26					'with_front' => ( get_option('category_base') && ! $wp_rewrite->using_index_permalinks() ) ? false : true ) : false,
  27		'public' => true,
  28		'show_ui' => true,
  29		'_builtin' => true,
  30	) );
  31
  32	register_taxonomy( 'post_tag', 'post', array(
  33	 	'hierarchical' => false,
  34		'query_var' => 'tag',
  35		'rewrite' => did_action( 'init' ) ? array(
  36					'slug' => get_option('tag_base') ? get_option('tag_base') : 'tag',
  37					'with_front' => ( get_option('tag_base') && ! $wp_rewrite->using_index_permalinks() ) ? false : true ) : false,
  38		'public' => true,
  39		'show_ui' => true,
  40		'_builtin' => true,
  41	) );
  42
  43	register_taxonomy( 'nav_menu', 'nav_menu_item', array(
  44		'public' => false,
  45		'hierarchical' => false,
  46		'labels' => array(
  47			'name' => __( 'Navigation Menus' ),
  48			'singular_name' => __( 'Navigation Menu' ),
  49		),
  50		'query_var' => false,
  51		'rewrite' => false,
  52		'show_ui' => false,
  53		'_builtin' => true,
  54		'show_in_nav_menus' => false,
  55	) );
  56
  57	register_taxonomy( 'link_category', 'link', array(
  58		'hierarchical' => false,
  59		'labels' => array(
  60			'name' => __( 'Link Categories' ),
  61			'singular_name' => __( 'Link Category' ),
  62			'search_items' => __( 'Search Link Categories' ),
  63			'popular_items' => null,
  64			'all_items' => __( 'All Link Categories' ),
  65			'edit_item' => __( 'Edit Link Category' ),
  66			'update_item' => __( 'Update Link Category' ),
  67			'add_new_item' => __( 'Add New Link Category' ),
  68			'new_item_name' => __( 'New Link Category Name' ),
  69			'separate_items_with_commas' => null,
  70			'add_or_remove_items' => null,
  71			'choose_from_most_used' => null,
  72		),
  73		'query_var' => false,
  74		'rewrite' => false,
  75		'public' => false,
  76		'show_ui' => false,
  77		'_builtin' => true,
  78	) );
  79
  80	$rewrite = false;
  81	if ( did_action( 'init' ) ) {
  82		$rewrite = apply_filters( 'post_format_rewrite_base', 'type' );
  83		$rewrite = $rewrite ? array( 'slug' => $rewrite ) : false;
  84	}
  85
  86	register_taxonomy( 'post_format', 'post', array(
  87		'public' => true,
  88		'hierarchical' => false,
  89		'labels' => array(
  90			'name' => _x( 'Format', 'post format' ),
  91			'singular_name' => _x( 'Format', 'post format' ),
  92		),
  93		'query_var' => true,
  94		'rewrite' => $rewrite,
  95		'show_ui' => false,
  96		'_builtin' => true,
  97		'show_in_nav_menus' => false,
  98	) );
  99}
 100add_action( 'init', 'create_initial_taxonomies', 0 ); // highest priority
 101
 102/**
 103 * Get a list of registered taxonomy objects.
 104 *
 105 * @package WordPress
 106 * @subpackage Taxonomy
 107 * @since 3.0.0
 108 * @uses $wp_taxonomies
 109 * @see register_taxonomy
 110 *
 111 * @param array $args An array of key => value arguments to match against the taxonomy objects.
 112 * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
 113 * @param string $operator The logical operation to perform. 'or' means only one element
 114 *  from the array needs to match; 'and' means all elements must match. The default is 'and'.
 115 * @return array A list of taxonomy names or objects
 116 */
 117function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
 118	global $wp_taxonomies;
 119
 120	$field = ('names' == $output) ? 'name' : false;
 121
 122	return wp_filter_object_list($wp_taxonomies, $args, $operator, $field);
 123}
 124
 125
 126/**
 127 * Return all of the taxonomy names that are of $object_type.
 128 *
 129 * It appears that this function can be used to find all of the names inside of
 130 * $wp_taxonomies global variable.
 131 *
 132 * <code><?php $taxonomies = get_object_taxonomies('post'); ?></code> Should
 133 * result in <code>Array('category', 'post_tag')</code>
 134 *
 135 * @package WordPress
 136 * @subpackage Taxonomy
 137 * @since 2.3.0
 138 *
 139 * @uses $wp_taxonomies
 140 *
 141 * @param array|string|object $object Name of the type of taxonomy object, or an object (row from posts)
 142 * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
 143 * @return array The names of all taxonomy of $object_type.
 144 */
 145function get_object_taxonomies($object, $output = 'names') {
 146	global $wp_taxonomies;
 147
 148	if ( is_object($object) ) {
 149		if ( $object->post_type == 'attachment' )
 150			return get_attachment_taxonomies($object);
 151		$object = $object->post_type;
 152	}
 153
 154	$object = (array) $object;
 155
 156	$taxonomies = array();
 157	foreach ( (array) $wp_taxonomies as $tax_name => $tax_obj ) {
 158		if ( array_intersect($object, (array) $tax_obj->object_type) ) {
 159			if ( 'names' == $output )
 160				$taxonomies[] = $tax_name;
 161			else
 162				$taxonomies[ $tax_name ] = $tax_obj;
 163		}
 164	}
 165
 166	return $taxonomies;
 167}
 168
 169/**
 170 * Retrieves the taxonomy object of $taxonomy.
 171 *
 172 * The get_taxonomy function will first check that the parameter string given
 173 * is a taxonomy object and if it is, it will return it.
 174 *
 175 * @package WordPress
 176 * @subpackage Taxonomy
 177 * @since 2.3.0
 178 *
 179 * @uses $wp_taxonomies
 180 * @uses taxonomy_exists() Checks whether taxonomy exists
 181 *
 182 * @param string $taxonomy Name of taxonomy object to return
 183 * @return object|bool The Taxonomy Object or false if $taxonomy doesn't exist
 184 */
 185function get_taxonomy( $taxonomy ) {
 186	global $wp_taxonomies;
 187
 188	if ( ! taxonomy_exists( $taxonomy ) )
 189		return false;
 190
 191	return $wp_taxonomies[$taxonomy];
 192}
 193
 194/**
 195 * Checks that the taxonomy name exists.
 196 *
 197 * Formerly is_taxonomy(), introduced in 2.3.0.
 198 *
 199 * @package WordPress
 200 * @subpackage Taxonomy
 201 * @since 3.0.0
 202 *
 203 * @uses $wp_taxonomies
 204 *
 205 * @param string $taxonomy Name of taxonomy object
 206 * @return bool Whether the taxonomy exists.
 207 */
 208function taxonomy_exists( $taxonomy ) {
 209	global $wp_taxonomies;
 210
 211	return isset( $wp_taxonomies[$taxonomy] );
 212}
 213
 214/**
 215 * Whether the taxonomy object is hierarchical.
 216 *
 217 * Checks to make sure that the taxonomy is an object first. Then Gets the
 218 * object, and finally returns the hierarchical value in the object.
 219 *
 220 * A false return value might also mean that the taxonomy does not exist.
 221 *
 222 * @package WordPress
 223 * @subpackage Taxonomy
 224 * @since 2.3.0
 225 *
 226 * @uses taxonomy_exists() Checks whether taxonomy exists
 227 * @uses get_taxonomy() Used to get the taxonomy object
 228 *
 229 * @param string $taxonomy Name of taxonomy object
 230 * @return bool Whether the taxonomy is hierarchical
 231 */
 232function is_taxonomy_hierarchical($taxonomy) {
 233	if ( ! taxonomy_exists($taxonomy) )
 234		return false;
 235
 236	$taxonomy = get_taxonomy($taxonomy);
 237	return $taxonomy->hierarchical;
 238}
 239
 240/**
 241 * Create or modify a taxonomy object. Do not use before init.
 242 *
 243 * A simple function for creating or modifying a taxonomy object based on the
 244 * parameters given. The function will accept an array (third optional
 245 * parameter), along with strings for the taxonomy name and another string for
 246 * the object type.
 247 *
 248 * Nothing is returned, so expect error maybe or use taxonomy_exists() to check
 249 * whether taxonomy exists.
 250 *
 251 * Optional $args contents:
 252 *
 253 * label - Name of the taxonomy shown in the menu. Usually plural. If not set, labels['name'] will be used.
 254 *
 255 * hierarchical - has some defined purpose at other parts of the API and is a
 256 * boolean value.
 257 *
 258 * update_count_callback - works much like a hook, in that it will be called when the count is updated.
 259 * 	Defaults to _update_post_term_count() for taxonomies attached to post types, which then confirms
 260 * 	that the objects are published before counting them.
 261 * 	Defaults to _update_generic_term_count() for taxonomies attached to other object types, such as links.
 262 *
 263 * rewrite - false to prevent rewrite, or array('slug'=>$slug) to customize
 264 * permastruct; default will use $taxonomy as slug.
 265 *
 266 * query_var - false to prevent queries, or string to customize query var
 267 * (?$query_var=$term); default will use $taxonomy as query var.
 268 *
 269 * public - If the taxonomy should be publicly queryable; //@TODO not implemented.
 270 * defaults to true.
 271 *
 272 * show_ui - If the WordPress UI admin tags UI should apply to this taxonomy;
 273 * defaults to public.
 274 *
 275 * show_in_nav_menus - true makes this taxonomy available for selection in navigation menus.
 276 * Defaults to public.
 277 *
 278 * show_tagcloud - false to prevent the taxonomy being listed in the Tag Cloud Widget;
 279 * defaults to show_ui which defaults to public.
 280 *
 281 * labels - An array of labels for this taxonomy. You can see accepted values in {@link get_taxonomy_labels()}. By default tag labels are used for non-hierarchical types and category labels for hierarchical ones.
 282 *
 283 * @package WordPress
 284 * @subpackage Taxonomy
 285 * @since 2.3.0
 286 * @uses $wp_taxonomies Inserts new taxonomy object into the list
 287 * @uses $wp_rewrite Adds rewrite tags and permastructs
 288 * @uses $wp Adds query vars
 289 *
 290 * @param string $taxonomy Name of taxonomy object
 291 * @param array|string $object_type Name of the object type for the taxonomy object.
 292 * @param array|string $args See above description for the two keys values.
 293 */
 294function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
 295	global $wp_taxonomies, $wp_rewrite, $wp;
 296
 297	if ( ! is_array($wp_taxonomies) )
 298		$wp_taxonomies = array();
 299
 300	$defaults = array(	'hierarchical' => false,
 301						'update_count_callback' => '',
 302						'rewrite' => true,
 303						'query_var' => $taxonomy,
 304						'public' => true,
 305						'show_ui' => null,
 306						'show_tagcloud' => null,
 307						'_builtin' => false,
 308						'labels' => array(),
 309						'capabilities' => array(),
 310						'show_in_nav_menus' => null,
 311					);
 312	$args = wp_parse_args($args, $defaults);
 313
 314	if ( false !== $args['query_var'] && !empty($wp) ) {
 315		if ( true === $args['query_var'] )
 316			$args['query_var'] = $taxonomy;
 317		$args['query_var'] = sanitize_title_with_dashes($args['query_var']);
 318		$wp->add_query_var($args['query_var']);
 319	}
 320
 321	if ( false !== $args['rewrite'] && '' != get_option('permalink_structure') ) {
 322		$args['rewrite'] = wp_parse_args($args['rewrite'], array(
 323			'slug' => sanitize_title_with_dashes($taxonomy),
 324			'with_front' => true,
 325			'hierarchical' => false
 326		));
 327
 328		if ( $args['hierarchical'] && $args['rewrite']['hierarchical'] )
 329			$tag = '(.+?)';
 330		else
 331			$tag = '([^/]+)';
 332
 333		$wp_rewrite->add_rewrite_tag("%$taxonomy%", $tag, $args['query_var'] ? "{$args['query_var']}=" : "taxonomy=$taxonomy&term=");
 334		$wp_rewrite->add_permastruct($taxonomy, "{$args['rewrite']['slug']}/%$taxonomy%", $args['rewrite']['with_front']);
 335	}
 336
 337	if ( is_null($args['show_ui']) )
 338		$args['show_ui'] = $args['public'];
 339
 340	// Whether to show this type in nav-menus.php. Defaults to the setting for public.
 341	if ( null === $args['show_in_nav_menus'] )
 342		$args['show_in_nav_menus'] = $args['public'];
 343
 344	if ( is_null($args['show_tagcloud']) )
 345		$args['show_tagcloud'] = $args['show_ui'];
 346
 347	$default_caps = array(
 348		'manage_terms' => 'manage_categories',
 349		'edit_terms'   => 'manage_categories',
 350		'delete_terms' => 'manage_categories',
 351		'assign_terms' => 'edit_posts',
 352	);
 353	$args['cap'] = (object) array_merge( $default_caps, $args['capabilities'] );
 354	unset( $args['capabilities'] );
 355
 356	$args['name'] = $taxonomy;
 357	$args['object_type'] =  array_unique( (array)$object_type );
 358
 359	$args['labels'] = get_taxonomy_labels( (object) $args );
 360	$args['label'] = $args['labels']->name;
 361
 362	$wp_taxonomies[$taxonomy] = (object) $args;
 363
 364	// register callback handling for metabox
 365 	add_filter('wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term');
 366
 367	do_action( 'registered_taxonomy', $taxonomy, $object_type, $args );
 368}
 369
 370/**
 371 * Builds an object with all taxonomy labels out of a taxonomy object
 372 *
 373 * Accepted keys of the label array in the taxonomy object:
 374 * - name - general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is Tags/Categories
 375 * - singular_name - name for one object of this taxonomy. Default is Tag/Category
 376 * - search_items - Default is Search Tags/Search Categories
 377 * - popular_items - This string isn't used on hierarchical taxonomies. Default is Popular Tags
 378 * - all_items - Default is All Tags/All Categories
 379 * - parent_item - This string isn't used on non-hierarchical taxonomies. In hierarchical ones the default is Parent Category
 380 * - parent_item_colon - The same as <code>parent_item</code>, but with colon <code>:</code> in the end
 381 * - edit_item - Default is Edit Tag/Edit Category
 382 * - update_item - Default is Update Tag/Update Category
 383 * - add_new_item - Default is Add New Tag/Add New Category
 384 * - new_item_name - Default is New Tag Name/New Category Name
 385 * - separate_items_with_commas - This string isn't used on hierarchical taxonomies. Default is "Separate tags with commas," used in the meta box.
 386 * - 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.
 387 * - 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.
 388 *
 389 * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories.)
 390 *
 391 * @since 3.0.0
 392 * @param object $tax Taxonomy object
 393 * @return object object with all the labels as member variables
 394 */
 395
 396function get_taxonomy_labels( $tax ) {
 397	if ( isset( $tax->helps ) && empty( $tax->labels['separate_items_with_commas'] ) )
 398		$tax->labels['separate_items_with_commas'] = $tax->helps;
 399
 400	$nohier_vs_hier_defaults = array(
 401		'name' => array( _x( 'Tags', 'taxonomy general name' ), _x( 'Categories', 'taxonomy general name' ) ),
 402		'singular_name' => array( _x( 'Tag', 'taxonomy singular name' ), _x( 'Category', 'taxonomy singular name' ) ),
 403		'search_items' => array( __( 'Search Tags' ), __( 'Search Categories' ) ),
 404		'popular_items' => array( __( 'Popular Tags' ), null ),
 405		'all_items' => array( __( 'All Tags' ), __( 'All Categories' ) ),
 406		'parent_item' => array( null, __( 'Parent Category' ) ),
 407		'parent_item_colon' => array( null, __( 'Parent Category:' ) ),
 408		'edit_item' => array( __( 'Edit Tag' ), __( 'Edit Category' ) ),
 409		'view_item' => array( __( 'View Tag' ), __( 'View Category' ) ),
 410		'update_item' => array( __( 'Update Tag' ), __( 'Update Category' ) ),
 411		'add_new_item' => array( __( 'Add New Tag' ), __( 'Add New Category' ) ),
 412		'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ),
 413		'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ),
 414		'add_or_remove_items' => array( __( 'Add or remove tags' ), null ),
 415		'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ),
 416	);
 417	$nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
 418
 419	return _get_custom_object_labels( $tax, $nohier_vs_hier_defaults );
 420}
 421
 422/**
 423 * Add an already registered taxonomy to an object type.
 424 *
 425 * @package WordPress
 426 * @subpackage Taxonomy
 427 * @since 3.0.0
 428 * @uses $wp_taxonomies Modifies taxonomy object
 429 *
 430 * @param string $taxonomy Name of taxonomy object
 431 * @param array|string $object_type Name of the object type
 432 * @return bool True if successful, false if not
 433 */
 434function register_taxonomy_for_object_type( $taxonomy, $object_type) {
 435	global $wp_taxonomies;
 436
 437	if ( !isset($wp_taxonomies[$taxonomy]) )
 438		return false;
 439
 440	if ( ! get_post_type_object($object_type) )
 441		return false;
 442
 443	if ( ! in_array( $object_type, $wp_taxonomies[$taxonomy]->object_type ) )
 444		$wp_taxonomies[$taxonomy]->object_type[] = $object_type;
 445
 446	return true;
 447}
 448
 449//
 450// Term API
 451//
 452
 453/**
 454 * Retrieve object_ids of valid taxonomy and term.
 455 *
 456 * The strings of $taxonomies must exist before this function will continue. On
 457 * failure of finding a valid taxonomy, it will return an WP_Error class, kind
 458 * of like Exceptions in PHP 5, except you can't catch them. Even so, you can
 459 * still test for the WP_Error class and get the error message.
 460 *
 461 * The $terms aren't checked the same as $taxonomies, but still need to exist
 462 * for $object_ids to be returned.
 463 *
 464 * It is possible to change the order that object_ids is returned by either
 465 * using PHP sort family functions or using the database by using $args with
 466 * either ASC or DESC array. The value should be in the key named 'order'.
 467 *
 468 * @package WordPress
 469 * @subpackage Taxonomy
 470 * @since 2.3.0
 471 *
 472 * @uses $wpdb
 473 * @uses wp_parse_args() Creates an array from string $args.
 474 *
 475 * @param int|array $term_ids Term id or array of term ids of terms that will be used
 476 * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names
 477 * @param array|string $args Change the order of the object_ids, either ASC or DESC
 478 * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success
 479 *	the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
 480 */
 481function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
 482	global $wpdb;
 483
 484	if ( ! is_array( $term_ids ) )
 485		$term_ids = array( $term_ids );
 486
 487	if ( ! is_array( $taxonomies ) )
 488		$taxonomies = array( $taxonomies );
 489
 490	foreach ( (array) $taxonomies as $taxonomy ) {
 491		if ( ! taxonomy_exists( $taxonomy ) )
 492			return new WP_Error( 'invalid_taxonomy', __( 'Invalid Taxonomy' ) );
 493	}
 494
 495	$defaults = array( 'order' => 'ASC' );
 496	$args = wp_parse_args( $args, $defaults );
 497	extract( $args, EXTR_SKIP );
 498
 499	$order = ( 'desc' == strtolower( $order ) ) ? 'DESC' : 'ASC';
 500
 501	$term_ids = array_map('intval', $term_ids );
 502
 503	$taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
 504	$term_ids = "'" . implode( "', '", $term_ids ) . "'";
 505
 506	$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");
 507
 508	if ( ! $object_ids )
 509		return array();
 510
 511	return $object_ids;
 512}
 513
 514/**
 515 * Given a taxonomy query, generates SQL to be appended to a main query.
 516 *
 517 * @since 3.1.0
 518 *
 519 * @see WP_Tax_Query
 520 *
 521 * @param array $tax_query A compact tax query
 522 * @param string $primary_table
 523 * @param string $primary_id_column
 524 * @return array
 525 */
 526function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) {
 527	$tax_query_obj = new WP_Tax_Query( $tax_query );
 528	return $tax_query_obj->get_sql( $primary_table, $primary_id_column );
 529}
 530
 531/**
 532 * Container class for a multiple taxonomy query.
 533 *
 534 * @since 3.1.0
 535 */
 536class WP_Tax_Query {
 537
 538	/**
 539	 * List of taxonomy queries. A single taxonomy query is an associative array:
 540	 * - 'taxonomy' string The taxonomy being queried
 541	 * - 'terms' string|array The list of terms
 542	 * - 'field' string (optional) Which term field is being used.
 543	 *		Possible values: 'term_id', 'slug' or 'name'
 544	 *		Default: 'term_id'
 545	 * - 'operator' string (optional)
 546	 *		Possible values: 'AND', 'IN' or 'NOT IN'.
 547	 *		Default: 'IN'
 548	 * - 'include_children' bool (optional) Whether to include child terms.
 549	 *		Default: true
 550	 *
 551	 * @since 3.1.0
 552	 * @access public
 553	 * @var array
 554	 */
 555	public $queries = array();
 556
 557	/**
 558	 * The relation between the queries. Can be one of 'AND' or 'OR'.
 559	 *
 560	 * @since 3.1.0
 561	 * @access public
 562	 * @var string
 563	 */
 564	public $relation;
 565
 566	/**
 567	 * Standard response when the query should not return any rows.
 568	 *
 569	 * @since 3.2.0
 570	 * @access private
 571	 * @var string
 572	 */
 573	private static $no_results = array( 'join' => '', 'where' => ' AND 0 = 1' );
 574
 575	/**
 576	 * Constructor.
 577	 *
 578	 * Parses a compact tax query and sets defaults.
 579	 *
 580	 * @since 3.1.0
 581	 * @access public
 582	 *
 583	 * @param array $tax_query A compact tax query:
 584	 *  array(
 585	 *    'relation' => 'OR',
 586	 *    array(
 587	 *      'taxonomy' => 'tax1',
 588	 *      'terms' => array( 'term1', 'term2' ),
 589	 *      'field' => 'slug',
 590	 *    ),
 591	 *    array(
 592	 *      'taxonomy' => 'tax2',
 593	 *      'terms' => array( 'term-a', 'term-b' ),
 594	 *      'field' => 'slug',
 595	 *    ),
 596	 *  )
 597	 */
 598	public function __construct( $tax_query ) {
 599		if ( isset( $tax_query['relation'] ) && strtoupper( $tax_query['relation'] ) == 'OR' ) {
 600			$this->relation = 'OR';
 601		} else {
 602			$this->relation = 'AND';
 603		}
 604
 605		$defaults = array(
 606			'taxonomy' => '',
 607			'terms' => array(),
 608			'include_children' => true,
 609			'field' => 'term_id',
 610			'operator' => 'IN',
 611		);
 612
 613		foreach ( $tax_query as $query ) {
 614			if ( ! is_array( $query ) )
 615				continue;
 616
 617			$query = array_merge( $defaults, $query );
 618
 619			$query['terms'] = (array) $query['terms'];
 620
 621			$this->queries[] = $query;
 622		}
 623	}
 624
 625	/**
 626	 * Generates SQL clauses to be appended to a main query.
 627	 *
 628	 * @since 3.1.0
 629	 * @access public
 630	 *
 631	 * @param string $primary_table
 632	 * @param string $primary_id_column
 633	 * @return array
 634	 */
 635	public function get_sql( $primary_table, $primary_id_column ) {
 636		global $wpdb;
 637
 638		$join = '';
 639		$where = array();
 640		$i = 0;
 641
 642		foreach ( $this->queries as $query ) {
 643			$this->clean_query( $query );
 644
 645			if ( is_wp_error( $query ) ) {
 646				return self::$no_results;
 647			}
 648
 649			extract( $query );
 650
 651			if ( 'IN' == $operator ) {
 652
 653				if ( empty( $terms ) ) {
 654					if ( 'OR' == $this->relation )
 655						continue;
 656					else
 657						return self::$no_results;
 658				}
 659
 660				$terms = implode( ',', $terms );
 661
 662				$alias = $i ? 'tt' . $i : $wpdb->term_relationships;
 663
 664				$join .= " INNER JOIN $wpdb->term_relationships";
 665				$join .= $i ? " AS $alias" : '';
 666				$join .= " ON ($primary_table.$primary_id_column = $alias.object_id)";
 667
 668				$where[] = "$alias.term_taxonomy_id $operator ($terms)";
 669			} elseif ( 'NOT IN' == $operator ) {
 670
 671				if ( empty( $terms ) )
 672					continue;
 673
 674				$terms = implode( ',', $terms );
 675
 676				$where[] = "$primary_table.$primary_id_column NOT IN (
 677					SELECT object_id
 678					FROM $wpdb->term_relationships
 679					WHERE term_taxonomy_id IN ($terms)
 680				)";
 681			} elseif ( 'AND' == $operator ) {
 682
 683				if ( empty( $terms ) )
 684					continue;
 685
 686				$num_terms = count( $terms );
 687
 688				$terms = implode( ',', $terms );
 689
 690				$where[] = "(
 691					SELECT COUNT(1)
 692					FROM $wpdb->term_relationships
 693					WHERE term_taxonomy_id IN ($terms)
 694					AND object_id = $primary_table.$primary_id_column
 695				) = $num_terms";
 696			}
 697
 698			$i++;
 699		}
 700
 701		if ( !empty( $where ) )
 702			$where = ' AND ( ' . implode( " $this->relation ", $where ) . ' )';
 703		else
 704			$where = '';
 705
 706		return compact( 'join', 'where' );
 707	}
 708
 709	/**
 710	 * Validates a single query.
 711	 *
 712	 * @since 3.2.0
 713	 * @access private
 714	 *
 715	 * @param array &$query The single query
 716	 */
 717	private function clean_query( &$query ) {
 718		if ( ! taxonomy_exists( $query['taxonomy'] ) ) {
 719			$query = new WP_Error( 'Invalid taxonomy' );
 720			return;
 721		}
 722
 723		$query['terms'] = array_unique( (array) $query['terms'] );
 724
 725		if ( is_taxonomy_hierarchical( $query['taxonomy'] ) && $query['include_children'] ) {
 726			$this->transform_query( $query, 'term_id' );
 727
 728			if ( is_wp_error( $query ) )
 729				return;
 730
 731			$children = array();
 732			foreach ( $query['terms'] as $term ) {
 733				$children = array_merge( $children, get_term_children( $term, $query['taxonomy'] ) );
 734				$children[] = $term;
 735			}
 736			$query['terms'] = $children;
 737		}
 738
 739		$this->transform_query( $query, 'term_taxonomy_id' );
 740	}
 741
 742	/**
 743	 * Transforms a single query, from one field to another.
 744	 *
 745	 * @since 3.2.0
 746	 * @access private
 747	 *
 748	 * @param array &$query The single query
 749	 * @param string $resulting_field The resulting field
 750	 */
 751	private function transform_query( &$query, $resulting_field ) {
 752		global $wpdb;
 753
 754		if ( empty( $query['terms'] ) )
 755			return;
 756
 757		if ( $query['field'] == $resulting_field )
 758			return;
 759
 760		$resulting_field = esc_sql( $resulting_field );
 761
 762		switch ( $query['field'] ) {
 763			case 'slug':
 764			case 'name':
 765				$terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $query['terms'] ) ) . "'";
 766				$terms = $wpdb->get_col( "
 767					SELECT $wpdb->term_taxonomy.$resulting_field
 768					FROM $wpdb->term_taxonomy
 769					INNER JOIN $wpdb->terms USING (term_id)
 770					WHERE taxonomy = '{$query['taxonomy']}'
 771					AND $wpdb->terms.{$query['field']} IN ($terms)
 772				" );
 773				break;
 774
 775			default:
 776				$terms = implode( ',', array_map( 'intval', $query['terms'] ) );
 777				$terms = $wpdb->get_col( "
 778					SELECT $resulting_field
 779					FROM $wpdb->term_taxonomy
 780					WHERE taxonomy = '{$query['taxonomy']}'
 781					AND term_id IN ($terms)
 782				" );
 783		}
 784
 785		if ( 'AND' == $query['operator'] && count( $terms ) < count( $query['terms'] ) ) {
 786			$query = new WP_Error( 'Inexistent terms' );
 787			return;
 788		}
 789
 790		$query['terms'] = $terms;
 791		$query['field'] = $resulting_field;
 792	}
 793}
 794
 795/**
 796 * Get all Term data from database by Term ID.
 797 *
 798 * The usage of the get_term function is to apply filters to a term object. It
 799 * is possible to get a term object from the database before applying the
 800 * filters.
 801 *
 802 * $term ID must be part of $taxonomy, to get from the database. Failure, might
 803 * be able to be captured by the hooks. Failure would be the same value as $wpdb
 804 * returns for the get_row method.
 805 *
 806 * There are two hooks, one is specifically for each term, named 'get_term', and
 807 * the second is for the taxonomy name, 'term_$taxonomy'. Both hooks gets the
 808 * term object, and the taxonomy name as parameters. Both hooks are expected to
 809 * return a Term object.
 810 *
 811 * 'get_term' hook - Takes two parameters the term Object and the taxonomy name.
 812 * Must return term object. Used in get_term() as a catch-all filter for every
 813 * $term.
 814 *
 815 * 'get_$taxonomy' hook - Takes two parameters the term Object and the taxonomy
 816 * name. Must return term object. $taxonomy will be the taxonomy name, so for
 817 * example, if 'category', it would be 'get_category' as the filter name. Useful
 818 * for custom taxonomies or plugging into default taxonomies.
 819 *
 820 * @package WordPress
 821 * @subpackage Taxonomy
 822 * @since 2.3.0
 823 *
 824 * @uses $wpdb
 825 * @uses sanitize_term() Cleanses the term based on $filter context before returning.
 826 * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
 827 *
 828 * @param int|object $term If integer, will get from database. If object will apply filters and return $term.
 829 * @param string $taxonomy Taxonomy name that $term is part of.
 830 * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
 831 * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
 832 * @return mixed|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
 833 * exist then WP_Error will be returned.
 834 */
 835function &get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') {
 836	global $wpdb;
 837	$null = null;
 838
 839	if ( empty($term) ) {
 840		$error = new WP_Error('invalid_term', __('Empty Term'));
 841		return $error;
 842	}
 843
 844	if ( ! taxonomy_exists($taxonomy) ) {
 845		$error = new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
 846		return $error;
 847	}
 848
 849	if ( is_object($term) && empty($term->filter) ) {
 850		wp_cache_add($term->term_id, $term, $taxonomy);
 851		$_term = $term;
 852	} else {
 853		if ( is_object($term) )
 854			$term = $term->term_id;
 855		if ( !$term = (int) $term )
 856			return $null;
 857		if ( ! $_term = wp_cache_get($term, $taxonomy) ) {
 858			$_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) );
 859			if ( ! $_term )
 860				return $null;
 861			wp_cache_add($term, $_term, $taxonomy);
 862		}
 863	}
 864
 865	$_term = apply_filters('get_term', $_term, $taxonomy);
 866	$_term = apply_filters("get_$taxonomy", $_term, $taxonomy);
 867	$_term = sanitize_term($_term, $taxonomy, $filter);
 868
 869	if ( $output == OBJECT ) {
 870		return $_term;
 871	} elseif ( $output == ARRAY_A ) {
 872		$__term = get_object_vars($_term);
 873		return $__term;
 874	} elseif ( $output == ARRAY_N ) {
 875		$__term = array_values(get_object_vars($_term));
 876		return $__term;
 877	} else {
 878		return $_term;
 879	}
 880}
 881
 882/**
 883 * Get all Term data from database by Term field and data.
 884 *
 885 * Warning: $value is not escaped for 'name' $field. You must do it yourself, if
 886 * required.
 887 *
 888 * The default $field is 'id', therefore it is possible to also use null for
 889 * field, but not recommended that you do so.
 890 *
 891 * If $value does not exist, the return value will be false. If $taxonomy exists
 892 * and $field and $value combinations exist, the Term will be returned.
 893 *
 894 * @package WordPress
 895 * @subpackage Taxonomy
 896 * @since 2.3.0
 897 *
 898 * @uses $wpdb
 899 * @uses sanitize_term() Cleanses the term based on $filter context before returning.
 900 * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
 901 *
 902 * @param string $field Either 'slug', 'name', or 'id'
 903 * @param string|int $value Search for this term value
 904 * @param string $taxonomy Taxonomy Name
 905 * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
 906 * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
 907 * @return mixed Term Row from database. Will return false if $taxonomy does not exist or $term was not found.
 908 */
 909function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') {
 910	global $wpdb;
 911
 912	if ( ! taxonomy_exists($taxonomy) )
 913		return false;
 914
 915	if ( 'slug' == $field ) {
 916		$field = 't.slug';
 917		$value = sanitize_title($value);
 918		if ( empty($value) )
 919			return false;
 920	} else if ( 'name' == $field ) {
 921		// Assume already escaped
 922		$value = stripslashes($value);
 923		$field = 't.name';
 924	} else {
 925		$term = get_term( (int) $value, $taxonomy, $output, $filter);
 926		if ( is_wp_error( $term ) )
 927			$term = false;
 928		return $term;
 929	}
 930
 931	$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) );
 932	if ( !$term )
 933		return false;
 934
 935	wp_cache_add($term->term_id, $term, $taxonomy);
 936
 937	$term = apply_filters('get_term', $term, $taxonomy);
 938	$term = apply_filters("get_$taxonomy", $term, $taxonomy);
 939	$term = sanitize_term($term, $taxonomy, $filter);
 940
 941	if ( $output == OBJECT ) {
 942		return $term;
 943	} elseif ( $output == ARRAY_A ) {
 944		return get_object_vars($term);
 945	} elseif ( $output == ARRAY_N ) {
 946		return array_values(get_object_vars($term));
 947	} else {
 948		return $term;
 949	}
 950}
 951
 952/**
 953 * Merge all term children into a single array of their IDs.
 954 *
 955 * This recursive function will merge all of the children of $term into the same
 956 * array of term IDs. Only useful for taxonomies which are hierarchical.
 957 *
 958 * Will return an empty array if $term does not exist in $taxonomy.
 959 *
 960 * @package WordPress
 961 * @subpackage Taxonomy
 962 * @since 2.3.0
 963 *
 964 * @uses $wpdb
 965 * @uses _get_term_hierarchy()
 966 * @uses get_term_children() Used to get the children of both $taxonomy and the parent $term
 967 *
 968 * @param string $term_id ID of Term to get children
 969 * @param string $taxonomy Taxonomy Name
 970 * @return array|WP_Error List of Term Objects. WP_Error returned if $taxonomy does not exist
 971 */
 972function get_term_children( $term_id, $taxonomy ) {
 973	if ( ! taxonomy_exists($taxonomy) )
 974		return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
 975
 976	$term_id = intval( $term_id );
 977
 978	$terms = _get_term_hierarchy($taxonomy);
 979
 980	if ( ! isset($terms[$term_id]) )
 981		return array();
 982
 983	$children = $terms[$term_id];
 984
 985	foreach ( (array) $terms[$term_id] as $child ) {
 986		if ( isset($terms[$child]) )
 987			$children = array_merge($children, get_term_children($child, $taxonomy));
 988	}
 989
 990	return $children;
 991}
 992
 993/**
 994 * Get sanitized Term field.
 995 *
 996 * Does checks for $term, based on the $taxonomy. The function is for contextual
 997 * reasons and for simplicity of usage. See sanitize_term_field() for more
 998 * information.
 999 *
1000 * @package WordPress
1001 * @subpackage Taxonomy
1002 * @since 2.3.0
1003 *
1004 * @uses sanitize_term_field() Passes the return value in sanitize_term_field on success.
1005 *
1006 * @param string $field Term field to fetch
1007 * @param int $term Term ID
1008 * @param string $taxonomy Taxonomy Name
1009 * @param string $context Optional, default is display. Look at sanitize_term_field() for available options.
1010 * @return mixed Will return an empty string if $term is not an object or if $field is not set in $term.
1011 */
1012function get_term_field( $field, $term, $taxonomy, $context = 'display' ) {
1013	$term = (int) $term;
1014	$term = get_term( $term, $taxonomy );
1015	if ( is_wp_error($term) )
1016		return $term;
1017
1018	if ( !is_object($term) )
1019		return '';
1020
1021	if ( !isset($term->$field) )
1022		return '';
1023
1024	return sanitize_term_field($field, $term->$field, $term->term_id, $taxonomy, $context);
1025}
1026
1027/**
1028 * Sanitizes Term for editing.
1029 *
1030 * Return value is sanitize_term() and usage is for sanitizing the term for
1031 * editing. Function is for contextual and simplicity.
1032 *
1033 * @package WordPress
1034 * @subpackage Taxonomy
1035 * @since 2.3.0
1036 *
1037 * @uses sanitize_term() Passes the return value on success
1038 *
1039 * @param int|object $id Term ID or Object
1040 * @param string $taxonomy Taxonomy Name
1041 * @return mixed|null|WP_Error Will return empty string if $term is not an object.
1042 */
1043function get_term_to_edit( $id, $taxonomy ) {
1044	$term = get_term( $id, $taxonomy );
1045
1046	if ( is_wp_error($term) )
1047		return $term;
1048
1049	if ( !is_object($term) )
1050		return '';
1051
1052	return sanitize_term($term, $taxonomy, 'edit');
1053}
1054
1055/**
1056 * Retrieve the terms in a given taxonomy or list of taxonomies.
1057 *
1058 * You can fully inject any customizations to the query before it is sent, as
1059 * well as control the output with a filter.
1060 *
1061 * The 'get_terms' filter will be called when the cache has the term and will
1062 * pass the found term along with the array of $taxonomies and array of $args.
1063 * This filter is also called before the array of terms is passed and will pass
1064 * the array of terms, along with the $taxonomies and $args.
1065 *
1066 * The 'list_terms_exclusions' filter passes the compiled exclusions along with
1067 * the $args.
1068 *
1069 * The 'get_terms_orderby' filter passes the ORDER BY clause for the query
1070 * along with the $args array.
1071 *
1072 * The 'get_terms_fields' filter passes the fields for the SELECT query
1073 * along with the $args array.
1074 *
1075 * The list of arguments that $args can contain, which will overwrite the defaults:
1076 *
1077 * orderby - Default is 'name'. Can be name, count, term_group, slug or nothing
1078 * (will use term_id), Passing a custom value other than these will cause it to
1079 * order based on the custom value.
1080 *
1081 * order - Default is ASC. Can use DESC.
1082 *
1083 * hide_empty - Default is true. Will not return empty terms, which means
1084 * terms whose count is 0 according to the given taxonomy.
1085 *
1086 * exclude - Default is an empty array.  An array, comma- or space-delimited string
1087 * of term ids to exclude from the return array.  If 'include' is non-empty,
1088 * 'exclude' is ignored.
1089 *
1090 * exclude_tree - Default is an empty array.  An array, comma- or space-delimited
1091 * string of term ids to exclude from the return array, along with all of their
1092 * descendant terms according to the primary taxonomy.  If 'include' is non-empty,
1093 * 'exclude_tree' is ignored.
1094 *
1095 * include - Default is an empty array.  An array, comma- or space-delimited string
1096 * of term ids to include in the return array.
1097 *
1098 * number - The maximum number of terms to return.  Default is to return them all.
1099 *
1100 * offset - The number by which to offset the terms query.
1101 *
1102 * fields - Default is 'all', which returns an array of term objects.
1103 * If 'fields' is 'ids' or 'names', returns an array of
1104 * integers or strings, respectively.
1105 *
1106 * slug - Returns terms whose "slug" matches this value. Default is empty string.
1107 *
1108 * hierarchical - Whether to include terms that have non-empty descendants
1109 * (even if 'hide_empty' is set to true).
1110 *
1111 * search - Returned terms' names will contain the value of 'search',
1112 * case-insensitive.  Default is an empty string.
1113 *
1114 * name__like - Returned terms' names will begin with the value of 'name__like',
1115 * case-insensitive. Default is empty string.
1116 *
1117 * The argument 'pad_counts', if set to true will include the quantity of a term's
1118 * children in the quantity of each term's "count" object variable.
1119 *
1120 * The 'get' argument, if set to 'all' instead of its default empty string,
1121 * returns terms regardless of ancestry or whether the terms are empty.
1122 *
1123 * The 'child_of' argument, when used, should be set to the integer of a term ID.  Its default
1124 * is 0.  If set to a non-zero value, all returned terms will be descendants
1125 * of that term according to the given taxonomy.  Hence 'child_of' is set to 0
1126 * if more than one taxonomy is passed in $taxonomies, because multiple taxonomies
1127 * make term ancestry ambiguous.
1128 *
1129 * The 'parent' argument, when used, should be set to the integer of a term ID.  Its default is
1130 * the empty string '', which has a different meaning from the integer 0.
1131 * If set to an integer value, all returned terms will have as an immediate
1132 * ancestor the term whose ID is specified by that integer according to the given taxonomy.
1133 * The 'parent' argument is different from 'child_of' in that a term X is considered a 'parent'
1134 * of term Y only if term X is the father of term Y, not its grandfather or great-grandfather, etc.
1135 *
1136 * The 'cache_domain' argument enables a unique cache key to be produced when this query is stored
1137 * in object cache. For instance, if you are using one of this function's filters to modify the
1138 * query (such as 'terms_clauses'), setting 'cache_domain' to a unique value will not overwrite
1139 * the cache for similar queries. Default value is 'core'.
1140 *
1141 * @package WordPress
1142 * @subpackage Taxonomy
1143 * @since 2.3.0
1144 *
1145 * @uses $wpdb
1146 * @uses wp_parse_args() Merges the defaults with those defined by $args and allows for strings.
1147 *
1148 * @param string|array $taxonomies Taxonomy name or list of Taxonomy names
1149 * @param string|array $args The values of what to search for when returning terms
1150 * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies do not exist.
1151 */
1152function &get_terms($taxonomies, $args = '') {
1153	global $wpdb;
1154	$empty_array = array();
1155
1156	$single_taxonomy = false;
1157	if ( !is_array($taxonomies) ) {
1158		$single_taxonomy = true;
1159		$taxonomies = array($taxonomies);
1160	}
1161
1162	foreach ( $taxonomies as $taxonomy ) {
1163		if ( ! taxonomy_exists($taxonomy) ) {
1164			$error = new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
1165			return $error;
1166		}
1167	}
1168
1169	$defaults = array('orderby' => 'name', 'order' => 'ASC',
1170		'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(),
1171		'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '',
1172		'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '',
1173		'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' );
1174	$args = wp_parse_args( $args, $defaults );
1175	$args['number'] = absint( $args['number'] );
1176	$args['offset'] = absint( $args['offset'] );
1177	if ( !$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) ||
1178		'' !== $args['parent'] ) {
1179		$args['child_of'] = 0;
1180		$args['hierarchical'] = false;
1181		$args['pad_counts'] = false;
1182	}
1183
1184	if ( 'all' == $args['get'] ) {
1185		$args['child_of'] = 0;
1186		$args['hide_empty'] = 0;
1187		$args['hierarchical'] = false;
1188		$args['pad_counts'] = false;
1189	}
1190
1191	$args = apply_filters( 'get_terms_args', $args, $taxonomies );
1192
1193	extract($args, EXTR_SKIP);
1194
1195	if ( $child_of ) {
1196		$hierarchy = _get_term_hierarchy($taxonomies[0]);
1197		if ( !isset($hierarchy[$child_of]) )
1198			return $empty_array;
1199	}
1200
1201	if ( $parent ) {
1202		$hierarchy = _get_term_hierarchy($taxonomies[0]);
1203		if ( !isset($hierarchy[$parent]) )
1204			return $empty_array;
1205	}
1206
1207	// $args can be whatever, only use the args defined in defaults to compute the key
1208	$filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
1209	$key = md5( serialize( compact(array_keys($defaults)) ) . serialize( $taxonomies ) . $filter_key );
1210	$last_changed = wp_cache_get('last_changed', 'terms');
1211	if ( !$last_changed ) {
1212		$last_changed = time();
1213		wp_cache_set('last_changed', $last_changed, 'terms');
1214	}
1215	$cache_key = "get_terms:$key:$last_changed";
1216	$cache = wp_cache_get( $cache_key, 'terms' );
1217	if ( false !== $cache ) {
1218		$cache = apply_filters('get_terms', $cache, $taxonomies, $args);
1219		return $cache;
1220	}
1221
1222	$_orderby = strtolower($orderby);
1223	if ( 'count' == $_orderby )
1224		$orderby = 'tt.count';
1225	else if ( 'name' == $_orderby )
1226		$orderby = 't.name';
1227	else if ( 'slug' == $_orderby )
1228		$orderby = 't.slug';
1229	else if ( 'term_group' == $_orderby )
1230		$orderby = 't.term_group';
1231	else if ( 'none' == $_orderby )
1232		$orderby = '';
1233	elseif ( empty($_orderby) || 'id' == $_orderby )
1234		$orderby = 't.term_id';
1235	else
1236		$orderby = 't.name';
1237
1238	$orderby = apply_filters( 'get_terms_orderby', $orderby, $args );
1239
1240	if ( !empty($orderby) )
1241		$orderby = "ORDER BY $orderby";
1242	else
1243		$order = '';
1244
1245	$order = strtoupper( $order );
1246	if ( '' !== $order && !in_array( $order, array( 'ASC', 'DESC' ) ) )
1247		$order = 'ASC';
1248
1249	$where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')";
1250	$inclusions = '';
1251	if ( !empty($include) ) {
1252		$exclude = '';
1253		$exclude_tree = '';
1254		$interms = wp_parse_id_list($include);
1255		foreach ( $interms as $interm ) {
1256			if ( empty($inclusions) )
1257				$inclusions = ' AND ( t.term_id = ' . intval($interm) . ' ';
1258			else
1259				$inclusions .= ' OR t.term_id = ' . intval($interm) . ' ';
1260		}
1261	}
1262
1263	if ( !empty($inclusions) )
1264		$inclusions .= ')';
1265	$where .= $inclusions;
1266
1267	$exclusions = '';
1268	if ( !empty( $exclude_tree ) ) {
1269		$excluded_trunks = wp_parse_id_list($exclude_tree);
1270		foreach ( $excluded_trunks as $extrunk ) {
1271			$excluded_children = (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids', 'hide_empty' => 0));
1272			$excluded_children[] = $extrunk;
1273			foreach( $excluded_children as $exterm ) {
1274				if ( empty($exclusions) )
1275					$exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
1276				else
1277					$exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
1278			}
1279		}
1280	}
1281
1282	if ( !empty($exclude) ) {
1283		$exterms = wp_parse_id_list($exclude);
1284		foreach ( $exterms as $exterm ) {
1285			if ( empty($exclusions) )
1286				$exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
1287			else
1288				$exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
1289		}
1290	}
1291
1292	if ( !empty($exclusions) )
1293		$exclusions .= ')';
1294	$exclusions = apply_filters('list_terms_exclusions', $exclusions, $args );
1295	$where .= $exclusions;
1296
1297	if ( !empty($slug) ) {
1298		$slug = sanitize_title($slug);
1299		$where .= " AND t.slug = '$slug'";
1300	}
1301
1302	if ( !empty($name__like) ) {
1303		$name__like = like_escape( $name__like );
1304		$where .= $wpdb->prepare( " AND t.name LIKE %s", $name__like . '%' );
1305	}
1306
1307	if ( '' !== $parent ) {
1308		$parent = (int) $parent;
1309		$where .= " AND tt.parent = '$parent'";
1310	}
1311
1312	if ( $hide_empty && !$hierarchical )
1313		$where .= ' AND tt.count > 0';
1314
1315	// don't limit the query results when we have to descend the family tree
1316	if ( ! empty($number) && ! $hierarchical && empty( $child_of ) && '' === $parent ) {
1317		if ( $offset )
1318			$limits = 'LIMIT ' . $offset . ',' . $number;
1319		else
1320			$limits = 'LIMIT ' . $number;
1321	} else {
1322		$limits = '';
1323	}
1324
1325	if ( !empty($search) ) {
1326		$search = like_escape($search);
1327		$where .= $wpdb->prepare( " AND (t.name LIKE %s)", '%' . $search . '%');
1328	}
1329
1330	$selects = array();
1331	switch ( $fields ) {
1332		case 'all':
1333			$selects = array('t.*', 'tt.*');
1334			break;
1335		case 'ids':
1336		case 'id=>parent':
1337			$selects = array('t.term_id', 'tt.parent', 'tt.count');
1338			break;
1339		case 'names':
1340			$selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name');
1341			break;
1342		case 'count':
1343			$orderby = '';
1344			$order = '';
1345			$selects = array('COUNT(*)');
1346	}
1347
1348	$_fields = $fields;
1349
1350	$fields = implode(', ', apply_filters( 'get_terms_fields', $selects, $args ));
1351
1352	$join = "INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
1353
1354	$pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' );
1355	$clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args );
1356	foreach ( $pieces as $piece )
1357		$$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
1358
1359	$query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits";
1360
1361	$fields = $_fields;
1362
1363	if ( 'count' == $fields ) {
1364		$term_count = $wpdb->get_var($query);
1365		return $term_count;
1366	}
1367
1368	$terms = $wpdb->get_results($query);
1369	if ( 'all' == $fields ) {
1370		update_term_cache($terms);
1371	}
1372
1373	if ( empty($terms) ) {
1374		wp_cache_add( $cache_key, array(), 'terms', 86400 ); // one day
1375		$terms = apply_filters('get_terms', array(), $taxonomies, $args);
1376		return $terms;
1377	}
1378
1379	if ( $child_of ) {
1380		$children = _get_term_hierarchy($taxonomies[0]);
1381		if ( ! empty($children) )
1382			$terms = & _get_term_children($child_of, $terms, $taxonomies[0]);
1383	}
1384
1385	// Update term counts to include children.
1386	if ( $pad_counts && 'all' == $fields )
1387		_pad_term_counts($terms, $taxonomies[0]);
1388
1389	// Make sure we show empty categories that have children.
1390	if ( $hierarchical && $hide_empty && is_array($terms) ) {
1391		foreach ( $terms as $k => $term ) {
1392			if ( ! $term->count ) {
1393				$children = _get_term_children($term->term_id, $terms, $taxonomies[0]);
1394				if ( is_array($children) )
1395					foreach ( $children as $child )
1396						if ( $child->count )
1397							continue 2;
1398
1399				// It really is empty
1400				unset($terms[$k]);
1401			}
1402		}
1403	}
1404	reset ( $terms );
1405
1406	$_terms = array();
1407	if ( 'id=>parent' == $fields ) {
1408		while ( $term = array_shift($terms) )
1409			$_terms[$term->term_id] = $term->parent;
1410		$terms = $_terms;
1411	} elseif ( 'ids' == $fields ) {
1412		while ( $term = array_shift($terms) )
1413			$_terms[] = $term->term_id;
1414		$terms = $_terms;
1415	} elseif ( 'names' == $fields ) {
1416		while ( $term = array_shift($terms) )
1417			$_terms[] = $term->name;
1418		$terms = $_terms;
1419	}
1420
1421	if ( 0 < $number && intval(@count($terms)) > $number ) {
1422		$terms = array_slice($terms, $offset, $number);
1423	}
1424
1425	wp_cache_add( $cache_key, $terms, 'terms', 86400 ); // one day
1426
1427	$terms = apply_filters('get_terms', $terms, $taxonomies, $args);
1428	return $terms;
1429}
1430
1431/**
1432 * Check if Term exists.
1433 *
1434 * Returns the index of a defined term, or 0 (false) if the term doesn't exist.
1435 *
1436 * Formerly is_term(), introduced in 2.3.0.
1437 *
1438 * @package WordPress
1439 * @subpackage Taxonomy
1440 * @since 3.0.0
1441 *
1442 * @uses $wpdb
1443 *
1444 * @param int|string $term The term to check
1445 * @param string $taxonomy The taxonomy name to use
1446 * @param int $parent ID of parent term under which to confine the exists search.
1447 * @return mixed Get the term id or Term Object, if exists.
1448 */
1449function term_exists($term, $taxonomy = '', $parent = 0) {
1450	global $wpdb;
1451
1452	$select = "SELECT term_id FROM $wpdb->terms as t WHERE ";
1453	$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 ";
1454
1455	if ( is_int($term) ) {
1456		if ( 0 == $term )
1457			return 0;
1458		$where = 't.term_id = %d';
1459		if ( !empty($taxonomy) )
1460			return $wpdb->get_row( $wpdb->prepare( $tax_select . $where . " AND tt.taxonomy = %s", $term, $taxonomy ), ARRAY_A );
1461		else
1462			return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
1463	}
1464
1465	$term = trim( stripslashes( $term ) );
1466
1467	if ( '' === $slug = sanitize_title($term) )
1468		return 0;
1469
1470	$where = 't.slug = %s';
1471	$else_where = 't.name = %s';
1472	$where_fields = array($slug);
1473	$else_where_fields = array($term);
1474	if ( !empty($taxonomy) ) {
1475		$parent = (int) $parent;
1476		if ( $parent > 0 ) {
1477			$where_fields[] = $parent;
1478			$else_where_fields[] = $parent;
1479			$where .= ' AND tt.parent = %d';
1480			$else_where .= ' AND tt.parent = %d';
1481		}
1482
1483		$where_fields[] = $taxonomy;
1484		$else_where_fields[] = $taxonomy;
1485
1486		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) )
1487			return $result;
1488
1489		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);
1490	}
1491
1492	if ( $result = $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $where", $where_fields) ) )
1493		return $result;
1494
1495	return $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $else_where", $else_where_fields) );
1496}
1497
1498/**
1499 * Sanitize Term all fields.
1500 *
1501 * Relies on sanitize_term_field() to sanitize the term. The difference is that
1502 * this function will sanitize <strong>all</strong> fields. The context is based
1503 * on sanitize_term_field().
1504 *
1505 * The $term is expected to be either an array or an object.
1506 *
1507 * @package WordPress
1508 * @subpackage Taxonomy
1509 * @since 2.3.0
1510 *
1511 * @uses sanitize_term_field Used to sanitize all fields in a term
1512 *
1513 * @param array|object $term The term to check
1514 * @param string $taxonomy The taxonomy name to use
1515 * @param string $context Default is 'display'.
1516 * @return array|object Term with all fields sanitized
1517 */
1518function sanitize_term($term, $taxonomy, $context = 'display') {
1519
1520	if ( 'raw' == $context )
1521		return $term;
1522
1523	$fields = array('term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group');
1524
1525	$do_object = false;
1526	if ( is_object($term) )
1527		$do_object = true;
1528
1529	$term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0);
1530
1531	foreach ( (array) $fields as $field ) {
1532		if ( $do_object ) {
1533			if ( isset($term->$field) )
1534				$term->$field = sanitize_term_field($field, $term->$field, $term_id, $taxonomy, $context);
1535		} else {
1536			if ( isset($term[$field]) )
1537				$term[$field] = sanitize_term_field($field, $term[$field], $term_id, $taxonomy, $context);
1538		}
1539	}
1540
1541	if ( $do_object )
1542		$term->filter = $context;
1543	else
1544		$term['filter'] = $context;
1545
1546	return $term;
1547}
1548
1549/**
1550 * Cleanse the field value in the term based on the context.
1551 *
1552 * Passing a term field value through the function should be assumed to have
1553 * cleansed the value for whatever context the term field is going to b…

Large files files are truncated, but you can click here to view the full file