Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions src/wp-includes/class-wp-term.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,12 @@ public static function get_instance( $term_id, $taxonomy = null ) {
}
}

$term_obj = new WP_Term( $_term );
$term_obj->filter( $term_obj->filter );
if ( empty( $_term->filter ) ) {
$_term = sanitize_term( $_term, $_term->taxonomy, 'raw' );
wp_cache_replace( $term_id, $_term, 'terms' );
}

return $term_obj;
return new WP_Term( $_term );
}

/**
Expand All @@ -206,9 +208,22 @@ public function __construct( $term ) {
* @since 4.4.0
*
* @param string $filter Filter context. Accepts 'edit', 'db', 'display', 'attribute', 'js', 'rss', or 'raw'.
* @return WP_Term Sanitized term object.
*/
public function filter( $filter ) {
sanitize_term( $this, $this->taxonomy, $filter );
if ( $this->filter === $filter ) {
return $this;
}

if ( 'raw' === $filter ) {
$raw = self::get_instance( $this->term_id, $this->taxonomy );
if ( $raw instanceof WP_Term ) {
return $raw;
}
return $this;
}

return sanitize_term( $this, $this->taxonomy, $filter );
}

/**
Expand Down
12 changes: 11 additions & 1 deletion src/wp-includes/taxonomy.php
Original file line number Diff line number Diff line change
Expand Up @@ -1046,7 +1046,7 @@ function get_term( $term, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) {

// Sanitize term, according to the specified filter.
if ( $_term !== $old_term || $_term->filter !== $filter ) {
$_term->filter( $filter );
$_term = $_term->filter( $filter );
}

if ( ARRAY_A === $output ) {
Expand Down Expand Up @@ -1723,6 +1723,16 @@ function sanitize_term( $term, $taxonomy, $context = 'display' ) {

$do_object = is_object( $term );

if ( 'raw' !== $context ) {
if ( $do_object ) {
if ( isset( $term->filter ) && $context === $term->filter ) {
return $term;
}
} elseif ( isset( $term['filter'] ) && $context === $term['filter'] ) {
return $term;
}
}

$term_id = $do_object ? ( $term->term_id ?? 0 ) : ( $term['term_id'] ?? 0 );

foreach ( (array) $fields as $field ) {
Expand Down
26 changes: 26 additions & 0 deletions tests/phpunit/tests/term/cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,32 @@ public function test_term_objects_should_not_be_modified_by_update_term_cache()
}
}

/**
* @ticket 50568
*/
public function test_get_instance_should_prime_unfiltered_cached_term_as_raw() {
register_taxonomy( 'wptests_tax', 'post' );
$term_id = self::factory()->term->create( array( 'taxonomy' => 'wptests_tax' ) );
$term = get_term( $term_id, 'wptests_tax' );

$this->assertInstanceOf( 'WP_Term', $term );

$term->filter = '';
wp_cache_delete( $term_id, 'terms' );
update_term_cache( array( $term ) );

$cached_term = wp_cache_get( $term_id, 'terms' );
$this->assertSame( '', $cached_term->filter );

$found = WP_Term::get_instance( $term_id );

$this->assertInstanceOf( 'WP_Term', $found );
$this->assertSame( 'raw', $found->filter );

$cached_term = wp_cache_get( $term_id, 'terms' );
$this->assertSame( 'raw', $cached_term->filter );
}

/**
* @ticket 21760
*/
Expand Down
41 changes: 41 additions & 0 deletions tests/phpunit/tests/term/getTerm.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,47 @@ public function test_numeric_properties_should_be_cast_to_ints() {
}
}

/**
* @ticket 50568
*/
public function test_raw_filter_object_should_normalize_integer_fields() {
$term = new stdClass();
$term->term_id = (string) self::$term->term_id;
$term->term_taxonomy_id = '123';
$term->parent = '0';
$term->count = '7';
$term->term_group = '0';
$term->filter = 'raw';
$term->name = 'Test Term';
$term->slug = 'test-term';
$term->taxonomy = 'wptests_tax';

$found = get_term( $term, 'wptests_tax' );

$this->assertInstanceOf( 'WP_Term', $found );
$this->assertSame( self::$term->term_id, $found->term_id );
$this->assertSame( 123, $found->term_taxonomy_id );
$this->assertSame( 0, $found->parent );
$this->assertSame( 7, $found->count );
$this->assertSame( 0, $found->term_group );
$this->assertSame( 'raw', $found->filter );
}

/**
* @ticket 50568
*/
public function test_display_filtered_term_should_be_returned_raw_when_raw_filter_is_requested() {
$display_term = get_term( self::$term->term_id, 'wptests_tax', OBJECT, 'display' );

$this->assertInstanceOf( 'WP_Term', $display_term );
$this->assertSame( 'display', $display_term->filter );

$raw_term = get_term( $display_term, 'wptests_tax', OBJECT, 'raw' );

$this->assertInstanceOf( 'WP_Term', $raw_term );
$this->assertSame( 'raw', $raw_term->filter );
}

/**
* @ticket 34332
*/
Expand Down
39 changes: 39 additions & 0 deletions tests/phpunit/tests/term/sanitizeTerm.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,43 @@ public function data_sanitize_term(): array {
),
);
}

