WordPress.org

Make WordPress Core

Ticket #14162: 14162.diff

File 14162.diff, 16.6 KB (added by boonebgorges, 6 years ago)
  • src/wp-includes/category-functions.php

    diff --git src/wp-includes/category-functions.php src/wp-includes/category-functions.php
    index 847dd50..193887f 100644
    function clean_category_cache( $id ) { 
    325325 */
    326326function _make_cat_compat( &$category ) {
    327327        if ( is_object( $category ) && ! is_wp_error( $category ) ) {
    328                 $category->cat_ID = &$category->term_id;
    329                 $category->category_count = &$category->count;
    330                 $category->category_description = &$category->description;
    331                 $category->cat_name = &$category->name;
    332                 $category->category_nicename = &$category->slug;
    333                 $category->category_parent = &$category->parent;
     328                $category->cat_ID = $category->term_id;
     329                $category->category_count = $category->count;
     330                $category->category_description = $category->description;
     331                $category->cat_name = $category->name;
     332                $category->category_nicename = $category->slug;
     333                $category->category_parent = $category->parent;
    334334        } elseif ( is_array( $category ) && isset( $category['term_id'] ) ) {
    335335                $category['cat_ID'] = &$category['term_id'];
    336336                $category['category_count'] = &$category['count'];
  • new file src/wp-includes/class-wp-term.php

    diff --git src/wp-includes/class-wp-term.php src/wp-includes/class-wp-term.php
    new file mode 100644
    index 0000000..68fb187
    - +  
     1<?php
     2/**
     3 * WordPress Term class.
     4 *
     5 * @since 4.4.0
     6 * @package WordPress
     7 * @subpackage Taxonomy
     8 *
     9 */
     10final class WP_Term {
     11
     12        /**
     13         * Term ID.
     14         *
     15         * @since 4.4.0
     16         * @access public
     17         * @var int
     18         */
     19        public $term_id;
     20
     21        /**
     22         * The term's name.
     23         *
     24         * @since 4.4.0
     25         * @access public
     26         * @var string
     27         */
     28        public $name = '';
     29
     30        /**
     31         * The term's slug.
     32         *
     33         * @since 4.4.0
     34         * @access public
     35         * @var string
     36         */
     37        public $slug = '';
     38
     39        /**
     40         * The term's term_group.
     41         *
     42         * @since 4.4.0
     43         * @access public
     44         * @var string
     45         */
     46        public $term_group = '';
     47
     48        /**
     49         * Term Taxonomy ID.
     50         *
     51         * @since 4.4.0
     52         * @access public
     53         * @var int
     54         */
     55        public $term_taxonomy_id = 0;
     56
     57        /**
     58         * The term's taxonomy name.
     59         *
     60         * @since 4.4.0
     61         * @access public
     62         * @var string
     63         */
     64        public $taxonomy = '';
     65
     66        /**
     67         * The term's description.
     68         *
     69         * @since 4.4.0
     70         * @access public
     71         * @var string
     72         */
     73        public $description = '';
     74
     75        /**
     76         * ID of a term's parent term.
     77         *
     78         * @since 4.4.0
     79         * @access public
     80         * @var int
     81         */
     82        public $parent = 0;
     83
     84        /**
     85         * Cached object count for this term.
     86         *
     87         * @since 4.4.0
     88         * @access public
     89         * @var int
     90         */
     91        public $count = 0;
     92
     93        /**
     94         * Stores the term object's sanitization level.
     95         *
     96         * Does not correspond to a DB field.
     97         *
     98         * @since 4.4.0
     99         * @access public
     100         * @var string
     101         */
     102        public $filter = 'raw';
     103
     104        /**
     105         * Retrieve WP_Term instance.
     106         *
     107         * @since 4.4.0
     108         * @access public
     109         * @static
     110         *
     111         * @global wpdb $wpdb
     112         *
     113         * @param int $term_id Term ID.
     114         * @return WP_Term|false Term object, false otherwise.
     115         */
     116        public static function get_instance( $term_id ) {
     117                global $wpdb;
     118
     119                $term_id = (int) $term_id;
     120                if ( ! $term_id ) {
     121                        return false;
     122                }
     123
     124                $_term = wp_cache_get( $term_id, 'terms' );
     125
     126                if ( ! $_term ) {
     127                        $_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE t.term_id = %d LIMIT 1", $term_id ) );
     128                        if ( ! $_term ) {
     129                                return false;
     130                        }
     131
     132                        $_term = sanitize_term( $_term, $_term->taxonomy, 'raw' );
     133                        wp_cache_add( $term_id, $_term, 'terms' );
     134                } elseif ( empty( $_term->filter ) ) {
     135                        $_term = sanitize_term( $_term, $_term->taxonomy, 'raw' );
     136                }
     137
     138                return new WP_Term( $_term );
     139        }
     140
     141        /**
     142         * Constructor.
     143         *
     144         * @since 4.4.0
     145         *
     146         * @param WP_Term|object $term Term object.
     147         */
     148        public function __construct( $term ) {
     149                foreach ( get_object_vars( $term ) as $key => $value ) {
     150                        $this->$key = $value;
     151                }
     152        }
     153
     154        /**
     155         * Sanitize term fields, according to the filter type provided.
     156         *
     157         * @param string $filter Filter context. Accepts 'edit', 'db', 'display', 'attribute', 'js', 'raw'.
     158         * @return WP_Term
     159         */
     160        public function filter( $filter ) {
     161                if ( isset( $this->filter ) && $this->filter === $filter ) {
     162                        return $this;
     163                }
     164
     165                return sanitize_term( $this, $this->taxonomy, $filter );
     166        }
     167
     168        /**
     169         * Convert object to array.
     170         *
     171         * @return array Object as array.
     172         */
     173        public function to_array() {
     174                return get_object_vars( $this );
     175        }
     176}
  • src/wp-includes/taxonomy-functions.php

    diff --git src/wp-includes/taxonomy-functions.php src/wp-includes/taxonomy-functions.php
    index a13424b..afd8a40 100644
    function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) { 
    712712 * @global wpdb $wpdb WordPress database abstraction object.
    713713 * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
    714714 *
    715  * @param int|object $term     If integer, will get from database. If object will apply filters and return $term.
     715 * @param int|WP_Term|object $term If integer, term data will be fetched from the database, or from the cache if
     716 *                                 available. If stdClass object (as in the results of a database query), will apply
     717 *                                 filters and return a `WP_Term` object corresponding to the `$term` data. If `WP_Term`,
     718 *                                 will return `$term`.
    716719 * @param string     $taxonomy Taxonomy name that $term is part of.
    717720 * @param string     $output   Constant OBJECT, ARRAY_A, or ARRAY_N
    718721 * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
    719  * @return object|array|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
    720  * exist then WP_Error will be returned.
     722 * @return WP_Term|array|null|WP_Error Type corresponding to $output on success or null on failure. When $output is OBJECT,
     723 *                                     a `WP_Term` instance is returned. If taxonomy does not exist then WP_Error will be returned.
    721724 */
    722 function get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') {
    723         global $wpdb;
    724 
     725function get_term( $term, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
    725726        if ( empty( $term ) ) {
    726727                return new WP_Error( 'invalid_term', __( 'Empty Term' ) );
    727728        }
    728729
    729         if ( ! taxonomy_exists( $taxonomy ) ) {
     730        if ( $taxonomy && ! taxonomy_exists( $taxonomy ) ) {
    730731                return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
    731732        }
    732733
    733         if ( is_object($term) && empty($term->filter) ) {
    734                 wp_cache_add( $term->term_id, $term, $taxonomy );
     734        if ( $term instanceof WP_Term ) {
    735735                $_term = $term;
     736        } elseif ( is_object( $term ) ) {
     737                if ( empty( $term->filter ) ) {
     738                        $_term = sanitize_term( $term, $taxonomy, 'raw' );
     739                        $_term = new WP_Term( $_term );
     740                } elseif ( 'raw' == $term->filter ) {
     741                        $_term = new WP_Term( $term );
     742                } else {
     743                        $_term = WP_Term::get_instance( $term->term_id );
     744                }
    736745        } else {
    737                 if ( is_object($term) )
    738                         $term = $term->term_id;
    739                 if ( !$term = (int) $term )
    740                         return null;
    741                 if ( ! $_term = wp_cache_get( $term, $taxonomy ) ) {
    742                         $_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND t.term_id = %d LIMIT 1", $taxonomy, $term) );
    743                         if ( ! $_term )
    744                                 return null;
    745                         wp_cache_add( $term, $_term, $taxonomy );
     746                $_term = WP_Term::get_instance( $term );
     747        }
     748
     749        // If a taxonomy was passed, make sure it matches the taxonomy of the located term.
     750        if ( $_term && $taxonomy && $taxonomy !== $_term->taxonomy ) {
     751                // If there are two terms with the same ID, split the other one to a new term.
     752                $new_term_id = _split_shared_term( $_term->term_id, $_term->term_taxonomy_id );
     753
     754                // If no split occurred, this is an invalid request.
     755                if ( $new_term_id === $_term->term_id ) {
     756                        return new WP_Error( 'invalid_term', __( 'Empty Term' ) );
     757                } else {
     758                        // Refetch the term, now that it's no longer shared.
     759                        return get_term( $_term->term_id, $taxonomy, $output, $filter );
    746760                }
    747761        }
    748762
     763        if ( ! $_term ) {
     764                return null;
     765        }
     766
    749767        /**
    750768         * Filter a term.
    751769         *
    function get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') { 
    768786         * @param string     $taxonomy The taxonomy slug.
    769787         */
    770788        $_term = apply_filters( "get_$taxonomy", $_term, $taxonomy );
    771         $_term = sanitize_term($_term, $taxonomy, $filter);
    772789
    773         if ( $output == OBJECT ) {
    774                 return $_term;
    775         } elseif ( $output == ARRAY_A ) {
    776                 $__term = get_object_vars($_term);
    777                 return $__term;
     790        // Sanitize term, according to the specified filter.
     791        $_term = $_term->filter( $filter );
     792
     793        if ( $output == ARRAY_A ) {
     794                return $_term->to_array();
    778795        } elseif ( $output == ARRAY_N ) {
    779                 $__term = array_values(get_object_vars($_term));
    780                 return $__term;
    781         } else {
    782                 return $_term;
     796                return array_values( $_term->to_array() );
    783797        }
     798
     799        return $_term;
    784800}
    785801
    786802/**
    function get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') { 
    808824 * @param string     $taxonomy Taxonomy name. Optional, if `$field` is 'term_taxonomy_id'.
    809825 * @param string     $output   Constant OBJECT, ARRAY_A, or ARRAY_N
    810826 * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
    811  * @return object|array|null|WP_Error|false Term Row from database.
     827 * @return WP_Term|array|null|WP_Error|false Instance of WP_Term.
    812828 *                                          Will return false if $taxonomy does not exist or $term was not found.
    813829 */
    814830function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {
    function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter 
    822838        $tax_clause = $wpdb->prepare( "AND tt.taxonomy = %s", $taxonomy );
    823839
    824840        if ( 'slug' == $field ) {
    825                 $field = 't.slug';
     841                $_field = 't.slug';
    826842                $value = sanitize_title($value);
    827843                if ( empty($value) )
    828844                        return false;
    829845        } elseif ( 'name' == $field ) {
    830846                // Assume already escaped
    831847                $value = wp_unslash($value);
    832                 $field = 't.name';
     848                $_field = 't.name';
    833849        } elseif ( 'term_taxonomy_id' == $field ) {
    834850                $value = (int) $value;
    835                 $field = 'tt.term_taxonomy_id';
     851                $_field = 'tt.term_taxonomy_id';
    836852
    837853                // No `taxonomy` clause when searching by 'term_taxonomy_id'.
    838854                $tax_clause = '';
    function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter 
    844860                return $term;
    845861        }
    846862
    847         $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE $field = %s $tax_clause LIMIT 1", $value ) );
     863        $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE $_field = %s $tax_clause LIMIT 1", $value ) );
    848864        if ( ! $term )
    849865                return false;
    850866
    function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter 
    853869                $taxonomy = $term->taxonomy;
    854870        }
    855871
    856         wp_cache_add( $term->term_id, $term, $taxonomy );
    857 
    858         /** This filter is documented in wp-includes/taxonomy-functions.php */
    859         $term = apply_filters( 'get_term', $term, $taxonomy );
    860 
    861         /** This filter is documented in wp-includes/taxonomy-functions.php */
    862         $term = apply_filters( "get_$taxonomy", $term, $taxonomy );
    863 
    864         $term = sanitize_term($term, $taxonomy, $filter);
     872        wp_cache_add( $term->term_id, $term, 'terms' );
    865873
    866         if ( $output == OBJECT ) {
    867                 return $term;
    868         } elseif ( $output == ARRAY_A ) {
    869                 return get_object_vars($term);
    870         } elseif ( $output == ARRAY_N ) {
    871                 return array_values(get_object_vars($term));
    872         } else {
    873                 return $term;
    874         }
     874        return get_term( $term, $taxonomy, $output, $filter );
    875875}
    876876
    877877/**
    function get_term_to_edit( $id, $taxonomy ) { 
    10481048 *     @type array        $meta_query             Meta query clauses to limit retrieved terms by.
    10491049 *                                                See `WP_Meta_Query`. Default empty.
    10501050 * }
    1051  * @return array|int|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies
     1051 * @return array|int|WP_Error List of WP_Term instances and their children. Will return WP_Error, if any of $taxonomies
    10521052 *                        do not exist.
    10531053 */
    10541054function get_terms( $taxonomies, $args = '' ) {
    function get_terms( $taxonomies, $args = '' ) { 
    14891489                foreach ( $terms as $term ) {
    14901490                        $_terms[ $term->term_id ] = $term->slug;
    14911491                }
     1492        } else {
     1493                $_terms = array_map( 'get_term', $terms );
    14921494        }
    14931495
    14941496        if ( ! empty( $_terms ) ) {
    function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) { 
    34223424                foreach ( (array) $terms as $term ) {
    34233425                        $taxonomies[] = $term->taxonomy;
    34243426                        $ids[] = $term->term_id;
    3425                         wp_cache_delete($term->term_id, $term->taxonomy);
     3427                        wp_cache_delete( $term->term_id, 'terms' );
    34263428                }
    34273429                $taxonomies = array_unique($taxonomies);
    34283430        } else {
    34293431                $taxonomies = array($taxonomy);
    34303432                foreach ( $taxonomies as $taxonomy ) {
    34313433                        foreach ( $ids as $id ) {
    3432                                 wp_cache_delete($id, $taxonomy);
     3434                                wp_cache_delete( $id, 'terms' );
    34333435                        }
    34343436                }
    34353437        }
    function update_term_cache( $terms, $taxonomy = '' ) { 
    35523554                if ( empty($term_taxonomy) )
    35533555                        $term_taxonomy = $term->taxonomy;
    35543556
    3555                 wp_cache_add( $term->term_id, $term, $term_taxonomy );
     3557                wp_cache_add( $term->term_id, $term, 'terms' );
    35563558        }
    35573559}
    35583560
  • src/wp-includes/taxonomy.php

    diff --git src/wp-includes/taxonomy.php src/wp-includes/taxonomy.php
    index e29e65c..13b50fd 100644
     
    1010/** Core taxonomy functionality */
    1111require_once( ABSPATH . WPINC . '/taxonomy-functions.php' );
    1212
     13/** WP_Term class */
     14require_once( ABSPATH . WPINC . '/class-wp-term.php' );
     15
    1316/** WP_Tax_Query class */
    1417require_once( ABSPATH . WPINC . '/class-wp-tax-query.php' );
  • tests/phpunit/tests/term/cache.php

    diff --git tests/phpunit/tests/term/cache.php tests/phpunit/tests/term/cache.php
    index 1a31df0..a620986 100644
    class Tests_Term_Cache extends WP_UnitTestCase { 
    103103                ) );
    104104
    105105                $term_object = get_term( $term, 'wptests_tax' );
    106                 wp_cache_delete( $term, 'wptests_tax' );
     106                wp_cache_delete( $term, 'terms' );
    107107
    108108                // Affirm that the cache is empty.
    109                 $this->assertEmpty( wp_cache_get( $term, 'wptests_tax' ) );
     109                $this->assertEmpty( wp_cache_get( $term, 'terms' ) );
    110110
    111111                $num_queries = $wpdb->num_queries;
    112112
    class Tests_Term_Cache extends WP_UnitTestCase { 
    128128                        'taxonomy' => 'wptests_tax',
    129129                ) );
    130130
    131                 wp_cache_delete( $term, 'wptests_tax' );
     131                wp_cache_delete( $term, 'terms' );
    132132
    133133                // Affirm that the cache is empty.
    134                 $this->assertEmpty( wp_cache_get( $term, 'wptests_tax' ) );
     134                $this->assertEmpty( wp_cache_get( $term, 'terms' ) );
    135135
    136136                $num_queries = $wpdb->num_queries;
    137137
    138138                // Prime cache.
    139139                $term_object = get_term( $term, 'wptests_tax' );
    140                 $this->assertNotEmpty( wp_cache_get( $term, 'wptests_tax' ) );
     140                $this->assertNotEmpty( wp_cache_get( $term, 'terms' ) );
    141141                $this->assertSame( $num_queries + 1, $wpdb->num_queries );
    142142
    143143                $term_object_2 = get_term( $term, 'wptests_tax' );
    class Tests_Term_Cache extends WP_UnitTestCase { 
    155155                        'taxonomy' => 'wptests_tax',
    156156                ) );
    157157
    158                 wp_cache_delete( $term, 'wptests_tax' );
     158                wp_cache_delete( $term, 'terms' );
    159159
    160160                // Affirm that the cache is empty.
    161                 $this->assertEmpty( wp_cache_get( $term, 'wptests_tax' ) );
     161                $this->assertEmpty( wp_cache_get( $term, 'terms' ) );
    162162
    163163                $num_queries = $wpdb->num_queries;
    164164
    165165                // Prime cache.
    166166                $term_object = get_term_by( 'id', $term, 'wptests_tax' );
    167                 $this->assertNotEmpty( wp_cache_get( $term, 'wptests_tax' ) );
     167                $this->assertNotEmpty( wp_cache_get( $term, 'terms' ) );
    168168                $this->assertSame( $num_queries + 1, $wpdb->num_queries );
    169169
    170170                $term_object_2 = get_term( $term, 'wptests_tax' );
  • tests/phpunit/tests/term/getTerm.php

    diff --git tests/phpunit/tests/term/getTerm.php tests/phpunit/tests/term/getTerm.php
    index 6c84d68..db895a0 100644
    class Tests_Term_GetTerm extends WP_UnitTestCase { 
    3535                $this->assertSame( $num_queries, $wpdb->num_queries );
    3636        }
    3737
    38         public function test_passing_term_object_should_not_skip_database_query_when_filter_property_is_set() {
    39                 global $wpdb;
    40 
    41                 $term = $this->factory->term->create_and_get( array( 'taxonomy' => 'wptests_tax' ) );
    42                 clean_term_cache( $term->term_id, 'wptests_tax' );
    43 
    44                 $num_queries = $wpdb->num_queries;
    45 
    46                 $term_a = get_term( $term, 'wptests_tax' );
    47 
    48                 $this->assertSame( $num_queries + 1, $wpdb->num_queries );
    49         }
    50 
    5138        public function test_passing_term_string_that_casts_to_int_0_should_return_null() {
    5239                $this->assertSame( null, get_term( 'abc', 'wptests_tax' ) );
    5340        }