Make WordPress Core

Opened 3 years ago

Closed 3 years ago

#55887 closed defect (bug) (duplicate)

Calling get_terms() with exact same args (most important is exclude_tree) returns unexpected results from runtime cache (second call)

Reported by: szaqal21's profile szaqal21 Owned by:
Milestone: Priority: normal
Severity: normal Version: 6.0
Component: Taxonomy Keywords:
Focuses: Cc:

Description

Calling get_terms() with exact same args (most important is exclude_tree) returns unexpected results from runtime cache (second call).

Test case:

  1. Create some terms ex. in category tax

->Bez kategorii
->A (term_id: 110)
-->A1
->B (term_id: 111)
-->B1
->C (term_id: 112)
-->C1

  1. Then call get_terms() two times:
echo 'exclude B tree<br>';
var_dump(get_terms(array('taxonomy' => 'category', 'exclude_tree' => array(111), 'hide_empty' => false, 'fields' => 'names')));
	
echo '<br>2 exclude B tree<br>';
var_dump(get_terms(array('taxonomy' => 'category', 'exclude_tree' => array(111), 'hide_empty' => false, 'fields' => 'names')));

results:

exclude B tree
array(5) { [0]=> string(1) "A" [1]=> string(2) "A1" [2]=> string(13) "Bez kategorii" [3]=> string(1) "C" [4]=> string(2) "C1" }
2 exclude B tree
array(0) { }

Change History (3)

#1 @szaqal21
3 years ago

After some tests on WP_Term_Query::get_terms(), this query

get_terms(array('taxonomy' => 'category', 'exclude_tree' => array(111), 'hide_empty' => false, 'fields' => 'names'))

does the following, first calls another get_terms() to fill $exclusions

if ( ! empty( $exclude_tree ) ) {
			$exclude_tree      = wp_parse_id_list( $exclude_tree );
			$excluded_children = $exclude_tree;
			foreach ( $exclude_tree as $extrunk ) {
				$excluded_children = array_merge(
					$excluded_children,
					(array) get_terms(
						array(
							'taxonomy'   => reset( $taxonomies ),
							'child_of'   => (int) $extrunk,
							'fields'     => 'ids',
							'hide_empty' => 0,
						)
					)
				);
			}
			$exclusions = array_merge( $excluded_children, $exclusions );
		}

and I think here's the problem, adding some output before

...
// ADDED OUTPUT BEFORE ADDING TO CACHE

wp_cache_add( $cache_key, $terms, 'terms' );
		$terms = $this->format_terms( $term_objects, $_fields );

		$this->terms = $terms;
		return $this->terms;
}

in WP_Term_Query::get_terms() I got these results:

var_dump($this->request);
string(179) " SELECT t.term_id FROM wptest_terms AS t INNER JOIN wptest_term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy IN ('category') ORDER BY t.name ASC "
var_dump($cache_args);
array(31) { ["taxonomy"]=> array(1) { [0]=> string(8) "category" } ["object_ids"]=> array(0) { } ["orderby"]=> string(4) "name" ["order"]=> string(3) "ASC" ["hide_empty"]=> int(0) ["include"]=> array(0) { } ["exclude"]=> array(0) { } ["exclude_tree"]=> array(0) { } ["number"]=> int(0) ["offset"]=> int(0) ["fields"]=> string(3) "all" ["count"]=> bool(false) ["name"]=> array(0) { } ["slug"]=> array(0) { } ["term_taxonomy_id"]=> array(0) { } ["hierarchical"]=> bool(true) ["search"]=> string(0) "" ["name__like"]=> string(0) "" ["description__like"]=> string(0) "" ["get"]=> string(0) "" ["child_of"]=> int(111) ["parent"]=> string(0) "" ["childless"]=> bool(false) ["cache_domain"]=> string(4) "core" ["meta_query"]=> string(0) "" ["meta_key"]=> string(0) "" ["meta_value"]=> string(0) "" ["meta_type"]=> string(0) "" ["meta_compare"]=> string(0) "" ["parent__in"]=> array(0) { } ["parent__not_in"]=> array(0) { } }
var_dump($terms);
array(7) { [0]=> object(stdClass)#359 (1) { ["term_id"]=> string(3) "110" } [1]=> object(stdClass)#360 (1) { ["term_id"]=> string(3) "113" } [2]=> object(stdClass)#361 (1) { ["term_id"]=> string(3) "111" } [3]=> object(stdClass)#362 (1) { ["term_id"]=> string(3) "114" } [4]=> object(stdClass)#363 (1) { ["term_id"]=> string(1) "1" } [5]=> object(stdClass)#364 (1) { ["term_id"]=> string(3) "112" } [6]=> object(stdClass)#365 (1) { ["term_id"]=> string(3) "115" } }
var_dump($term_objects);
array(1) { [0]=> object(WP_Term)#375 (10) { ["term_id"]=> int(114) ["name"]=> string(2) "B1" ["slug"]=> string(2) "b1" ["term_group"]=> int(0) ["term_taxonomy_id"]=> int(114) ["taxonomy"]=> string(8) "category" ["description"]=> string(0) "" ["parent"]=> int(111) ["count"]=> int(0) ["filter"]=> string(3) "raw" } }

in $cache_args you can see that child_of = 111 so this query should return children for term_id = 111 and it does return proper result which is $term_objects but this is not what is being added to cache, $terms var is, as you can see $terms stores result of $wpdb->get_results( $this->request ); which is result of

SELECT t.term_id FROM wptest_terms AS t INNER JOIN wptest_term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy IN ('category') ORDER BY t.name ASC

that is all (7) terms in this taxonomy, $term_objects is the right list of terms limited to specific parent (child_of = 111).

Calling same get_terms() as previously second time results exclusion of all (7) terms (result from cache).

#2 @szaqal21
3 years ago

One more test case:

echo 'exclude_tree B (111)<br>';
var_dump(get_terms(array('taxonomy' => 'category', 'exclude_tree' => 111, 'hide_empty' => 0, 'fields' => 'ids')));

echo '<br><br>child_of B (111)<br>';
var_dump(get_terms(array('taxonomy' => 'category', 'child_of' => 111, 'hide_empty' => 0, 'fields' => 'ids')));

result

exclude_tree B (111)
array(5) { [0]=> int(110) [1]=> int(113) [2]=> int(1) [3]=> int(112) [4]=> int(115) }
OK

child_of B (111)
array(7) { [0]=> int(110) [1]=> int(113) [2]=> int(111) [3]=> int(114) [4]=> int(1) [5]=> int(112) [6]=> int(115) } 
WRONG

Second get_terms() results all terms not those which are children of parent term_id = 111.

Last edited 3 years ago by szaqal21 (previous) (diff)

#3 @SergeyBiryukov
3 years ago

  • Milestone Awaiting Review deleted
  • Resolution set to duplicate
  • Status changed from new to closed

Hi there, thanks for the ticket!

We're already tracking this issue in #55837.

Note: See TracTickets for help on using tickets.