Use a more reliable method for generating `get_terms()` cache key.

Previously, the cache key included a serialization of `list_terms_exclusions`
callbacks, to ensure that the cache was differentiated properly for different
uses of the `list_terms_exclusions` filter. This strategy was flawed in a
couple of ways: serialization doesn't work equally well for all callable types;
the serialization required reaching into the `$wp_filter` global; serializing
the callback itself didn't properly account for the possibility that the
callback might return different values in different contexts; the cache key
didn't account for other filters that similarly affect the cached values, such
as `terms_clauses`.

We skirt all these issues by concatenating the cache key using the SQL query
string, which will reflect all filters applied earlier in `get_terms()`.

Props boonebgorges, wonderboymusic.
Fixes #21267.

git-svn-id: https://develop.svn.wordpress.org/trunk@35120 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Boone Gorges 2015-10-13 03:06:27 +00:00
parent d5e0f87530
commit 0d28b59c0b
1 changed files with 26 additions and 27 deletions

View File

@ -1144,33 +1144,6 @@ function get_terms( $taxonomies, $args = '' ) {
}
}
// $args can be whatever, only use the args defined in defaults to compute the key.
$filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
$key = md5( serialize( wp_array_slice_assoc( $args, array_keys( $defaults ) ) ) . serialize( $taxonomies ) . $filter_key );
$last_changed = wp_cache_get( 'last_changed', 'terms' );
if ( ! $last_changed ) {
$last_changed = microtime();
wp_cache_set( 'last_changed', $last_changed, 'terms' );
}
$cache_key = "get_terms:$key:$last_changed";
$cache = wp_cache_get( $cache_key, 'terms' );
if ( false !== $cache ) {
if ( 'all' === $args['fields'] ) {
$cache = array_map( 'get_term', $cache );
}
/**
* Filter the given taxonomy's terms cache.
*
* @since 2.3.0
*
* @param array $cache Cached array of terms for the given taxonomy.
* @param array $taxonomies An array of taxonomies.
* @param array $args An array of get_terms() arguments.
*/
return apply_filters( 'get_terms', $cache, $taxonomies, $args );
}
$_orderby = strtolower( $args['orderby'] );
if ( 'count' == $_orderby ) {
$orderby = 'tt.count';
@ -1418,6 +1391,32 @@ function get_terms( $taxonomies, $args = '' ) {
$query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits";
// $args can be anything. Only use the args defined in defaults to compute the key.
$key = md5( serialize( wp_array_slice_assoc( $args, array_keys( $defaults ) ) ) . serialize( $taxonomies ) . $query );
$last_changed = wp_cache_get( 'last_changed', 'terms' );
if ( ! $last_changed ) {
$last_changed = microtime();
wp_cache_set( 'last_changed', $last_changed, 'terms' );
}
$cache_key = "get_terms:$key:$last_changed";
$cache = wp_cache_get( $cache_key, 'terms' );
if ( false !== $cache ) {
if ( 'all' === $_fields ) {
$cache = array_map( 'get_term', $cache );
}
/**
* Filter the given taxonomy's terms cache.
*
* @since 2.3.0
*
* @param array $cache Cached array of terms for the given taxonomy.
* @param array $taxonomies An array of taxonomies.
* @param array $args An array of get_terms() arguments.
*/
return apply_filters( 'get_terms', $cache, $taxonomies, $args );
}
if ( 'count' == $_fields ) {
return $wpdb->get_var( $query );
}