Skip to:
Content

Ticket #7502: 7502.01.patch

File 7502.01.patch, 88.2 KB (added by r-a-y, 9 months ago)
  • src/bp-forums/bp-forums-bbpress-sa.php

    diff --git src/bp-forums/bp-forums-bbpress-sa.php src/bp-forums/bp-forums-bbpress-sa.php
    index cefec1eb..020550ef 100644
    function bp_forums_load_bbpress() { 
    3737        define( 'BB_INC', 'bb-includes/' ); 
    3838 
    3939        require( BB_PATH . BB_INC . 'class.bb-query.php' ); 
    40         require( BB_PATH . BB_INC . 'class.bb-walker.php' ); 
     40        @require( BB_PATH . BB_INC . 'class.bb-walker.php' ); 
    4141 
    4242        require( BB_PATH . BB_INC . 'functions.bb-core.php' ); 
    4343        require( BB_PATH . BB_INC . 'functions.bb-forums.php' ); 
    function bp_forums_load_bbpress() { 
    5050        require( BB_PATH . BB_INC . 'functions.bb-formatting.php' ); 
    5151        require( BB_PATH . BB_INC . 'functions.bb-template.php' ); 
    5252 
    53         require( BACKPRESS_PATH . 'class.wp-taxonomy.php' ); 
    54         require( BB_PATH . BB_INC . 'class.bb-taxonomy.php' ); 
     53        require( $bp->plugin_dir . '/bp-forums/class.backpress-taxonomy.php' ); 
     54        require( $bp->plugin_dir . '/bp-forums/class.bb-taxonomy.php' ); 
    5555 
    56         require( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' ); 
     56        @require( BB_PATH . 'bb-admin/includes/functions.bb-admin.php' ); 
    5757 
    5858        $bb = new stdClass(); 
    5959        require( bp_get_option( 'bb-config-location' ) ); 
  • new file src/bp-forums/class.backpress-taxonomy.php

    diff --git src/bp-forums/class.backpress-taxonomy.php src/bp-forums/class.backpress-taxonomy.php
    new file mode 100644
    index 00000000..f02fe194
    - +  
     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 */ 
     17class BackPress_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                $this->__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} 
  • new file src/bp-forums/class.bb-taxonomy.php

    diff --git src/bp-forums/class.bb-taxonomy.php src/bp-forums/class.bb-taxonomy.php
    new file mode 100644
    index 00000000..ead4e34a
    - +  
     1<?php 
     2/** 
     3 * Taxonomy API 
     4 * 
     5 * @package bbPress 
     6 * @subpackage Taxonomy 
     7 * @since 1.0 
     8 * @todo cache 
     9 */ 
     10class BB_Taxonomy extends BackPress_Taxonomy 
     11{ 
     12        /** 
     13         * Retrieve object_ids of valid taxonomy and term. 
     14         * 
     15         * The strings of $taxonomies must exist before this function will continue. On 
     16         * failure of finding a valid taxonomy, it will return an WP_Error class, kind 
     17         * of like Exceptions in PHP 5, except you can't catch them. Even so, you can 
     18         * still test for the WP_Error class and get the error message. 
     19         * 
     20         * The $terms aren't checked the same as $taxonomies, but still need to exist 
     21         * for $object_ids to be returned. 
     22         * 
     23         * It is possible to change the order that object_ids is returned by either 
     24         * using PHP sort family functions or using the database by using $args with 
     25         * either ASC or DESC array. The value should be in the key named 'order'. 
     26         * 
     27         * @package bbPress 
     28         * @subpackage Taxonomy 
     29         * @since 1.0 
     30         * 
     31         * @uses wp_parse_args() Creates an array from string $args. 
     32         * 
     33         * @param string|array $terms String of term or array of string values of terms that will be used 
     34         * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names 
     35         * @param array|string $args Change the order of the object_ids, either ASC or DESC 
     36         * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success 
     37         *      the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found. 
     38         */ 
     39        function get_objects_in_term( $terms, $taxonomies, $args = null ) { 
     40                if ( !is_array($terms) ) 
     41                        $terms = array($terms); 
     42 
     43                if ( !is_array($taxonomies) ) 
     44                        $taxonomies = array($taxonomies); 
     45 
     46                foreach ( (array) $taxonomies as $taxonomy ) { 
     47                        if ( !$this->is_taxonomy($taxonomy) ) 
     48                                return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy')); 
     49                } 
     50 
     51                $defaults = array('order' => 'ASC', 'field' => 'term_id', 'user_id' => 0); 
     52                $args = wp_parse_args( $args, $defaults ); 
     53                extract($args, EXTR_SKIP); 
     54 
     55                if ( 'tt_id' == $field ) 
     56                        $field = 'tt.term_taxonomy_id'; 
     57                else 
     58                        $field = 'tt.term_id'; 
     59 
     60                $order = ( 'desc' == strtolower($order) ) ? 'DESC' : 'ASC'; 
     61                $user_id = (int) $user_id; 
     62 
     63                $terms = array_map('intval', $terms); 
     64 
     65                $taxonomies = "'" . implode("', '", $taxonomies) . "'"; 
     66                $terms = "'" . implode("', '", $terms) . "'"; 
     67 
     68                $sql = "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)"; 
     69                if ( $user_id ) 
     70                        $sql .= " AND tr.user_id = '$user_id'"; 
     71                $sql .= " ORDER BY tr.object_id $order"; 
     72 
     73                $object_ids = $this->db->get_col( $sql ); 
     74 
     75                if ( ! $object_ids ) 
     76                        return array(); 
     77 
     78                return $object_ids; 
     79        } 
     80 
     81        /** 
     82         * Will unlink the term from the taxonomy. 
     83         * 
     84         * Will remove the term's relationship to the taxonomy, not the term or taxonomy 
     85         * itself. The term and taxonomy will still exist. Will require the term's 
     86         * object ID to perform the operation. 
     87         * 
     88         * @package bbPress 
     89         * @subpackage Taxonomy 
     90         * @since 1.0 
     91         * 
     92         * @param int $object_id The term Object Id that refers to the term 
     93         * @param string|array $taxonomy List of Taxonomy Names or single Taxonomy name. 
     94         * @param int $user_id The ID of the user who created the relationship. 
     95         */ 
     96        function delete_object_term_relationships( $object_id, $taxonomies, $user_id = 0 ) { 
     97                $object_id = (int) $object_id; 
     98                $user_id = (int) $user_id; 
     99 
     100                if ( !is_array($taxonomies) ) 
     101                        $taxonomies = array($taxonomies); 
     102 
     103                foreach ( (array) $taxonomies as $taxonomy ) { 
     104                        $terms = $this->get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids', 'user_id' => $user_id)); 
     105                        $in_terms = "'" . implode("', '", $terms) . "'"; 
     106                        $sql = "DELETE FROM {$this->db->term_relationships} WHERE object_id = %d AND term_taxonomy_id IN ($in_terms)"; 
     107                        if ( $user_id ) 
     108                                $sql .= " AND user_id = %d"; 
     109                        $this->db->query( $this->db->prepare( $sql, $object_id, $user_id ) ); 
     110                        $this->update_term_count($terms, $taxonomy); 
     111                } 
     112        } 
     113 
     114        /** 
     115         * Retrieves the terms associated with the given object(s), in the supplied taxonomies. 
     116         * 
     117         * The following information has to do the $args parameter and for what can be 
     118         * contained in the string or array of that parameter, if it exists. 
     119         * 
     120         * The first argument is called, 'orderby' and has the default value of 'name'. 
     121         * The other value that is supported is 'count'. 
     122         * 
     123         * The second argument is called, 'order' and has the default value of 'ASC'. 
     124         * The only other value that will be acceptable is 'DESC'. 
     125         * 
     126         * The final argument supported is called, 'fields' and has the default value of 
     127         * 'all'. There are multiple other options that can be used instead. Supported 
     128         * values are as follows: 'all', 'ids', 'names', and finally 
     129         * 'all_with_object_id'. 
     130         * 
     131         * The fields argument also decides what will be returned. If 'all' or 
     132         * 'all_with_object_id' is choosen or the default kept intact, then all matching 
     133         * terms objects will be returned. If either 'ids' or 'names' is used, then an 
     134         * array of all matching term ids or term names will be returned respectively. 
     135         * 
     136         * @package bbPress 
     137         * @subpackage Taxonomy 
     138         * @since 1.0 
     139         * 
     140         * @param int|array $object_id The id of the object(s) to retrieve. 
     141         * @param string|array $taxonomies The taxonomies to retrieve terms from. 
     142         * @param array|string $args Change what is returned 
     143         * @return array|WP_Error The requested term data or empty array if no terms found. WP_Error if $taxonomy does not exist. 
     144         */ 
     145        function get_object_terms($object_ids, $taxonomies, $args = array()) { 
     146                if ( !is_array($taxonomies) ) 
     147                        $taxonomies = array($taxonomies); 
     148 
     149                foreach ( (array) $taxonomies as $taxonomy ) { 
     150                        if ( !$this->is_taxonomy($taxonomy) ) 
     151                                return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy')); 
     152                } 
     153 
     154                if ( !is_array($object_ids) ) 
     155                        $object_ids = array($object_ids); 
     156                $object_ids = array_map('intval', $object_ids); 
     157 
     158                $defaults = array('orderby' => 'name', 'order' => 'ASC', 'fields' => 'all', 'user_id' => 0); 
     159                $args = wp_parse_args( $args, $defaults ); 
     160                $args['user_id'] = (int) $args['user_id']; 
     161 
     162                $terms = array(); 
     163                if ( count($taxonomies) > 1 ) { 
     164                        foreach ( $taxonomies as $index => $taxonomy ) { 
     165                                $t = $this->get_taxonomy($taxonomy); 
     166                                if ( isset($t->args) && is_array($t->args) && $args != array_merge($args, $t->args) ) { 
     167                                        unset($taxonomies[$index]); 
     168                                        $terms = array_merge($terms, $this->get_object_terms($object_ids, $taxonomy, array_merge($args, $t->args))); 
     169                                } 
     170                        } 
     171                } else { 
     172                        $t = $this->get_taxonomy($taxonomies[0]); 
     173                        if ( isset($t->args) && is_array($t->args) ) 
     174                                $args = array_merge($args, $t->args); 
     175                } 
     176 
     177                extract($args, EXTR_SKIP); 
     178                $user_id = (int) $user_id; 
     179 
     180                if ( 'count' == $orderby ) 
     181                        $orderby = 'tt.count'; 
     182                else if ( 'name' == $orderby ) 
     183                        $orderby = 't.name'; 
     184                else if ( 'slug' == $orderby ) 
     185                        $orderby = 't.slug'; 
     186                else if ( 'term_group' == $orderby ) 
     187                        $orderby = 't.term_group'; 
     188                else if ( 'term_order' == $orderby ) 
     189                        $orderby = 'tr.term_order'; 
     190                else if ( 'none' == $orderby ) { 
     191                        $orderby = ''; 
     192                        $order = ''; 
     193                } else { 
     194                        $orderby = 't.term_id'; 
     195                } 
     196 
     197                // tt_ids queries can only be none or tr.term_taxonomy_id 
     198                if ( ('tt_ids' == $fields) && !empty($orderby) ) 
     199                        $orderby = 'tr.term_taxonomy_id'; 
     200 
     201                if ( !empty($orderby) ) 
     202                        $orderby = "ORDER BY $orderby"; 
     203 
     204                $taxonomies = "'" . implode("', '", $taxonomies) . "'"; 
     205                $object_ids = implode(', ', $object_ids); 
     206 
     207                $select_this = ''; 
     208                if ( 'all' == $fields ) 
     209                        $select_this = 't.*, tt.*, tr.user_id'; 
     210                else if ( 'ids' == $fields ) 
     211                        $select_this = 't.term_id'; 
     212                else if ( 'names' == $fields ) 
     213                        $select_this = 't.name'; 
     214                else if ( 'all_with_object_id' == $fields ) 
     215                        $select_this = 't.*, tt.*, tr.user_id, tr.object_id'; 
     216 
     217                $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)"; 
     218                if ( $user_id ) 
     219                        $query .= " AND user_id = '$user_id'"; 
     220                $query .= " $orderby $order"; 
     221 
     222                if ( 'all' == $fields || 'all_with_object_id' == $fields ) { 
     223                        $terms = array_merge($terms, $this->db->get_results($query)); 
     224                        $this->update_term_cache($terms); 
     225                } else if ( 'ids' == $fields || 'names' == $fields ) { 
     226                        $terms = array_merge($terms, $this->db->get_col($query)); 
     227                } else if ( 'tt_ids' == $fields ) { 
     228                        $query = "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)"; 
     229                        if ( $user_id ) 
     230                                $query .= " AND tr.user_id = '$user_id'"; 
     231                        $query .= " $orderby $order"; 
     232                        $terms = $this->db->get_col( $query ); 
     233                } 
     234 
     235                if ( ! $terms ) 
     236                        $terms = array(); 
     237 
     238                return apply_filters('wp_get_object_terms', $terms, $object_ids, $taxonomies, $args); 
     239        } 
     240 
     241        /** 
     242         * Create Term and Taxonomy Relationships. 
     243         * 
     244         * Relates an object (post, link etc) to a term and taxonomy type. Creates the 
     245         * term and taxonomy relationship if it doesn't already exist. Creates a term if 
     246         * it doesn't exist (using the slug). 
     247         * 
     248         * A relationship means that the term is grouped in or belongs to the taxonomy. 
     249         * A term has no meaning until it is given context by defining which taxonomy it 
     250         * exists under. 
     251         * 
     252         * @package bbPress 
     253         * @subpackage Taxonomy 
     254         * @since 1.0 
     255         * 
     256         * @param int $object_id The object to relate to. 
     257         * @param array|int|string $term The slug or id of the term, will replace all existing 
     258         * related terms in this taxonomy. 
     259         * @param array|string $taxonomy The context in which to relate the term to the object. 
     260         * @param bool $append If false will delete difference of terms. 
     261         * @return array|WP_Error Affected Term IDs 
     262         */ 
     263        function set_object_terms($object_id, $terms, $taxonomy, $args = null) { 
     264                $object_id = (int) $object_id; 
     265 
     266                $defaults = array( 'append' => false, 'user_id' => 0 ); 
     267                if ( is_scalar( $args ) ) 
     268                        $args = array( 'append' => (bool) $args ); 
     269                $args = wp_parse_args( $args, $defaults ); 
     270                extract( $args, EXTR_SKIP ); 
     271                if ( !$user_id = (int) $user_id ) 
     272                        return new WP_Error('invalid_user_id', __('Invalid User ID')); 
     273 
     274                if ( !$this->is_taxonomy($taxonomy) ) 
     275                        return new WP_Error('invalid_taxonomy', __('Invalid Taxonomy')); 
     276 
     277                if ( !is_array($terms) ) 
     278                        $terms = array($terms); 
     279 
     280                if ( ! $append ) 
     281                        $old_tt_ids = $this->get_object_terms($object_id, $taxonomy, array('user_id' => $user_id, 'fields' => 'tt_ids', 'orderby' => 'none')); 
     282 
     283                $tt_ids = array(); 
     284                $term_ids = array(); 
     285 
     286                foreach ( (array) $terms as $term ) { 
     287                        if ( !strlen(trim($term)) ) 
     288                                continue; 
     289 
     290                        if ( !$id = $this->is_term($term, $taxonomy) ) 
     291                                $id = $this->insert_term($term, $taxonomy); 
     292                        if ( is_wp_error($id) ) 
     293                                return $id; 
     294                        $term_ids[] = $id['term_id']; 
     295                        $id = $id['term_taxonomy_id']; 
     296                        $tt_ids[] = $id; 
     297 
     298                        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 AND user_id = %d", $object_id, $id, $user_id ) ) ) 
     299                                continue; 
     300                        $this->db->insert( $this->db->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $id, 'user_id' => $user_id ) ); 
     301                } 
     302 
     303                $this->update_term_count($tt_ids, $taxonomy); 
     304 
     305                if ( ! $append ) { 
     306                        $delete_terms = array_diff($old_tt_ids, $tt_ids); 
     307                        if ( $delete_terms ) { 
     308                                $in_delete_terms = "'" . implode("', '", $delete_terms) . "'"; 
     309                                $this->db->query( $this->db->prepare("DELETE FROM {$this->db->term_relationships} WHERE object_id = %d AND user_id = %d AND term_taxonomy_id IN ($in_delete_terms)", $object_id, $user_id) ); 
     310                                $this->update_term_count($delete_terms, $taxonomy); 
     311                        } 
     312                } 
     313 
     314                $t = $this->get_taxonomy($taxonomy); 
     315                if ( ! $append && isset($t->sort) && $t->sort ) { 
     316                        $values = array(); 
     317                        $term_order = 0; 
     318                        $final_tt_ids = $this->get_object_terms($object_id, $taxonomy, array( 'user_id' => $user_id, 'fields' => 'tt_ids' )); 
     319                        foreach ( $tt_ids as $tt_id ) 
     320                                if ( in_array($tt_id, $final_tt_ids) ) 
     321                                        $values[] = $this->db->prepare( "(%d, %d, %d, %d)", $object_id, $tt_id, $user_id, ++$term_order); 
     322                        if ( $values ) 
     323                                $this->db->query("INSERT INTO {$this->db->term_relationships} (object_id, term_taxonomy_id, user_id, term_order) VALUES " . join(',', $values) . " ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)"); 
     324                } 
     325 
     326                do_action('set_object_terms', $object_id, $terms, $tt_ids, $taxonomy, $append); 
     327                return $tt_ids; 
     328        } 
     329} // END class BB_Taxonomy extends WP_Taxonomy