/**
* @ticket 50568
*/
public function test_sanitize_term_should_return_early_when_object_already_filtered_for_context() {
$term = new stdClass();
$term->term_id = 1;
$term->name = 'Test';
$term->slug = 'test';
$term->taxonomy = 'category';
$term->description = '';
$term->filter = 'edit';

$count = did_filter( 'edit_term_name' );

$result = sanitize_term( $term, 'category', 'edit' );

$this->assertSame( $term, $result );
$this->assertSame( $count, did_filter( 'edit_term_name' ), 'edit_term_name filter should not have fired.' );
}

/**
* @ticket 50568
*/
public function test_sanitize_term_should_return_early_when_array_already_filtered_for_context() {
$term = array(
'term_id' => 1,
'name' => 'Test',
'slug' => 'test',
'filter' => 'display',
);

$count = did_filter( 'term_name' );

$result = sanitize_term( $term, 'category', 'display' );

$this->assertSame( $term, $result );
$this->assertSame( $count, did_filter( 'term_name' ), 'term_name filter should not have fired.' );
}
}
88 changes: 87 additions & 1 deletion tests/phpunit/tests/term/wpTerm.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
*/
class Tests_Term_WpTerm extends WP_UnitTestCase {
protected static $term_id;
protected static $shared_terms = array();

public function set_up() {
parent::set_up();
register_taxonomy( 'wptests_tax', 'post' );
register_taxonomy( 'wptests_tax_2', 'post' );
}

public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
global $wpdb;

register_taxonomy( 'wptests_tax', 'post' );
register_taxonomy( 'wptests_tax_2', 'post' );

// Ensure that there is a term with ID 1.
if ( ! get_term( 1 ) ) {
Expand All @@ -36,7 +39,44 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
clean_term_cache( 1, 'wptests_tax' );
}

self::$term_id = $factory->term->create( array( 'taxonomy' => 'wptests_tax' ) );
self::$term_id = $factory->term->create( array( 'taxonomy' => 'wptests_tax' ) );
self::$shared_terms = self::generate_shared_terms();
}

/**
* Utility function for generating two shared terms, in the 'wptests_tax' and 'wptests_tax_2' taxonomies.
*
* @return array Array of term_id/old_term_id/term_taxonomy_id triplets.
*/
protected static function generate_shared_terms() {
global $wpdb;

$term_1 = wp_insert_term( 'Foo', 'wptests_tax' );
$term_2 = wp_insert_term( 'Foo', 'wptests_tax_2' );

// Manually modify because shared terms shouldn't naturally occur.
$wpdb->update(
$wpdb->term_taxonomy,
array( 'term_id' => $term_1['term_id'] ),
array( 'term_taxonomy_id' => $term_2['term_taxonomy_id'] ),
array( '%d' ),
array( '%d' )
);

clean_term_cache( $term_1['term_id'] );

return array(
array(
'term_id' => $term_1['term_id'],
'old_term_id' => $term_1['term_id'],
'term_taxonomy_id' => $term_1['term_taxonomy_id'],
),
array(
'term_id' => $term_1['term_id'],
'old_term_id' => $term_2['term_id'],
'term_taxonomy_id' => $term_2['term_taxonomy_id'],
),
);
}

/**
Expand Down Expand Up @@ -89,4 +129,50 @@ public function test_get_instance_should_respect_taxonomy_when_term_id_is_found_
$found = WP_Term::get_instance( self::$term_id, 'wptests_tax2' );
$this->assertFalse( $found );
}

/**
* @ticket 50568
*/
public function test_filter_should_return_same_instance_when_context_matches() {
$term = WP_Term::get_instance( self::$term_id );

$this->assertSame( 'raw', $term->filter );
$this->assertSame( $term, $term->filter( 'raw' ) );
}

/**
* @ticket 50568
*/
public function test_filter_raw_should_return_raw_instance_from_display_filtered_term() {
$term = WP_Term::get_instance( self::$term_id );
$display_term = $term->filter( 'display' );

$this->assertSame( 'display', $display_term->filter );

$raw_term = $display_term->filter( 'raw' );

$this->assertInstanceOf( 'WP_Term', $raw_term );
$this->assertSame( 'raw', $raw_term->filter );
$this->assertNotSame( $display_term, $raw_term );
}

/**
* @ticket 50568
*/
public function test_filter_raw_should_use_taxonomy_to_disambiguate_shared_terms() {
$terms = self::$shared_terms;

$display_term = get_term( $terms[0]['term_id'], 'wptests_tax', OBJECT, 'display' );

$this->assertInstanceOf( 'WP_Term', $display_term );
$this->assertSame( 'display', $display_term->filter );
$this->assertSame( 'wptests_tax', $display_term->taxonomy );

$raw_term = $display_term->filter( 'raw' );

$this->assertInstanceOf( 'WP_Term', $raw_term );
$this->assertSame( 'raw', $raw_term->filter );
$this->assertSame( 'wptests_tax', $raw_term->taxonomy );
$this->assertSame( $terms[0]['term_taxonomy_id'], $raw_term->term_taxonomy_id );
}
}
Loading