Make WordPress Core

Changeset 56650


Ignore:
Timestamp:
09/21/2023 04:34:59 PM (9 months ago)
Author:
spacedmonkey
Message:

Taxonomy: Stop double sanitization in get_term function.

In the get_term function, the filter method is invoked on the WP_Term object, which subsequently triggers the execution of sanitize_term. The filter method is also executed within WP_Term::get_instance.

A common scenario when calling the get_term function is to invoke the function with an integer ID for the term and a filter set to "raw." This results in a call to WP_Term::get_instance. However, since both get_term and WP_Term::get_instance invoke the filter method, it leads to double sanitization of the term.

Considering that get_term may be called thousands of times on a page, especially when priming a large number of terms into memory, this redundancy can result in thousands of unnecessary calls to sanitize_term. Performing the same sanitization operation twice with the same parameters is wasteful and detrimental to performance.

To address this issue, the code has been updated to execute the filter method only when the filter parameter does not match or when changes have been made to the term object within the get_term hook. This optimization ensures that the filter is applied selectively, mitigating performance concerns and avoiding unnecessary sanitization calls.

Props spacedmonkey, flixos90, costdev, mukesh27, joemcgill, oglekler, peterwilsoncc.
Fixes #58329.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/taxonomy.php

    r56642 r56650  
    981981    $taxonomy = $_term->taxonomy;
    982982
     983    $old_term = $_term;
    983984    /**
    984985     * Filters a taxonomy term object.
     
    10201021
    10211022    // Sanitize term, according to the specified filter.
    1022     $_term->filter( $filter );
     1023    if ( $_term !== $old_term || $_term->filter !== $filter ) {
     1024        $_term->filter( $filter );
     1025    }
    10231026
    10241027    if ( ARRAY_A === $output ) {
  • trunk/tests/phpunit/tests/term.php

    r54402 r56650  
    309309        $this->assertWPError( $cat_id2 );
    310310    }
     311
     312    /**
     313     * @ticket 58329
     314     *
     315     * @covers ::get_term
     316     *
     317     */
     318    public function test_get_term_sanitize_once() {
     319        $cat_id1 = self::factory()->category->create();
     320        $_term   = get_term( $cat_id1, '', OBJECT, 'edit' );
     321
     322        $filter = new MockAction();
     323        add_filter( 'edit_term_slug', array( $filter, 'filter' ) );
     324
     325        $term = get_term( $_term, '', OBJECT, 'edit' );
     326
     327        $this->assertSame( 0, $filter->get_call_count(), 'The term was filtered more than once' );
     328        $this->assertSame( $_term, $term, 'Both terms should match' );
     329    }
     330
     331    /**
     332     * @ticket 58329
     333     *
     334     * @covers ::get_term
     335     *
     336     * @dataProvider data_get_term_filter
     337     *
     338     * @param string $filter How to sanitize term fields.
     339     */
     340    public function test_get_term_should_set_term_filter_property_to_filter_argument( $filter ) {
     341        $cat_id1 = self::factory()->category->create();
     342
     343        $term = get_term( $cat_id1, '', OBJECT, $filter );
     344
     345        $this->assertSame( $filter, $term->filter, "The term's 'filter' property should be set to '$filter'." );
     346    }
     347
     348    /**
     349     * @ticket 58329
     350     *
     351     * @covers ::get_term
     352     *
     353     * @dataProvider data_get_term_filter
     354     *
     355     * @param string $filter How to sanitize term fields.
     356     */
     357    public function test_get_term_filtered( $filter ) {
     358        $cat_id1 = self::factory()->category->create();
     359        $cat     = self::factory()->category->create_and_get();
     360        add_filter(
     361            'get_term',
     362            static function () use ( $cat ) {
     363                return $cat;
     364            }
     365        );
     366
     367        $term = get_term( $cat_id1, '', OBJECT, $filter );
     368
     369        $this->assertSame( $filter, $term->filter, "The term's 'filter' property should be set to '$filter'." );
     370        $this->assertSame( $term, $cat, 'The returned term should match the filtered term' );
     371    }
     372
     373    /**
     374     * Data provider.
     375     *
     376     * @return array[]
     377     */
     378    public function data_get_term_filter() {
     379        return self::text_array_to_dataprovider( array( 'edit', 'db', 'display', 'attribute', 'js', 'rss', 'raw' ) );
     380    }
    311381}
Note: See TracChangeset for help on using the changeset viewer.