[ Index ]

PHP Cross Reference of BackPress

title

Body

[close]

/includes/ -> class.wp-taxonomy.php (source)

   1  <?php
   2  // Last sync [WP11537] - Refactored into a class based on wp-includes/taxonomy.php
   3  
   4  /**
   5   * Taxonomy API
   6   *
   7   * @package WordPress
   8   * @subpackage Taxonomy
   9   * @since 2.3.0
  10   */
  11  
  12  /**
  13   * WordPress Taxonomy based off of WordPress revision 8782.
  14   *
  15   * @since 2.3.0
  16   */
  17  class WP_Taxonomy {
  18      /**
  19       * Stores the database.
  20       *
  21       * @var unknown_type
  22       */
  23      var $db;
  24      var $taxonomies = array();
  25  
  26  	function WP_Taxonomy( &$db ) {
  27          self::__construct( $db );
  28          register_shutdown_function( array(&$this, '__destruct') );
  29      }
  30  
  31      /**
  32       * PHP5 constructor - Assigns the database to an attribute of the class.
  33       *
  34       * @param unknown_type $db
  35       */
  36  	function __construct( &$db ) {
  37          $this->db =& $db;
  38      }
  39  
  40      /**
  41       * Does nothing.
  42       *
  43       * @package BackPress
  44       * @subpackage Taxonomy
  45       */
  46  	function __destruct() {
  47      }
  48  
  49      /**
  50       * Return all of the taxonomy names that are of $object_type.
  51       *
  52       * It appears that this function can be used to find all of the names inside of
  53       * $this->taxonomies variable.
  54       *
  55       * <code><?php $taxonomies = $this->get_object_taxonomies('post'); ?></code> Should
  56       * result in <code>Array('category', 'post_tag')</code>
  57       *
  58       * @package WordPress
  59       * @subpackage Taxonomy
  60       * @since 2.3.0
  61       *
  62       * @uses $this->taxonomies
  63       *
  64       * @param array|string|object $object_type Name of the type of taxonomy object, or an object (row from posts)
  65       * @return array The names of all taxonomy of $object_type.
  66       */
  67  	function get_object_taxonomies($object_type) {
  68          $object_type = (array) $object_type;
  69  
  70          // WP DIFF
  71          $taxonomies = array();
  72          foreach ( (array) $this->taxonomies as $taxonomy ) {
  73              if ( array_intersect($object_type, (array) $taxonomy->object_type) )
  74                  $taxonomies[] = $taxonomy->name;
  75          }
  76  
  77          return $taxonomies;
  78      }
  79  
  80      /**
  81       * Retrieves the taxonomy object of $taxonomy.
  82       *
  83       * The get_taxonomy function will first check that the parameter string given
  84       * is a taxonomy object and if it is, it will return it.
  85       *
  86       * @package WordPress
  87       * @subpackage Taxonomy
  88       * @since 2.3.0
  89       *
  90       * @uses $this->taxonomies
  91       * @uses $this->is_taxonomy() Checks whether taxonomy exists
  92       *
  93       * @param string $taxonomy Name of taxonomy object to return
  94       * @return object|bool The Taxonomy Object or false if $taxonomy doesn't exist
  95       */
  96  	function get_taxonomy( $taxonomy ) {
  97          if ( !$this->is_taxonomy($taxonomy) )
  98              return false;
  99  
 100          return $this->taxonomies[$taxonomy];
 101      }
 102  
 103      /**
 104       * Checks that the taxonomy name exists.
 105       *
 106       * @package WordPress
 107       * @subpackage Taxonomy
 108       * @since 2.3.0
 109       * 
 110       * @uses $this->taxonomies
 111       *
 112       * @param string $taxonomy Name of taxonomy object
 113       * @return bool Whether the taxonomy exists or not.
 114       */
 115  	function is_taxonomy( $taxonomy ) {
 116          return isset($this->taxonomies[$taxonomy]);
 117      }
 118  
 119      /**
 120       * Whether the taxonomy object is hierarchical.
 121       *
 122       * Checks to make sure that the taxonomy is an object first. Then Gets the
 123       * object, and finally returns the hierarchical value in the object.
 124       *
 125       * A false return value might also mean that the taxonomy does not exist.
 126       *
 127       * @package WordPress
 128       * @subpackage Taxonomy
 129       * @since 2.3.0
 130       *
 131       * @uses $this->is_taxonomy() Checks whether taxonomy exists
 132       * @uses $this->get_taxonomy() Used to get the taxonomy object
 133       *
 134       * @param string $taxonomy Name of taxonomy object
 135       * @return bool Whether the taxonomy is hierarchical
 136       */
 137  	function is_taxonomy_hierarchical($taxonomy) {
 138          if ( !$this->is_taxonomy($taxonomy) )
 139              return false;
 140  
 141          $taxonomy = $this->get_taxonomy($taxonomy);
 142          return $taxonomy->hierarchical;
 143      }
 144  
 145      /**
 146       * Create or modify a taxonomy object. Do not use before init.
 147       *
 148       * A simple function for creating or modifying a taxonomy object based on the
 149       * parameters given. The function will accept an array (third optional
 150       * parameter), along with strings for the taxonomy name and another string for
 151       * the object type.
 152       *
 153       * The function keeps a default set, allowing for the $args to be optional but
 154       * allow the other functions to still work. It is possible to overwrite the
 155       * default set, which contains two keys: hierarchical and update_count_callback.
 156       *
 157       * Nothing is returned, so expect error maybe or use is_taxonomy() to check
 158       * whether taxonomy exists.
 159       *
 160       * Optional $args contents:
 161       *
 162       * hierarachical - has some defined purpose at other parts of the API and is a
 163       * boolean value.
 164       *
 165       * update_count_callback - works much like a hook, in that it will be called
 166       * when the count is updated.
 167       *
 168       * @package WordPress
 169       * @subpackage Taxonomy
 170       * @since 2.3.0
 171       * @uses $this->taxonomies Inserts new taxonomy object into the list
 172       * 
 173       * @param string $taxonomy Name of taxonomy object
 174       * @param string $object_type Name of the object type for the taxonomy object.
 175       * @param array|string $args See above description for the two keys values.
 176       */
 177  	function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
 178          $defaults = array('hierarchical' => false, 'update_count_callback' => '');
 179          $args = wp_parse_args($args, $defaults);
 180  
 181          $args['name'] = $taxonomy;
 182          $args['object_type'] = $object_type;
 183          $this->taxonomies[$taxonomy] = (object) $args;
 184      }
 185  
 186      //
 187      // Term API
 188      //
 189  
 190      /**
 191       * Retrieve object_ids of valid taxonomy and term.
 192       *
 193       * The strings of $taxonomies must exist before this function will continue. On
 194       * failure of finding a valid taxonomy, it will return an WP_Error class, kind
 195       * of like Exceptions in PHP 5, except you can't catch them. Even so, you can
 196       * still test for the WP_Error class and get the error message.
 197       *
 198       * The $terms aren't checked the same as $taxonomies, but still need to exist
 199       * for $object_ids to be returned.
 200       *
 201       * It is possible to change the order that object_ids is returned by either
 202       * using PHP sort family functions or using the database by using $args with
 203       * either ASC or DESC array. The value should be in the key named 'order'.
 204       *
 205       * @package WordPress
 206       * @subpackage Taxonomy
 207       * @since 2.3.0
 208       *
 209       * @uses wp_parse_args() Creates an array from string $args.
 210       *
 211       * @param string|array $terms String of term or array of string values of terms that will be used
 212       * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names
 213       * @param array|string $args Change the order of the object_ids, either ASC or DESC
 214       * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success
 215       *    the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
 216       */
 217  	function get_objects_in_term( $terms, $taxonomies, $args = null ) {
 218          if ( !is_array($terms) )
 219              $terms = array($terms);
 220  
 221          if ( !is_array($taxonomies) )
 222              $taxonomies = array($taxonomies);
 223  
 224          foreach ( (array) $taxonomies as $taxonomy ) {
 225              if ( !$this->is_taxonomy($taxonomy) )
 226                  return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
 227          }
 228  
 229          $defaults = array('order' => 'ASC', 'field' => 'term_id');
 230          $args = wp_parse_args( $args, $defaults );
 231          extract($args, EXTR_SKIP);
 232  
 233          if ( 'tt_id' == $field )
 234              $field = 'tt.term_taxonomy_id';
 235          else
 236              $field = 'tt.term_id';
 237  
 238          $order = ( 'desc' == strtolower($order) ) ? 'DESC' : 'ASC';
 239  
 240          $terms = array_map('intval', $terms);
 241  
 242          $taxonomies = "'" . implode("', '", $taxonomies) . "'";
 243          $terms = "'" . implode("', '", $terms) . "'";
 244  
 245          $object_ids = $this->db->get_col("SELECT tr.object_id FROM {$this->db->term_relationships} AS tr INNER JOIN {$this->db->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND $field IN ($terms) ORDER BY tr.object_id $order");
 246  
 247          if ( ! $object_ids )
 248              return array();
 249  
 250          return $object_ids;
 251      }
 252  
 253      /**
 254       * Get all Term data from database by Term ID.
 255       *
 256       * The usage of the get_term function is to apply filters to a term object. It
 257       * is possible to get a term object from the database before applying the
 258       * filters.
 259       *
 260       * $term ID must be part of $taxonomy, to get from the database. Failure, might
 261       * be able to be captured by the hooks. Failure would be the same value as $this->db
 262       * returns for the get_row method.
 263       *
 264       * There are two hooks, one is specifically for each term, named 'get_term', and
 265       * the second is for the taxonomy name, 'term_$taxonomy'. Both hooks gets the
 266       * term object, and the taxonomy name as parameters. Both hooks are expected to
 267       * return a Term object.
 268       *
 269       * 'get_term' hook - Takes two parameters the term Object and the taxonomy name.
 270       * Must return term object. Used in get_term() as a catch-all filter for every
 271       * $term.
 272       *
 273       * 'get_$taxonomy' hook - Takes two parameters the term Object and the taxonomy
 274       * name. Must return term object. $taxonomy will be the taxonomy name, so for
 275       * example, if 'category', it would be 'get_category' as the filter name. Useful
 276       * for custom taxonomies or plugging into default taxonomies.
 277       *
 278       * @package WordPress
 279       * @subpackage Taxonomy
 280       * @since 2.3.0
 281       *
 282       * @uses $this->sanitize_term() Cleanses the term based on $filter context before returning.
 283       * @see $this->sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
 284       *
 285       * @param int|object $term If integer, will get from database. If object will apply filters and return $term.
 286       * @param string $taxonomy Taxonomy name that $term is part of.
 287       * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
 288       * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
 289       * @return mixed|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
 290       * exist then WP_Error will be returned.
 291       */
 292      function &get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') {
 293          if ( empty($term) ) {
 294              $error = new WP_Error('invalid_term', __('Empty Term'));
 295              return $error;
 296          }
 297  
 298          if ( !$this->is_taxonomy($taxonomy) ) {
 299              $error = new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
 300              return $error;
 301          }
 302  
 303          if ( is_object($term) ) {
 304              wp_cache_add($term->term_id, $term, $taxonomy);
 305              wp_cache_add($term->term_taxonomy_id, $term->term_id, "$taxonomy:tt_id" );
 306              $_term = $term;
 307          } else {
 308              $term = (int) $term;
 309              if ( ! $_term = wp_cache_get($term, $taxonomy) ) {
 310                  $_term = $this->db->get_row( $this->db->prepare( "SELECT t.*, tt.* FROM {$this->db->terms} AS t INNER JOIN {$this->db->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND t.term_id = %s LIMIT 1", $taxonomy, $term) );
 311                  wp_cache_add($term, $_term, $taxonomy);
 312                  wp_cache_add($_term->term_taxonomy_id, $_term->term_id, "$taxonomy:tt_id" );
 313              }
 314          }
 315  
 316          $_term = apply_filters('get_term', $_term, $taxonomy);
 317          $_term = apply_filters("get_$taxonomy", $_term, $taxonomy);
 318          $_term = $this->sanitize_term($_term, $taxonomy, $filter);
 319  
 320          backpress_convert_object( $_term, $output );
 321  
 322          return $_term;
 323      }
 324  
 325      /**
 326       * Get all Term data from database by Term field and data.
 327       *
 328       * Warning: $value is not escaped for 'name' $field. You must do it yourself, if
 329       * required.
 330       *
 331       * The default $field is 'id', therefore it is possible to also use null for
 332       * field, but not recommended that you do so.
 333       *
 334       * If $value does not exist, the return value will be false. If $taxonomy exists
 335       * and $field and $value combinations exist, the Term will be returned.
 336       *
 337       * @package WordPress
 338       * @subpackage Taxonomy
 339       * @since 2.3.0
 340       *
 341       * @uses $this->sanitize_term() Cleanses the term based on $filter context before returning.
 342       * @see $this->sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
 343       *
 344       * @param string $field Either 'slug', 'name', 'id', or 'tt_id'
 345       * @param string|int $value Search for this term value
 346       * @param string $taxonomy Taxonomy Name
 347       * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
 348       * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
 349       * @return mixed Term Row from database. Will return false if $taxonomy does not exist or $term was not found.
 350       */
 351  	function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') {
 352          if ( !$this->is_taxonomy($taxonomy) )
 353              return false;
 354  
 355          if ( 'slug' == $field ) {
 356              $field = 't.slug';
 357              $value = $this->sanitize_term_slug($value, $taxonomy);
 358              if ( empty($value) )
 359                  return false;
 360          } else if ( 'name' == $field ) {
 361              // Assume already escaped
 362              $field = 't.name';
 363          } else if ( 'tt_id' == $field ) {
 364              $field = 'tt.term_taxonomy_id';
 365              $value = (int) $value;
 366              if ( $_term_id = wp_cache_get( $value, "$taxonomy:tt_id" ) )
 367                  return $this->get_term( $_term_id, $taxonomy, $output, $filter );
 368          } else {
 369              $field = 't.term_id';
 370              $value = (int) $value;
 371          }
 372  
 373          $term = $this->db->get_row( $this->db->prepare( "SELECT t.*, tt.* FROM {$this->db->terms} AS t INNER JOIN {$this->db->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value) );
 374          if ( !$term )
 375              return false;
 376  
 377          wp_cache_add($term->term_id, $term, $taxonomy);
 378          wp_cache_add($term->term_taxonomy_id, $term->term_id, "$taxonomy:tt_id" );
 379  
 380          $term = $this->sanitize_term($term, $taxonomy, $filter);
 381  
 382          backpress_convert_object( $term, $output );
 383  
 384          return $term;
 385      }
 386  
 387      /**
 388       * Merge all term children into a single array of their IDs.
 389       *
 390       * This recursive function will merge all of the children of $term into the same
 391       * array of term IDs. Only useful for taxonomies which are hierarchical.
 392       *
 393       * Will return an empty array if $term does not exist in $taxonomy.
 394       * 
 395       * @package WordPress
 396       * @subpackage Taxonomy
 397       * @since 2.3.0
 398       *
 399       * @uses $this->_get_term_hierarchy()
 400       * @uses $this->get_term_children() Used to get the children of both $taxonomy and the parent $term
 401       *
 402       * @param string $term ID of Term to get children
 403       * @param string $taxonomy Taxonomy Name
 404       * @return array|WP_Error List of Term Objects. WP_Error returned if $taxonomy does not exist
 405       */
 406  	function get_term_children( $term_id, $taxonomy ) {
 407          if ( !$this->is_taxonomy($taxonomy) )
 408              return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
 409  
 410          $term_id = intval( $term_id );
 411  
 412          $terms = $this->_get_term_hierarchy($taxonomy);
 413  
 414          if ( ! isset($terms[$term_id]) )
 415              return array();
 416  
 417          $children = $terms[$term_id];
 418  
 419          foreach ( (array) $terms[$term_id] as $child ) {
 420              if ( isset($terms[$child]) )
 421                  $children = array_merge($children, $this->get_term_children($child, $taxonomy));
 422          }
 423  
 424          return $children;
 425      }
 426  
 427      /**
 428       * Get sanitized Term field.
 429       *
 430       * Does checks for $term, based on the $taxonomy. The function is for contextual
 431       * reasons and for simplicity of usage. See sanitize_term_field() for more
 432       * information.
 433       *
 434       * @package WordPress
 435       * @subpackage Taxonomy
 436       * @since 2.3.0
 437       *
 438       * @uses $this->sanitize_term_field() Passes the return value in sanitize_term_field on success.
 439       *
 440       * @param string $field Term field to fetch
 441       * @param int $term Term ID
 442       * @param string $taxonomy Taxonomy Name
 443       * @param string $context Optional, default is display. Look at sanitize_term_field() for available options.
 444       * @return mixed Will return an empty string if $term is not an object or if $field is not set in $term.
 445       */
 446  	function get_term_field( $field, $term, $taxonomy, $context = 'display' ) {
 447          $term = (int) $term;
 448          $term = $this->get_term( $term, $taxonomy );
 449          if ( is_wp_error($term) )
 450              return $term;
 451  
 452          if ( !is_object($term) )
 453              return '';
 454  
 455          if ( !isset($term->$field) )
 456              return '';
 457  
 458          return $this->sanitize_term_field($field, $term->$field, $term->term_id, $taxonomy, $context);
 459      }
 460  
 461      /**
 462       * Sanitizes Term for editing.
 463       *
 464       * Return value is sanitize_term() and usage is for sanitizing the term for
 465       * editing. Function is for contextual and simplicity.
 466       * 
 467       * @package WordPress
 468       * @subpackage Taxonomy
 469       * @since 2.3.0
 470       *
 471       * @uses $this->sanitize_term() Passes the return value on success
 472       *
 473       * @param int|object $id Term ID or Object
 474       * @param string $taxonomy Taxonomy Name
 475       * @return mixed|null|WP_Error Will return empty string if $term is not an object.
 476       */
 477  	function get_term_to_edit( $id, $taxonomy ) {
 478          $term = $this->get_term( $id, $taxonomy );
 479  
 480          if ( is_wp_error($term) )
 481              return $term;
 482  
 483          if ( !is_object($term) )
 484              return '';
 485  
 486          return $this->sanitize_term($term, $taxonomy, 'edit');
 487      }
 488  
 489      /**
 490       * Retrieve the terms in a given taxonomy or list of taxonomies.
 491       *
 492       * You can fully inject any customizations to the query before it is sent, as
 493       * well as control the output with a filter.
 494       *
 495       * The 'get_terms' filter will be called when the cache has the term and will
 496       * pass the found term along with the array of $taxonomies and array of $args.
 497       * This filter is also called before the array of terms is passed and will pass
 498       * the array of terms, along with the $taxonomies and $args.
 499       *
 500       * The 'list_terms_exclusions' filter passes the compiled exclusions along with
 501       * the $args.
 502       *
 503       * The 'get_terms_orderby' filter passes the ORDER BY clause for the query
 504       * along with the $args array.
 505       *
 506       * The 'get_terms_fields' filter passes the fields for the SELECT query
 507       * along with the $args array.
 508       *
 509       * The list of arguments that $args can contain, which will overwrite the defaults:
 510       *
 511       * orderby - Default is 'name'. Can be name, count, term_group, slug or nothing
 512       * (will use term_id), Passing a custom value other than these will cause it to
 513       * order based on the custom value.
 514       *
 515       * order - Default is ASC. Can use DESC.
 516       *
 517       * hide_empty - Default is true. Will not return empty terms, which means
 518       * terms whose count is 0 according to the given taxonomy.
 519       *
 520       * exclude - Default is an empty string.  A comma- or space-delimited string
 521       * of term ids to exclude from the return array.  If 'include' is non-empty,
 522       * 'exclude' is ignored.
 523       *
 524       * include - Default is an empty string.  A comma- or space-delimited string
 525       * of term ids to include in the return array.
 526       *
 527       * number - The maximum number of terms to return.  Default is empty.
 528       *
 529       * offset - The number by which to offset the terms query.
 530       *
 531       * fields - Default is 'all', which returns an array of term objects.
 532       * If 'fields' is 'ids' or 'names', returns an array of
 533       * integers or strings, respectively.
 534       *
 535       * slug - Returns terms whose "slug" matches this value. Default is empty string.
 536       *
 537       * hierarchical - Whether to include terms that have non-empty descendants
 538       * (even if 'hide_empty' is set to true).
 539       *
 540       * search - Returned terms' names will contain the value of 'search',
 541       * case-insensitive.  Default is an empty string.
 542       *
 543       * name__like - Returned terms' names will begin with the value of 'name__like',
 544       * case-insensitive. Default is empty string.
 545       *
 546       * The argument 'pad_counts', if set to true will include the quantity of a term's
 547       * children in the quantity of each term's "count" object variable.
 548       *
 549       * The 'get' argument, if set to 'all' instead of its default empty string,
 550       * returns terms regardless of ancestry or whether the terms are empty.
 551       *
 552       * The 'child_of' argument, when used, should be set to the integer of a term ID.  Its default
 553       * is 0.  If set to a non-zero value, all returned terms will be descendants
 554       * of that term according to the given taxonomy.  Hence 'child_of' is set to 0
 555       * if more than one taxonomy is passed in $taxonomies, because multiple taxonomies
 556       * make term ancestry ambiguous.
 557       *
 558       * The 'parent' argument, when used, should be set to the integer of a term ID.  Its default is
 559       * the empty string '', which has a different meaning from the integer 0.
 560       * If set to an integer value, all returned terms will have as an immediate
 561       * ancestor the term whose ID is specified by that integer according to the given taxonomy.
 562       * The 'parent' argument is different from 'child_of' in that a term X is considered a 'parent'
 563       * of term Y only if term X is the father of term Y, not its grandfather or great-grandfather, etc.
 564       *
 565       * @package WordPress
 566       * @subpackage Taxonomy
 567       * @since 2.3.0
 568       *
 569       * @uses wp_parse_args() Merges the defaults with those defined by $args and allows for strings.
 570       *
 571       * @param string|array Taxonomy name or list of Taxonomy names
 572       * @param string|array $args The values of what to search for when returning terms
 573       * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies do not exist.
 574       */
 575      function &get_terms($taxonomies, $args = '') {
 576          $empty_array = array();
 577  
 578          $single_taxonomy = false;
 579          if ( !is_array($taxonomies) ) {
 580              $single_taxonomy = true;
 581              $taxonomies = array($taxonomies);
 582          }
 583  
 584          foreach ( (array) $taxonomies as $taxonomy ) {
 585              if ( ! $this->is_taxonomy($taxonomy) ) {
 586                  $error = new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
 587                  return $error;
 588              }
 589          }
 590  
 591          $in_taxonomies = "'" . implode("', '", $taxonomies) . "'";
 592  
 593          $defaults = array('orderby' => 'name', 'order' => 'ASC',
 594              'hide_empty' => true, 'exclude' => '', 'exclude_tree' => '', 'include' => '',
 595              'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '',
 596              'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '',
 597              'pad_counts' => false, 'offset' => '', 'search' => '');
 598          $args = wp_parse_args( $args, $defaults );
 599          $args['number'] = absint( $args['number'] );
 600          $args['offset'] = absint( $args['offset'] );
 601          if ( !$single_taxonomy || !$this->is_taxonomy_hierarchical($taxonomies[0]) ||
 602              '' !== $args['parent'] ) {
 603              $args['child_of'] = 0;
 604              $args['hierarchical'] = false;
 605              $args['pad_counts'] = false;
 606          }
 607  
 608          if ( 'all' == $args['get'] ) {
 609              $args['child_of'] = 0;
 610              $args['hide_empty'] = 0;
 611              $args['hierarchical'] = false;
 612              $args['pad_counts'] = false;
 613          }
 614          extract($args, EXTR_SKIP);
 615  
 616          if ( $child_of ) {
 617              $hierarchy = $this->_get_term_hierarchy($taxonomies[0]);
 618              if ( !isset($hierarchy[$child_of]) )
 619                  return $empty_array;
 620          }
 621  
 622          if ( $parent ) {
 623              $hierarchy = $this->_get_term_hierarchy($taxonomies[0]);
 624              if ( !isset($hierarchy[$parent]) )
 625                  return $empty_array;
 626          }
 627  
 628          // $args can be whatever, only use the args defined in defaults to compute the key
 629          $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
 630          $key = md5( serialize( compact(array_keys($defaults)) ) . serialize( $taxonomies ) . $filter_key );
 631          $last_changed = wp_cache_get('last_changed', 'terms');
 632          if ( !$last_changed ) {
 633              $last_changed = time();
 634              wp_cache_set('last_changed', $last_changed, 'terms');
 635          }
 636          $cache_key = "get_terms:$key:$last_changed";
 637          $cache = wp_cache_get( $cache_key, 'terms' );
 638          if ( false !== $cache ) {
 639              $cache = apply_filters('get_terms', $cache, $taxonomies, $args);
 640              return $cache;
 641          }
 642  
 643          $_orderby = strtolower($orderby);
 644          if ( 'count' == $_orderby )
 645              $orderby = 'tt.count';
 646          else if ( 'name' == $_orderby )
 647              $orderby = 't.name';
 648          else if ( 'slug' == $_orderby )
 649              $orderby = 't.slug';
 650          else if ( 'term_group' == $_orderby )
 651              $orderby = 't.term_group';
 652          elseif ( empty($_orderby) || 'id' == $_orderby )
 653              $orderby = 't.term_id';
 654  
 655          $orderby = apply_filters( 'get_terms_orderby', $orderby, $args );
 656  
 657          $where = '';
 658          $inclusions = '';
 659          if ( !empty($include) ) {
 660              $exclude = '';
 661              $exclude_tree = '';
 662              $interms = preg_split('/[\s,]+/',$include);
 663              if ( count($interms) ) {
 664                  foreach ( (array) $interms as $interm ) {
 665                      if (empty($inclusions))
 666                          $inclusions = ' AND ( t.term_id = ' . intval($interm) . ' ';
 667                      else
 668                          $inclusions .= ' OR t.term_id = ' . intval($interm) . ' ';
 669                  }
 670              }
 671          }
 672  
 673          if ( !empty($inclusions) )
 674              $inclusions .= ')';
 675          $where .= $inclusions;
 676  
 677          $exclusions = '';
 678          if ( ! empty( $exclude_tree ) ) {
 679              $excluded_trunks = preg_split('/[\s,]+/',$exclude_tree);
 680              foreach( (array) $excluded_trunks as $extrunk ) {
 681                  $excluded_children = (array) $this->get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids'));
 682                  $excluded_children[] = $extrunk;
 683                  foreach( (array) $excluded_children as $exterm ) {
 684                      if ( empty($exclusions) )
 685                          $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
 686                      else
 687                          $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
 688  
 689                  }
 690              }
 691          }
 692          if ( !empty($exclude) ) {
 693              $exterms = preg_split('/[\s,]+/',$exclude);
 694              if ( count($exterms) ) {
 695                  foreach ( (array) $exterms as $exterm ) {
 696                      if ( empty($exclusions) )
 697                          $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
 698                      else
 699                          $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
 700                  }
 701              }
 702          }
 703  
 704          if ( !empty($exclusions) )
 705              $exclusions .= ')';
 706          $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args );
 707          $where .= $exclusions;
 708  
 709          if ( !empty($slug) ) {
 710              $slug =  $this->sanitize_term_slug($slug);
 711              $where .= " AND t.slug = '$slug'";
 712          }
 713  
 714          if ( !empty($name__like) )
 715              $where .= " AND t.name LIKE '{$name__like}%'";
 716  
 717          if ( '' !== $parent ) {
 718              $parent = (int) $parent;
 719              $where .= " AND tt.parent = '$parent'";
 720          }
 721  
 722          if ( $hide_empty && !$hierarchical )
 723              $where .= ' AND tt.count > 0';
 724  
 725          // don't limit the query results when we have to descend the family tree
 726          if ( ! empty($number) && ! $hierarchical && empty( $child_of ) && '' === $parent ) {
 727              if( $offset )
 728                  $limit = 'LIMIT ' . $offset . ',' . $number;
 729              else
 730                  $limit = 'LIMIT ' . $number;
 731  
 732          } else
 733              $limit = '';
 734  
 735          if ( !empty($search) ) {
 736              $search = like_escape($search);
 737              $where .= " AND (t.name LIKE '%$search%')";
 738          }
 739  
 740          if ( !in_array( $fields, array( 'all', 'ids', 'names', 'tt_ids' ) ) )
 741              $fields = 'all';
 742  
 743          $selects = array();
 744          if ( 'all' == $fields )
 745              $selects = array('t.*', 'tt.*');
 746          else if ( 'ids' == $fields )
 747              $selects = array('t.term_id', 'tt.parent', 'tt.count');
 748          else if ( 'names' == $fields )
 749              $selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name');
 750              $select_this = implode(', ', apply_filters( 'get_terms_fields', $selects, $args ));
 751  
 752          $query = "SELECT $select_this FROM {$this->db->terms} AS t INNER JOIN {$this->db->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy IN ($in_taxonomies) $where ORDER BY $orderby $order $limit";
 753  
 754          $terms = $this->db->get_results($query);
 755          if ( 'all' == $fields ) {
 756              $this->update_term_cache($terms);
 757          }
 758  
 759          if ( empty($terms) ) {
 760              wp_cache_add( $cache_key, array(), 'terms' );
 761              $terms = apply_filters('get_terms', array(), $taxonomies, $args);
 762              return $terms;
 763          }
 764  
 765          if ( $child_of || $hierarchical ) {
 766              $children = $this->_get_term_hierarchy($taxonomies[0]);
 767              if ( ! empty($children) )
 768                  $terms = & $this->_get_term_children($child_of, $terms, $taxonomies[0]);
 769          }
 770  
 771          // Update term counts to include children.
 772          if ( $pad_counts )
 773              $this->_pad_term_counts($terms, $taxonomies[0]);
 774  
 775          // Make sure we show empty categories that have children.
 776          if ( $hierarchical && $hide_empty && is_array($terms) ) {
 777              foreach ( $terms as $k => $term ) {
 778                  if ( ! $term->count ) {
 779                      $children = $this->_get_term_children($term->term_id, $terms, $taxonomies[0]);
 780                      if( is_array($children) )
 781                          foreach ( $children as $child )
 782                              if ( $child->count )
 783                                  continue 2;
 784  
 785                      // It really is empty
 786                      unset($terms[$k]);
 787                  }
 788              }
 789          }
 790          reset ( $terms );
 791  
 792          $_terms = array();
 793          if ( 'ids' == $fields ) {
 794              while ( $term = array_shift($terms) )
 795                  $_terms[] = $term->term_id;
 796              $terms = $_terms;
 797          } elseif ( 'names' == $fields ) {
 798              while ( $term = array_shift($terms) )
 799                  $_terms[] = $term->name;
 800              $terms = $_terms;
 801          }
 802  
 803          if ( 0 < $number && intval(@count($terms)) > $number ) {
 804              $terms = array_slice($terms, $offset, $number);
 805          }
 806  
 807          wp_cache_add( $cache_key, $terms, 'terms' );
 808  
 809          $terms = apply_filters('get_terms', $terms, $taxonomies, $args);
 810          return $terms;
 811      }
 812  
 813      /**
 814       * Check if Term exists.
 815       *
 816       * Returns the index of a defined term, or 0 (false) if the term doesn't exist.
 817       *
 818       * @package WordPress
 819       * @subpackage Taxonomy
 820       * @since 2.3.0
 821       *
 822       * @param int|string $term The term to check
 823       * @param string $taxonomy The taxonomy name to use
 824       * @param int $parent ID of parent term under which to confine the exists search.
 825       * @return mixed Get the term id or Term Object, if exists.
 826       */
 827  	function is_term($term, $taxonomy = '', $parent = 0) {
 828          $select = "SELECT term_id FROM {$this->db->terms} as t WHERE ";
 829          $tax_select = "SELECT tt.term_id, tt.term_taxonomy_id FROM {$this->db->terms} AS t INNER JOIN {$this->db->term_taxonomy} as tt ON tt.term_id = t.term_id WHERE ";
 830          
 831          if ( is_int($term) ) {
 832              if ( 0 == $term )
 833                  return 0;
 834              $where = 't.term_id = %d';
 835              if ( !empty($taxonomy) )
 836                  return $this->db->get_row( $this->db->prepare( $tax_select . $where . " AND tt.taxonomy = %s", $term, $taxonomy ), ARRAY_A );
 837              else
 838                  return $this->db->get_var( $this->db->prepare( $select . $where, $term ) );
 839          }
 840  
 841          $term = trim( stripslashes( $term ) );
 842  
 843          if ( '' === $slug = $this->sanitize_term_slug($term) )
 844              return 0;
 845  
 846          $where = 't.slug = %s';
 847          $else_where = 't.name = %s';
 848          $where_fields = array($slug);
 849          $else_where_fields = array($term);
 850          if ( !empty($taxonomy) ) {
 851              $parent = (int) $parent;
 852              if ( $parent > 0 ) {
 853                  $where_fields[] = $parent;
 854                  $else_where_fields[] = $parent;
 855                  $where .= ' AND tt.parent = %d';
 856                  $else_where .= ' AND tt.parent = %d';
 857              }
 858  
 859              $where_fields[] = $taxonomy;
 860              $else_where_fields[] = $taxonomy;
 861  
 862              if ( $result = $this->db->get_row( $this->db->prepare("SELECT tt.term_id, tt.term_taxonomy_id FROM {$this->db->terms} AS t INNER JOIN {$this->db->term_taxonomy} as tt ON tt.term_id = t.term_id WHERE $where AND tt.taxonomy = %s", $where_fields), ARRAY_A) )
 863                  return $result;
 864  
 865              return $this->db->get_row( $this->db->prepare("SELECT tt.term_id, tt.term_taxonomy_id FROM {$this->db->terms} AS t INNER JOIN {$this->db->term_taxonomy} as tt ON tt.term_id = t.term_id WHERE $else_where AND tt.taxonomy = %s", $else_where_fields), ARRAY_A);
 866          }
 867  
 868          if ( $result = $this->db->get_var( $this->db->prepare("SELECT term_id FROM {$this->db->terms} as t WHERE $where", $where_fields) ) )
 869              return $result;
 870  
 871          return $this->db->get_var( $this->db->prepare("SELECT term_id FROM {$this->db->terms} as t WHERE $else_where", $else_where_fields) );
 872      }
 873  
 874  	function sanitize_term_slug( $title, $taxonomy = '', $term_id = 0 ) {
 875          return apply_filters( 'pre_term_slug', $title, $taxonomy, $term_id );
 876      }
 877  
 878  	function format_to_edit( $text ) {
 879          return format_to_edit( $text );
 880      }
 881  
 882      /**
 883       * Sanitize Term all fields
 884       *
 885       * Relies on sanitize_term_field() to sanitize the term. The difference
 886       * is that this function will sanitize <strong>all</strong> fields. The
 887       * context is based on sanitize_term_field().
 888       *
 889       * The $term is expected to be either an array or an object.
 890       *
 891       * @package WordPress
 892       * @subpackage Taxonomy
 893       * @since 2.3.0
 894       *
 895       * @uses $this->sanitize_term_field Used to sanitize all fields in a term
 896       *
 897       * @param array|object $term The term to check
 898       * @param string $taxonomy The taxonomy name to use
 899       * @param string $context Default is 'display'.
 900       * @return array|object Term with all fields sanitized
 901       */
 902  	function sanitize_term($term, $taxonomy, $context = 'display') {
 903  
 904          if ( 'raw' == $context )
 905              return $term;
 906  
 907          $fields = array('term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group');
 908  
 909          $do_object = false;
 910          if ( is_object($term) )
 911              $do_object = true;
 912  
 913          $term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0);
 914  
 915          foreach ( (array) $fields as $field ) {
 916              if ( $do_object ) {
 917                  if ( isset($term->$field) )
 918                      $term->$field = $this->sanitize_term_field($field, $term->$field, $term_id, $taxonomy, $context);
 919              } else {
 920                  if ( isset($term[$field]) )
 921                      $term[$field] = $this->sanitize_term_field($field, $term[$field], $term_id, $taxonomy, $context);
 922              }
 923          }
 924  
 925          if ( $do_object )
 926              $term->filter = $context;
 927          else
 928              $term['filter'] = $context;
 929  
 930          return $term;
 931      }
 932  
 933      /**
 934       * Cleanse the field value in the term based on the context.
 935       *
 936       * Passing a term field value through the function should be assumed to have
 937       * cleansed the value for whatever context the term field is going to be used.
 938       *
 939       * If no context or an unsupported context is given, then default filters will
 940       * be applied.
 941       *
 942       * There are enough filters for each context to support a custom filtering
 943       * without creating your own filter function. Simply create a function that
 944       * hooks into the filter you need.
 945       *
 946       * @package WordPress
 947       * @subpackage Taxonomy
 948       * @since 2.3.0
 949       *
 950       * @param string $field Term field to sanitize
 951       * @param string $value Search for this term value
 952       * @param int $term_id Term ID
 953       * @param string $taxonomy Taxonomy Name
 954       * @param string $context Either edit, db, display, attribute, or js.
 955       * @return mixed sanitized field
 956       */
 957  	function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) {
 958          if ( 'parent' == $field  || 'term_id' == $field || 'count' == $field || 'term_group' == $field ) {
 959              $value = (int) $value;
 960              if ( $value < 0 )
 961                  $value = 0;
 962          }
 963  
 964          if ( 'raw' == $context )
 965              return $value;
 966  
 967          if ( 'edit' == $context ) {
 968              $value = apply_filters("edit_term_$field", $value, $term_id, $taxonomy);
 969              $value = apply_filters("edit_$taxonomy}_$field", $value, $term_id);
 970              if ( 'description' == $field )
 971                  $value = $this->format_to_edit($value);
 972              else
 973                  $value = esc_attr($value);
 974          } else if ( 'db' == $context ) {
 975              $value = apply_filters("pre_term_$field", $value, $taxonomy);
 976              $value = apply_filters("pre_$taxonomy}_$field", $value);
 977              // WP DIFF
 978          } else if ( 'rss' == $context ) {
 979              $value = apply_filters("term_$field}_rss", $value, $taxonomy);
 980              $value = apply_filters("$taxonomy}_$field}_rss", $value);
 981          } else {
 982              // Use display filters by default.
 983              $value = apply_filters("term_$field", $value, $term_id, $taxonomy, $context);
 984              $value = apply_filters("$taxonomy}_$field", $value, $term_id, $context);
 985          }
 986  
 987          if ( 'attribute' == $context )
 988              $value = esc_attr($value);
 989          else if ( 'js' == $context )
 990              $value = esc_js($value);
 991  
 992          return $value;
 993      }
 994  
 995      /**
 996       * Count how many terms are in Taxonomy.
 997       *
 998       * Default $args is 'ignore_empty' which can be <code>'ignore_empty=true'</code>
 999       * or <code>array('ignore_empty' => true);</code>.
1000       *
1001       * @package WordPress
1002       * @subpackage Taxonomy
1003       * @since 2.3.0
1004       *
1005       * @uses wp_parse_args() Turns strings into arrays and merges defaults into an array.
1006       *
1007       * @param string $taxonomy Taxonomy name
1008       * @param array|string $args Overwrite defaults
1009       * @return int How many terms are in $taxonomy
1010       */
1011  	function count_terms( $taxonomy, $args = array() ) {
1012          $defaults = array('ignore_empty' => false);
1013          $args = wp_parse_args($args, $defaults);
1014          extract($args, EXTR_SKIP);
1015  
1016          $where = '';
1017          if ( $ignore_empty )
1018              $where = 'AND count > 0';
1019  
1020          return $this->db->get_var( $this->db->prepare( "SELECT COUNT(*) FROM {$this->db->term_taxonomy} WHERE taxonomy = %s $where", $taxonomy ) );
1021      }
1022  
1023      /**
1024       * Will unlink the term from the taxonomy.
1025       *
1026       * Will remove the term's relationship to the taxonomy, not the term or taxonomy
1027       * itself. The term and taxonomy will still exist. Will require the term's
1028       * object ID to perform the operation.
1029       *
1030       * @package WordPress
1031       * @subpackage Taxonomy
1032       * @since 2.3.0
1033       *
1034       * @param int $object_id The term Object Id that refers to the term
1035       * @param string|array $taxonomy List of Taxonomy Names or single Taxonomy name.
1036       */
1037  	function delete_object_term_relationships( $object_id, $taxonomies ) {
1038          $object_id = (int) $object_id;
1039  
1040          if ( !is_array($taxonomies) )
1041              $taxonomies = array($taxonomies);
1042  
1043          foreach ( (array) $taxonomies as $taxonomy ) {
1044              $terms = $this->get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids'));
1045              $in_terms = "'" . implode("', '", $terms) . "'";
1046              $this->db->query( $this->db->prepare( "DELETE FROM {$this->db->term_relationships} WHERE object_id = %d AND term_taxonomy_id IN ($in_terms)", $object_id ) );
1047              $this->update_term_count($terms, $taxonomy);
1048          }
1049      }
1050  
1051      /**
1052       * Removes a term from the database.
1053       *
1054       * If the term is a parent of other terms, then the children will be updated to
1055       * that term's parent.
1056       *
1057       * The $args 'default' will only override the terms found, if there is only one
1058       * term found. Any other and the found terms are used.
1059       *
1060       * The $args 'force_default' will force the term supplied as default to be
1061       * assigned even if the object was not going to be termless
1062       * @package WordPress
1063       * @subpackage Taxonomy
1064       * @since 2.3.0
1065       *
1066       * @uses do_action() Calls both 'delete_term' and 'delete_$taxonomy' action
1067       *  hooks, passing term object, term id. 'delete_term' gets an additional
1068       *  parameter with the $taxonomy parameter.
1069       *
1070       * @param int $term Term ID
1071       * @param string $taxonomy Taxonomy Name
1072       * @param array|string $args Optional. Change 'default' term id and override found term ids.
1073       * @return bool|WP_Error Returns false if not term; true if completes delete action.
1074       */
1075  	function delete_term( $term, $taxonomy, $args = array() ) {
1076          $term = (int) $term;
1077  
1078          if ( ! $ids = $this->is_term($term, $taxonomy) )
1079              return false;
1080          if ( is_wp_error( $ids ) )
1081              return $ids;
1082  
1083          $tt_id = $ids['term_taxonomy_id'];
1084  
1085          $defaults = array();
1086          $args = wp_parse_args($args, $defaults);
1087          extract($args, EXTR_SKIP);
1088  
1089          if ( isset($default) ) {
1090              $default = (int) $default;
1091              if ( !$this->is_term($default, $taxonomy) )
1092                  unset($default);
1093          }
1094  
1095          // Update children to point to new parent
1096          if ( $this->is_taxonomy_hierarchical($taxonomy) ) {
1097              $term_obj = $this->get_term($term, $taxonomy);
1098              if ( is_wp_error( $term_obj ) )
1099                  return $term_obj;
1100              $parent = $term_obj->parent;
1101  
1102              $this->db->update( $this->db->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id ) + compact( 'taxonomy' ) );
1103          }
1104  
1105          $objects = $this->db->get_col( $this->db->prepare( "SELECT object_id FROM {$this->db->term_relationships} WHERE term_taxonomy_id = %d", $tt_id ) );
1106  
1107          foreach ( (array) $objects as $object ) {
1108              $terms = $this->get_object_terms($object, $taxonomy, array('fields' => 'ids', 'orderby' => 'none'));
1109              if ( 1 == count($terms) && isset($default) ) {
1110                  $terms = array($default);
1111              } else {
1112                  $terms = array_diff($terms, array($term));
1113                  if (isset($default) && isset($force_default) && $force_default)
1114                      $terms = array_merge($terms, array($default));
1115              }
1116              $terms = array_map('intval', $terms);
1117              $this->set_object_terms($object, $terms, $taxonomy);
1118          }
1119  
1120          $this->db->query( $this->db->prepare( "DELETE FROM {$this->db->term_taxonomy} WHERE term_taxonomy_id = %d", $tt_id ) );
1121  
1122          // Delete the term if no taxonomies use it.
1123          if ( !$this->db->get_var( $this->db->prepare( "SELECT COUNT(*) FROM {$this->db->term_taxonomy} WHERE term_id = %d", $term) ) )
1124              $this->db->query( $this->db->prepare( "DELETE FROM {$this->db->terms} WHERE term_id = %d", $term) );
1125  
1126          $this->clean_term_cache($term, $taxonomy);
1127  
1128          do_action('delete_term', $term, $tt_id, $taxonomy);
1129          do_action("delete_$taxonomy", $term, $tt_id);
1130  
1131          return true;
1132      }
1133  
1134      /**
1135       * Retrieves the terms associated with the given object(s), in the supplied taxonomies.
1136       *
1137       * The following information has to do the $args parameter and for what can be
1138       * contained in the string or array of that parameter, if it exists.
1139       *
1140       * The first argument is called, 'orderby' and has the default value of 'name'.
1141       * The other value that is supported is 'count'.
1142       *
1143       * The second argument is called, 'order' and has the default value of 'ASC'.
1144       * The only other value that will be acceptable is 'DESC'.
1145       *
1146       * The final argument supported is called, 'fields' and has the default value of
1147       * 'all'. There are multiple other options that can be used instead. Supported
1148       * values are as follows: 'all', 'ids', 'names', and finally
1149       * 'all_with_object_id'.
1150       *
1151       * The fields argument also decides what will be returned. If 'all' or
1152       * 'all_with_object_id' is choosen or the default kept intact, then all matching
1153       * terms objects will be returned. If either 'ids' or 'names' is used, then an
1154       * array of all matching term ids or term names will be returned respectively.
1155       *
1156       * @package WordPress
1157       * @subpackage Taxonomy
1158       * @since 2.3.0
1159       *
1160       * @param int|array $object_id The id of the object(s) to retrieve.
1161       * @param string|array $taxonomies The taxonomies to retrieve terms from.
1162       * @param array|string $args Change what is returned
1163       * @return array|WP_Error The requested term data or empty array if no terms found. WP_Error if $taxonomy does not exist.
1164       */
1165  	function get_object_terms($object_ids, $taxonomies, $args = array()) {
1166          if ( !is_array($taxonomies) )
1167              $taxonomies = array($taxonomies);
1168  
1169          foreach ( (array) $taxonomies as $taxonomy ) {
1170              if ( !$this->is_taxonomy($taxonomy) )
1171                  return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
1172          }
1173  
1174          if ( !is_array($object_ids) )
1175              $object_ids = array($object_ids);
1176          $object_ids = array_map('intval', $object_ids);
1177  
1178          $defaults = array('orderby' => 'name', 'order' => 'ASC', 'fields' => 'all');
1179          $args = wp_parse_args( $args, $defaults );
1180  
1181          $terms = array();
1182          if ( count($taxonomies) > 1 ) {
1183              foreach ( $taxonomies as $index => $taxonomy ) {
1184                  $t = $this->get_taxonomy($taxonomy);
1185                  if ( isset($t->args) && is_array($t->args) && $args != array_merge($args, $t->args) ) {
1186                      unset($taxonomies[$index]);
1187                      $terms = array_merge($terms, $this->get_object_terms($object_ids, $taxonomy, array_merge($args, $t->args)));
1188                  }
1189              }
1190          } else {
1191              $t = $this->get_taxonomy($taxonomies[0]);
1192              if ( isset($t->args) && is_array($t->args) )
1193                  $args = array_merge($args, $t->args);
1194          }
1195  
1196          extract($args, EXTR_SKIP);
1197  
1198          if ( 'count' == $orderby )
1199              $orderby = 'tt.count';
1200          else if ( 'name' == $orderby )
1201              $orderby = 't.name';
1202          else if ( 'slug' == $orderby )
1203              $orderby = 't.slug';
1204          else if ( 'term_group' == $orderby )
1205              $orderby = 't.term_group';
1206          else if ( 'term_order' == $orderby )
1207              $orderby = 'tr.term_order';
1208          else if ( 'none' == $orderby ) {
1209              $orderby = '';
1210              $order = '';
1211          } else {
1212              $orderby = 't.term_id';
1213          }
1214  
1215          // tt_ids queries can only be none or tr.term_taxonomy_id
1216          if ( ('tt_ids' == $fields) && !empty($orderby) )
1217              $orderby = 'tr.term_taxonomy_id';
1218  
1219          if ( !empty($orderby) )
1220              $orderby = "ORDER BY $orderby";
1221  
1222          $taxonomies = "'" . implode("', '", $taxonomies) . "'";
1223          $object_ids = implode(', ', $object_ids);
1224  
1225          $select_this = '';
1226          if ( 'all' == $fields )
1227              $select_this = 't.*, tt.*';
1228          else if ( 'ids' == $fields )
1229              $select_this = 't.term_id';
1230          else if ( 'names' == $fields )
1231              $select_this = 't.name';
1232          else if ( 'all_with_object_id' == $fields )
1233              $select_this = 't.*, tt.*, tr.object_id';
1234  
1235          $query = "SELECT $select_this FROM {$this->db->terms} AS t INNER JOIN {$this->db->term_taxonomy} AS tt ON tt.term_id = t.term_id INNER JOIN {$this->db->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";
1236  
1237          if ( 'all' == $fields || 'all_with_object_id' == $fields ) {
1238              $terms = array_merge($terms, $this->db->get_results($query));
1239              $this->update_term_cache($terms);
1240          } else if ( 'ids' == $fields || 'names' == $fields ) {
1241              $terms = array_merge($terms, $this->db->get_col($query));
1242          } else if ( 'tt_ids' == $fields ) {
1243              $terms = $this->db->get_col("SELECT tr.term_taxonomy_id FROM {$this->db->term_relationships} AS tr INNER JOIN {$this->db->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");
1244          }
1245  
1246          if ( ! $terms )
1247              $terms = array();
1248  
1249          return apply_filters('wp_get_object_terms', $terms, $object_ids, $taxonomies, $args);
1250      }
1251  
1252      /**
1253       * Adds a new term to the database. Optionally marks it as an alias of an existing term.
1254       *
1255       * Error handling is assigned for the nonexistance of the $taxonomy and $term
1256       * parameters before inserting. If both the term id and taxonomy exist
1257       * previously, then an array will be returned that contains the term id and the
1258       * contents of what is returned. The keys of the array are 'term_id' and
1259       * 'term_taxonomy_id' containing numeric values.
1260       *
1261       * It is assumed that the term does not yet exist or the above will apply. The
1262       * term will be first added to the term table and then related to the taxonomy
1263       * if everything is well. If everything is correct, then several actions will be
1264       * run prior to a filter and then several actions will be run after the filter
1265       * is run.
1266       *
1267       * The arguments decide how the term is handled based on the $args parameter.
1268       * The following is a list of the available overrides and the defaults.
1269       *
1270       * 'alias_of'. There is no default, but if added, expected is the slug that the
1271       * term will be an alias of. Expected to be a string.
1272       *
1273       * 'description'. There is no default. If exists, will be added to the database
1274       * along with the term. Expected to be a string.
1275       *
1276       * 'parent'. Expected to be numeric and default is 0 (zero). Will assign value
1277       * of 'parent' to the term.
1278       *
1279       * 'slug'. Expected to be a string. There is no default.
1280       *
1281       * If 'slug' argument exists then the slug will be checked to see if it is not
1282       * a valid term. If that check succeeds (it is not a valid term), then it is
1283       * added and the term id is given. If it fails, then a check is made to whether
1284       * the taxonomy is hierarchical and the parent argument is not empty. If the
1285       * second check succeeds, the term will be inserted and the term id will be
1286       * given.
1287       *
1288       * @package WordPress
1289       * @subpackage Taxonomy
1290       * @since 2.3.0
1291       *
1292       * @uses do_action() Calls 'create_term' hook with the term id and taxonomy id as parameters.
1293       * @uses do_action() Calls 'create_$taxonomy' hook with term id and taxonomy id as parameters.
1294       * @uses apply_filters() Calls 'term_id_filter' hook with term id and taxonomy id as parameters.
1295       * @uses do_action() Calls 'created_term' hook with the term id and taxonomy id as parameters.
1296       * @uses do_action() Calls 'created_$taxonomy' hook with term id and taxonomy id as parameters.
1297       *
1298       * @param int|string $term The term to add or update.
1299       * @param string $taxonomy The taxonomy to which to add the term
1300       * @param array|string $args Change the values of the inserted term
1301       * @return array|WP_Error The Term ID and Term Taxonomy ID
1302       */
1303  	function insert_term( $term, $taxonomy, $args = array() ) {
1304          if ( !$this->is_taxonomy($taxonomy) )
1305              return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
1306  
1307          if ( is_int($term) && 0 == $term )
1308              return new WP_Error('invalid_term_id', __('Invalid term ID'));
1309  
1310          if ( '' == trim($term) )
1311              return new WP_Error('empty_term_name', __('A name is required for this term'));
1312  
1313          $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
1314          $args = wp_parse_args($args, $defaults);
1315          $args['name'] = $term;
1316          $args['taxonomy'] = $taxonomy;
1317          $args = $this->sanitize_term($args, $taxonomy, 'db');
1318          extract($args, EXTR_SKIP);
1319  
1320          // expected_slashed ($name)
1321          $name = stripslashes($name);
1322          $description = stripslashes($description);
1323  
1324          if ( empty($slug) )
1325              $slug = $this->sanitize_term_slug($name, $taxonomy);
1326  
1327          $term_group = 0;
1328          if ( $alias_of ) {
1329              $alias = $this->db->get_row( $this->db->prepare( "SELECT term_id, term_group FROM {$this->db->terms} WHERE slug = %s", $alias_of) );
1330              if ( $alias->term_group ) {
1331                  // The alias we want is already in a group, so let's use that one.
1332                  $term_group = $alias->term_group;
1333              } else {
1334                  // The alias isn't in a group, so let's create a new one and firstly add the alias term to it.
1335                  $term_group = $this->db->get_var("SELECT MAX(term_group) FROM {$this->db->terms}") + 1;
1336                  $this->db->query( $this->db->prepare( "UPDATE {$this->db->terms} SET term_group = %d WHERE term_id = %d", $term_group, $alias->term_id ) );
1337              }
1338          }
1339  
1340          if ( ! $term_id = $this->is_term($slug) ) {
1341              if ( false === $this->db->insert( $this->db->terms, compact( 'name', 'slug', 'term_group' ) ) )
1342                  return new WP_Error('db_insert_error', __('Could not insert term into the database'), $this->db->last_error);
1343              $term_id = (int) $this->db->insert_id;
1344          } else if ( $this->is_taxonomy_hierarchical($taxonomy) && !empty($parent) ) {
1345              // If the taxonomy supports hierarchy and the term has a parent, make the slug unique
1346              // by incorporating parent slugs.
1347              $slug = $this->unique_term_slug($slug, (object) $args);
1348              if ( false === $this->db->insert( $this->db->terms, compact( 'name', 'slug', 'term_group' ) ) )
1349                  return new WP_Error('db_insert_error', __('Could not insert term into the database'), $this->db->last_error);
1350              $term_id = (int) $this->db->insert_id;
1351          }
1352  
1353          if ( empty($slug) ) {
1354              $slug = $this->sanitize_term_slug($slug, $taxonomy, $term_id);
1355              $this->db->update( $this->db->terms, compact( 'slug' ), compact( 'term_id' ) );
1356          }
1357  
1358          $tt_id = $this->db->get_var( $this->db->prepare( "SELECT tt.term_taxonomy_id FROM {$this->db->term_taxonomy} AS tt INNER JOIN {$this->db->terms} AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) );
1359  
1360          if ( !empty($tt_id) )
1361              return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
1362  
1363          $this->db->insert( $this->db->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) );
1364          $tt_id = (int) $this->db->insert_id;
1365  
1366          do_action("create_term", $term_id, $tt_id);
1367          do_action("create_$taxonomy", $term_id, $tt_id);
1368  
1369          $term_id = apply_filters('term_id_filter', $term_id, $tt_id);
1370  
1371          $this->clean_term_cache($term_id, $taxonomy);
1372  
1373          do_action("created_term", $term_id, $tt_id);
1374          do_action("created_$taxonomy", $term_id, $tt_id);
1375  
1376          return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
1377      }
1378  
1379      /**
1380       * Create Term and Taxonomy Relationships.
1381       *
1382       * Relates an object (post, link etc) to a term and taxonomy type. Creates the
1383       * term and taxonomy relationship if it doesn't already exist. Creates a term if
1384       * it doesn't exist (using the slug).
1385       *
1386       * A relationship means that the term is grouped in or belongs to the taxonomy.
1387       * A term has no meaning until it is given context by defining which taxonomy it
1388       * exists under.
1389       *
1390       * @package WordPress
1391       * @subpackage Taxonomy
1392       * @since 2.3.0
1393       *
1394       * @param int $object_id The object to relate to.
1395       * @param array|int|string $term The slug or id of the term, will replace all existing
1396       * related terms in this taxonomy.
1397       * @param array|string $taxonomy The context in which to relate the term to the object.
1398       * @param bool $append If false will delete difference of terms.
1399       * @return array|WP_Error Affected Term IDs
1400       */
1401  	function set_object_terms($object_id, $terms, $taxonomy, $append = false) {
1402          $object_id = (int) $object_id;
1403  
1404          if ( !$this->is_taxonomy($taxonomy) )
1405              return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy'));
1406  
1407          if ( !is_array($terms) )
1408              $terms = array($terms);
1409  
1410          if ( ! $append )
1411              $old_tt_ids = $this->get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids', 'orderby' => 'none'));
1412  
1413          $tt_ids = array();
1414          $term_ids = array();
1415  
1416          foreach ( (array) $terms as $term ) {
1417              if ( !strlen(trim($term)) )
1418                  continue;
1419  
1420              if ( !$id = $this->is_term($term, $taxonomy) )
1421                  $id = $this->insert_term($term, $taxonomy);
1422              if ( is_wp_error($id) )
1423                  return $id;
1424              $term_ids[] = $id['term_id'];
1425              $id = $id['term_taxonomy_id'];
1426              $tt_ids[] = $id;
1427  
1428              if ( $this->db->get_var( $this->db->prepare( "SELECT term_taxonomy_id FROM {$this->db->term_relationships} WHERE object_id = %d AND term_taxonomy_id = %d", $object_id, $id ) ) )
1429                  continue;
1430              $this->db->insert( $this->db->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $id ) );
1431          }
1432  
1433          $this->update_term_count($tt_ids, $taxonomy);
1434  
1435          if ( ! $append ) {
1436              $delete_terms = array_diff($old_tt_ids, $tt_ids);
1437              if ( $delete_terms ) {
1438                  $in_delete_terms = "'" . implode("', '", $delete_terms) . "'";
1439                  $this->db->query( $this->db->prepare("DELETE FROM {$this->db->term_relationships} WHERE object_id = %d AND term_taxonomy_id IN ($in_delete_terms)", $object_id) );
1440                  $this->update_term_count($delete_terms, $taxonomy);
1441              }
1442          }
1443  
1444          $t = $this->get_taxonomy($taxonomy);
1445          if ( ! $append && isset($t->sort) && $t->sort ) {
1446              $values = array();
1447              $term_order = 0;
1448              $final_tt_ids = $this->get_object_terms($object_id, $taxonomy, 'fields=tt_ids');
1449              foreach ( $tt_ids as $tt_id )
1450                  if ( in_array($tt_id, $final_tt_ids) )
1451                      $values[] = $this->db->prepare( "(%d, %d, %d)", $object_id, $tt_id, ++$term_order);
1452              if ( $values )
1453                  $this->db->query("INSERT INTO {$this->db->term_relationships} (object_id, term_taxonomy_id, term_order) VALUES " . join(',', $values) . " ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)");
1454          }
1455  
1456          do_action('set_object_terms', $object_id, $terms, $tt_ids, $taxonomy, $append);
1457          return $tt_ids;
1458      }
1459  
1460      /**
1461       * Will make slug unique, if it isn't already.
1462       *
1463       * The $slug has to be unique global to every taxonomy, meaning that one
1464       * taxonomy term can't have a matching slug with another taxonomy term. Each
1465       * slug has to be globally unique for every taxonomy.
1466       *
1467       * The way this works is that if the taxonomy that the term belongs to is
1468       * heirarchical and has a parent, it will append that parent to the $slug.
1469       *
1470       * If that still doesn't return an unique slug, then it try to append a number
1471       * until it finds a number that is truely unique.
1472       *
1473       * The only purpose for $term is for appending a parent, if one exists.
1474       *
1475       * @package WordPress
1476       * @subpackage Taxonomy
1477       * @since 2.3.0
1478       *
1479       * @param string $slug The string that will be tried for a unique slug
1480       * @param object $term The term object that the $slug will belong too
1481       * @return string Will return a true unique slug.
1482       */
1483  	function unique_term_slug($slug, $term) {
1484          // If the taxonomy supports hierarchy and the term has a parent, make the slug unique
1485          // by incorporating parent slugs.
1486          if ( $this->is_taxonomy_hierarchical($term->taxonomy) && !empty($term->parent) ) {
1487              $the_parent = $term->parent;
1488              while ( ! empty($the_parent) ) {
1489                  $parent_term = $this->get_term($the_parent, $term->taxonomy);
1490                  if ( is_wp_error($parent_term) || empty($parent_term) )
1491                      break;
1492                      $slug .= '-' . $parent_term->slug;
1493                  if ( empty($parent_term->parent) )
1494                      break;
1495                  $the_parent = $parent_term->parent;
1496              }
1497          }
1498  
1499          // If we didn't get a unique slug, try appending a number to make it unique.
1500          if ( !empty($args['term_id']) )
1501              $query = $this->db->prepare( "SELECT slug FROM {$this->db->terms} WHERE slug = %s AND term_id != %d", $slug, $args['term_id'] );
1502          else
1503              $query = $this->db->prepare( "SELECT slug FROM {$this->db->terms} WHERE slug = %s", $slug );
1504  
1505          if ( $this->db->get_var( $query ) ) {
1506              $num = 2;
1507              do {
1508                  $alt_slug = $slug . "-$num";
1509                  $num++;
1510                  $slug_check = $this->db->get_var( $this->db->prepare( "SELECT slug FROM {$this->db->terms} WHERE slug = %s", $alt_slug ) );
1511              } while ( $slug_check );
1512              $slug = $alt_slug;
1513          }
1514  
1515          return $slug;
1516      }
1517  
1518      /**
1519       * Update term based on arguments provided.
1520       *
1521       * The $args will indiscriminately override all values with the same field name.
1522       * Care must be taken to not override important information need to update or
1523       * update will fail (or perhaps create a new term, neither would be acceptable).
1524       *
1525       * Defaults will set 'alias_of', 'description', 'parent', and 'slug' if not
1526       * defined in $args already.
1527       *
1528       * 'alias_of' will create a term group, if it doesn't already exist, and update
1529       * it for the $term.
1530       *
1531       * If the 'slug' argument in $args is missing, then the 'name' in $args will be
1532       * used. It should also be noted that if you set 'slug' and it isn't unique then
1533       * a WP_Error will be passed back. If you don't pass any slug, then a unique one
1534       * will be created for you.
1535       *
1536       * For what can be overrode in $args, check the term scheme can contain and stay
1537       * away from the term keys.
1538       *
1539       * @package WordPress
1540       * @subpackage Taxonomy
1541       * @since 2.3.0
1542       *
1543       * @uses do_action() Will call both 'edit_term' and 'edit_$taxonomy' twice.
1544       * @uses apply_filters() Will call the 'term_id_filter' filter and pass the term
1545       *  id and taxonomy id.
1546       *
1547       * @param int $term_id The ID of the term
1548       * @param string $taxonomy The context in which to relate the term to the object.
1549       * @param array|string $args Overwrite term field values
1550       * @return array|WP_Error Returns Term ID and Taxonomy Term ID
1551       */
1552  	function update_term( $term_id, $taxonomy, $args = array() ) {
1553          if ( !$this->is_taxonomy($taxonomy) )
1554              return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
1555  
1556          $term_id = (int) $term_id;
1557  
1558          // First, get all of the original args
1559          $term = $this->get_term($term_id, $taxonomy, ARRAY_A);
1560  
1561          if ( is_wp_error( $term ) )
1562              return $term;
1563  
1564          // Merge old and new args with new args overwriting old ones.
1565          $args = array_merge($term, $args);
1566  
1567          $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
1568          $args = wp_parse_args($args, $defaults);
1569          $args = $this->sanitize_term($args, $taxonomy, 'db');
1570          extract($args, EXTR_SKIP);
1571  
1572          // expected_slashed ($name)
1573          $name = stripslashes($name);
1574          $description = stripslashes($description);
1575  
1576          if ( '' == trim($name) )
1577              return new WP_Error('empty_term_name', __('A name is required for this term'));
1578  
1579          $empty_slug = false;
1580          if ( empty($slug) ) {
1581              $empty_slug = true;
1582              $slug = $this->sanitize_term_slug($name, $taxonomy, $term_id);
1583          }
1584  
1585          if ( $alias_of ) {
1586              $alias = $this->db->get_row( $this->db->prepare( "SELECT term_id, term_group FROM {$this->db->terms} WHERE slug = %s", $alias_of) );
1587              if ( $alias->term_group ) {
1588                  // The alias we want is already in a group, so let's use that one.
1589                  $term_group = $alias->term_group;
1590              } else {
1591                  // The alias isn't in a group, so let's create a new one and firstly add the alias term to it.
1592                  $term_group = $this->db->get_var("SELECT MAX(term_group) FROM {$this->db->terms}") + 1;
1593                  $this->db->update( $this->db->terms, compact('term_group'), array( 'term_id' => $alias->term_id ) );
1594              }
1595          }
1596  
1597          // Check for duplicate slug
1598          $id = $this->db->get_var( $this->db->prepare( "SELECT term_id FROM {$this->db->terms} WHERE slug = %s", $slug ) );
1599          if ( $id && ($id != $term_id) ) {
1600              // If an empty slug was passed or the parent changed, reset the slug to something unique.
1601              // Otherwise, bail.
1602              if ( $empty_slug || ( $parent != $term->parent) )
1603                  $slug = $this->unique_term_slug($slug, (object) $args);
1604              else
1605                  return new WP_Error('duplicate_term_slug', sprintf(__('The slug &#8220;%s&#8221; is already in use by another term'), $slug));
1606          }
1607  
1608          $this->db->update($this->db->terms, compact( 'name', 'slug', 'term_group' ), compact( 'term_id' ) );
1609  
1610          if ( empty($slug) ) {
1611              $slug = $this->sanitize_term_slug($name, $taxonomy, $term_id);
1612              $this->db->update( $this->db->terms, compact( 'slug' ), compact( 'term_id' ) );
1613          }
1614  
1615          $tt_id = $this->db->get_var( $this->db->prepare( "SELECT tt.term_taxonomy_id FROM {$this->db->term_taxonomy} AS tt INNER JOIN {$this->db->terms} AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) );
1616  
1617          $this->db->update( $this->db->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) );
1618  
1619          do_action("edit_term", $term_id, $tt_id);
1620          do_action("edit_$taxonomy", $term_id, $tt_id);
1621  
1622          $term_id = apply_filters('term_id_filter', $term_id, $tt_id);
1623  
1624          $this->clean_term_cache($term_id, $taxonomy);
1625  
1626          do_action("edited_term", $term_id, $tt_id);
1627          do_action("edited_$taxonomy", $term_id, $tt_id);
1628  
1629          return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
1630      }
1631  
1632      /**
1633       * Enable or disable term counting.
1634       *
1635       * @since 2.5.0
1636       *
1637       * @param bool $defer Optional. Enable if true, disable if false.
1638       * @return bool Whether term counting is enabled or disabled.
1639       */
1640  	function defer_term_counting($defer=NULL) {
1641          static $_defer = false;
1642  
1643          if ( is_bool($defer) ) {
1644              $_defer = $defer;
1645              // flush any deferred counts
1646              if ( !$defer )
1647                  $this->update_term_count( NULL, NULL, true );
1648          }
1649  
1650          return $_defer;
1651      }
1652  
1653      /**
1654       * Updates the amount of terms in taxonomy.
1655       *
1656       * If there is a taxonomy callback applied, then it will be called for updating
1657       * the count.
1658       *
1659       * The default action is to count what the amount of terms have the relationship
1660       * of term ID. Once that is done, then update the database.
1661       *
1662       * @package WordPress
1663       * @subpackage Taxonomy
1664       * @since 2.3.0
1665       * @uses $this->db
1666       *
1667       * @param int|array $terms The ID of the terms
1668       * @param string $taxonomy The context of the term.
1669       * @return bool If no terms will return false, and if successful will return true.
1670       */
1671  	function update_term_count( $terms, $taxonomy, $do_deferred=false ) {
1672          static $_deferred = array();
1673  
1674          if ( $do_deferred ) {
1675              foreach ( (array) array_keys($_deferred) as $tax ) {
1676                  $this->update_term_count_now( $_deferred[$tax], $tax );
1677                  unset( $_deferred[$tax] );
1678              }
1679          }
1680  
1681          if ( empty($terms) )
1682              return false;
1683  
1684          if ( !is_array($terms) )
1685              $terms = array($terms);
1686  
1687          if ( $this->defer_term_counting() ) {
1688              if ( !isset($_deferred[$taxonomy]) )
1689                  $_deferred[$taxonomy] = array();
1690              $_deferred[$taxonomy] = array_unique( array_merge($_deferred[$taxonomy], $terms) );
1691              return true;
1692          }
1693  
1694          return $this->update_term_count_now( $terms, $taxonomy );
1695      }
1696  
1697      /**
1698       * Perform term count update immediately.
1699       *
1700       * @since 2.5.0
1701       *
1702       * @param array $terms The term_taxonomy_id of terms to update.
1703       * @param string $taxonomy The context of the term.
1704       * @return bool Always true when complete.
1705       */
1706  	function update_term_count_now( $terms, $taxonomy ) {
1707          $terms = array_map('intval', $terms);
1708  
1709          $taxonomy = $this->get_taxonomy($taxonomy);
1710          if ( !empty($taxonomy->update_count_callback) ) {
1711              call_user_func($taxonomy->update_count_callback, $terms);
1712          } else {
1713              // Default count updater
1714              foreach ( (array) $terms as $term ) {
1715                  $count = $this->db->get_var( $this->db->prepare( "SELECT COUNT(*) FROM {$this->db->term_relationships} WHERE term_taxonomy_id = %d", $term) );
1716                  $this->db->update( $this->db->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
1717              }
1718  
1719          }
1720  
1721          $this->clean_term_cache($terms);
1722  
1723          return true;
1724      }
1725  
1726      //
1727      // Cache
1728      //
1729  
1730      /**
1731       * Removes the taxonomy relationship to terms from the cache.
1732       *
1733       * Will remove the entire taxonomy relationship containing term $object_id. The
1734       * term IDs have to exist within the taxonomy $object_type for the deletion to
1735       * take place.
1736       *
1737       * @package WordPress
1738       * @subpackage Taxonomy
1739       * @since 2.3
1740       *
1741       * @see $this->get_object_taxonomies() for more on $object_type
1742       * @uses do_action() Will call action hook named, 'clean_object_term_cache' after completion.
1743       *    Passes, function params in same order.
1744       *
1745       * @param int|array $object_ids Single or list of term object ID(s)
1746       * @param string $object_type The taxonomy object type
1747       */
1748  	function clean_object_term_cache($object_ids, $object_type) {
1749          if ( !is_array($object_ids) )
1750              $object_ids = array($object_ids);
1751  
1752          foreach ( $object_ids as $id )
1753              foreach ( $this->get_object_taxonomies($object_type) as $taxonomy )
1754                  wp_cache_delete($id, "{$taxonomy}_relationships");
1755  
1756          do_action('clean_object_term_cache', $object_ids, $object_type);
1757      }
1758  
1759      /**
1760       * Will remove all of the term ids from the cache.
1761       *
1762       * @package WordPress
1763       * @subpackage Taxonomy
1764       * @since 2.3.0
1765       *
1766       * @param int|array $ids Single or list of Term IDs
1767       * @param string $taxonomy Can be empty and will assume tt_ids, else will use for context.
1768       */
1769  	function clean_term_cache($ids, $taxonomy = '') {
1770          static $cleaned = array();
1771  
1772          if ( !is_array($ids) )
1773              $ids = array($ids);
1774  
1775          $taxonomies = array();
1776          // If no taxonomy, assume tt_ids.
1777          if ( empty($taxonomy) ) {
1778              $tt_ids = implode( ',', array_map( 'intval', $ids ) );
1779              $terms = $this->db->get_results("SELECT term_id, term_taxonomy_id, taxonomy FROM {$this->db->term_taxonomy} WHERE term_taxonomy_id IN ($tt_ids)");
1780              foreach ( (array) $terms as $term ) {
1781                  $taxonomies[] = $term->taxonomy;
1782                  wp_cache_delete($term->term_id, $term->taxonomy);
1783                  wp_cache_delete($term->term_taxonomy_id, "{$term->taxonomy}:tt_id");
1784              }
1785              $taxonomies = array_unique($taxonomies);
1786          } else {
1787              $tt_ids = implode( ',', array_map( 'intval', $ids ) );
1788              $terms = $this->db->get_results("SELECT term_id, term_taxonomy_id FROM {$this->db->term_taxonomy} WHERE term_id IN ($tt_ids)");
1789              foreach ( (array) $terms as $term ) {
1790                  wp_cache_delete($term->term_id, $taxonomy);
1791                  wp_cache_delete($term->term_taxonomy_id, "$taxonomy:tt_id");
1792              }
1793              $taxonomies = array($taxonomy);
1794          }
1795  
1796          foreach ( $taxonomies as $taxonomy ) {
1797              if ( isset($cleaned[$taxonomy]) )
1798                  continue;
1799              $cleaned[$taxonomy] = true;
1800              wp_cache_delete('all_ids', $taxonomy);
1801              wp_cache_delete('get', $taxonomy);
1802              $this->delete_children_cache($taxonomy);
1803          }
1804  
1805          wp_cache_delete('get_terms', 'terms');
1806  
1807          do_action('clean_term_cache', $ids, $taxonomy);
1808      }
1809  
1810      /**
1811       * Retrieves the taxonomy relationship to the term object id.
1812       *
1813       * @package WordPress
1814       * @subpackage Taxonomy
1815       * @since 2.3.0
1816       *
1817       * @uses wp_cache_get() Retrieves taxonomy relationship from cache
1818       *
1819       * @param int|array $id Term object ID
1820       * @param string $taxonomy Taxonomy Name
1821       * @return bool|array Empty array if $terms found, but not $taxonomy. False if nothing is in cache for $taxonomy and $id.
1822       */
1823      function &get_object_term_cache($id, $taxonomy) {
1824          $cache = wp_cache_get($id, "{$taxonomy}_relationships");
1825          return $cache;
1826      }
1827  
1828      /**
1829       * Updates the cache for Term ID(s).
1830       *
1831       * Will only update the cache for terms not already cached.
1832       *
1833       * The $object_ids expects that the ids be separated by commas, if it is a
1834       * string.
1835       *
1836       * It should be noted that update_object_term_cache() is very time extensive. It
1837       * is advised that the function is not called very often or at least not for a
1838       * lot of terms that exist in a lot of taxonomies. The amount of time increases
1839       * for each term and it also increases for each taxonomy the term belongs to.
1840       *
1841       * @package WordPress
1842       * @subpackage Taxonomy
1843       * @since 2.3.0
1844       * @uses $this->get_object_terms() Used to get terms from the database to update
1845       *
1846       * @param string|array $object_ids Single or list of term object ID(s)
1847       * @param string $object_type The taxonomy object type
1848       * @return null|bool Null value is given with empty $object_ids. False if 
1849       */
1850  	function update_object_term_cache($object_ids, $object_type) {
1851          if ( empty($object_ids) )
1852              return;
1853  
1854          if ( !is_array($object_ids) )
1855              $object_ids = explode(',', $object_ids);
1856  
1857          $object_ids = array_map('intval', $object_ids);
1858  
1859          $taxonomies = $this->get_object_taxonomies($object_type);
1860  
1861          $ids = array();
1862          foreach ( (array) $object_ids as $id ) {
1863              foreach ( $taxonomies as $taxonomy ) {
1864                  if ( false === wp_cache_get($id, "{$taxonomy}_relationships") ) {
1865                      $ids[] = $id;
1866                      break;
1867                  }
1868              }
1869          }
1870  
1871          if ( empty( $ids ) )
1872              return false;
1873  
1874          $terms = $this->get_object_terms($ids, $taxonomies, 'fields=all_with_object_id');
1875  
1876          $object_terms = array();
1877          foreach ( (array) $terms as $term )
1878              $object_terms[$term->object_id][$term->taxonomy][$term->term_id] = $term;
1879  
1880          foreach ( $ids as $id ) {
1881              foreach ( $taxonomies  as $taxonomy ) {
1882                  if ( ! isset($object_terms[$id][$taxonomy]) ) {
1883                      if ( !isset($object_terms[$id]) )
1884                          $object_terms[$id] = array();
1885                      $object_terms[$id][$taxonomy] = array();
1886                  }
1887              }
1888          }
1889  
1890          foreach ( $object_terms as $id => $value ) {
1891              foreach ( $value as $taxonomy => $terms ) {
1892                  wp_cache_set($id, $terms, "{$taxonomy}_relationships");
1893              }
1894          }
1895      }
1896  
1897      /**
1898       * Updates Terms to Taxonomy in cache.
1899       *
1900       * @package WordPress
1901       * @subpackage Taxonomy
1902       * @since 2.3.0
1903       *
1904       * @param array $terms List of Term objects to change
1905       * @param string $taxonomy Optional. Update Term to this taxonomy in cache
1906       */
1907  	function update_term_cache($terms, $taxonomy = '') {
1908          foreach ( (array) $terms as $term ) {
1909              $term_taxonomy = $taxonomy;
1910              if ( empty($term_taxonomy) )
1911                  $term_taxonomy = $term->taxonomy;
1912  
1913              wp_cache_add($term->term_id, $term, $term_taxonomy);
1914              wp_cache_add($term->term_taxonomy_id, $term->term_id, "$term_taxonomy:tt_id");
1915          }
1916      }
1917  
1918      //
1919      // Private
1920      //
1921  
1922      /**
1923       * Retrieves children of taxonomy as Term IDs.
1924       *
1925       * @package WordPress
1926       * @subpackage Taxonomy
1927       * @access private
1928       * @since 2.3.0
1929       *
1930       * @uses backpress_update_option() Stores all of the children in "$taxonomy_children"
1931       *  option. That is the name of the taxonomy, immediately followed by '_children'.
1932       *
1933       * @param string $taxonomy Taxonomy Name
1934       * @return array Empty if $taxonomy isn't hierarachical or returns children as Term IDs.
1935       */
1936  	function _get_term_hierarchy($taxonomy) {
1937          if ( !$this->is_taxonomy_hierarchical($taxonomy) )
1938              return array();
1939          $children = $this->get_children_cache($taxonomy);
1940          if ( is_array($children) )
1941              return $children;
1942  
1943          $children = array();
1944          $terms = $this->get_terms($taxonomy, 'get=all');
1945          foreach ( $terms as $term ) {
1946              if ( $term->parent > 0 )
1947                  $children[$term->parent][] = $term->term_id;
1948          }
1949          $this->set_children_cache($taxonomy, $children);
1950  
1951          return $children;
1952      }
1953  
1954      /**
1955       * Get the subset of $terms that are descendants of $term_id.
1956       *
1957       * If $terms is an array of objects, then _get_term_children returns an array of objects.
1958       * If $terms is an array of IDs, then _get_term_children returns an array of IDs.
1959       *
1960       * @package WordPress
1961       * @subpackage Taxonomy
1962       * @access private
1963       * @since 2.3.0
1964       *
1965       * @param int $term_id The ancestor term: all returned terms should be descendants of $term_id.
1966       * @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.
1967       * @param string $taxonomy The taxonomy which determines the hierarchy of the terms.
1968       * @return array The subset of $terms that are descendants of $term_id.
1969       */
1970      function &_get_term_children($term_id, $terms, $taxonomy) {
1971          $empty_array = array();
1972          if ( empty($terms) )
1973              return $empty_array;
1974  
1975          $term_list = array();
1976          $has_children = $this->_get_term_hierarchy($taxonomy);
1977  
1978          if  ( ( 0 != $term_id ) && ! isset($has_children[$term_id]) )
1979              return $empty_array;
1980  
1981          foreach ( (array) $terms as $term ) {
1982              $use_id = false;
1983              if ( !is_object($term) ) {
1984                  $term = $this->get_term($term, $taxonomy);
1985                  if ( is_wp_error( $term ) )
1986                      return $term;
1987                  $use_id = true;
1988              }
1989  
1990              if ( $term->term_id == $term_id )
1991                  continue;
1992  
1993              if ( $term->parent == $term_id ) {
1994                  if ( $use_id )
1995                      $term_list[] = $term->term_id;
1996                  else
1997                      $term_list[] = $term;
1998  
1999                  if ( !isset($has_children[$term->term_id]) )
2000                      continue;
2001  
2002                  if ( $children = $this->_get_term_children($term->term_id, $terms, $taxonomy) )
2003                      $term_list = array_merge($term_list, $children);
2004              }
2005          }
2006  
2007          return $term_list;
2008      }
2009  
2010      /**
2011       * Add count of children to parent count.
2012       *
2013       * Recalculates term counts by including items from child terms. Assumes all
2014       * relevant children are already in the $terms argument.
2015       *
2016       * @package WordPress
2017       * @subpackage Taxonomy
2018       * @access private
2019       * @since 2.3
2020       *
2021       * @param array $terms List of Term IDs
2022       * @param string $taxonomy Term Context
2023       * @return null Will break from function if conditions are not met.
2024       */
2025  	function _pad_term_counts(&$terms, $taxonomy) {
2026          return;
2027      }
2028  
2029      /**
2030       * Determine if the given object is associated with any of the given terms.
2031       *
2032       * The given terms are checked against the object's terms' term_ids, names and slugs.
2033       * Terms given as integers will only be checked against the object's terms' term_ids.
2034       * If no terms are given, determines if object is associated with any terms in the given taxonomy.
2035       *
2036       * @since 2.7.0
2037       * @uses WP_Taxonomy::get_object_term_cache()
2038       * @uses WP_Taxonomy::get_object_terms()
2039       *
2040       * @param int $object_id.  ID of the object (post ID, link ID, ...)
2041       * @param string $taxonomy.  Single taxonomy name
2042       * @param int|string|array $terms Optional.  Term term_id, name, slug or array of said
2043       * @return bool|WP_Error. WP_Error on input error.
2044       */
2045  	function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
2046          if ( !$object_id = (int) $object_id )
2047              return new WP_Error( 'invalid_object', __( 'Invalid object ID' ) );
2048  
2049          $object_terms = $this->get_object_term_cache( $object_id, $taxonomy );
2050          if ( empty( $object_terms ) )
2051               $object_terms = $this->get_object_terms( $object_id, $taxonomy );
2052  
2053          if ( is_wp_error( $object_terms ) )
2054              return $object_terms;
2055          if ( empty( $object_terms ) )
2056              return false;
2057          if ( empty( $terms ) )
2058              return ( !empty( $object_terms ) );
2059  
2060          $terms = (array) $terms;
2061  
2062          if ( $ints = array_filter( $terms, 'is_int' ) )
2063              $strs = array_diff( $terms, $ints );
2064          else
2065              $strs =& $terms;
2066  
2067          foreach ( $object_terms as $object_term ) {
2068              if ( $ints && in_array( $object_term->term_id, $ints ) ) return true; // If int, check against term_id
2069              if ( $strs ) {
2070                  if ( in_array( $object_term->term_id, $strs ) ) return true;
2071                  if ( in_array( $object_term->name, $strs ) )    return true;
2072                  if ( in_array( $object_term->slug, $strs ) )    return true;
2073              }
2074          }
2075  
2076          return false;
2077      }
2078  
2079  	function get_children_cache( $taxonomy ) { return false; }
2080  	function set_children_cache( $taxonomy, $children ) {}
2081  	function delete_children_cache( $taxonomy ) {}
2082  }


Generated: Tue Mar 19 01:01:07 2024 Cross-referenced by PHPXref 0.7.1