: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Updates the amount of terms in taxonomy.
* If there is a taxonomy callback applied, then it will be called for updating
* The default action is to count what the amount of terms have the relationship
* of term ID. Once that is done, then update the database.
* @param int|array $terms The term_taxonomy_id of the terms.
* @param string $taxonomy The context of the term.
* @param bool $do_deferred Whether to flush the deferred term counts too. Default false.
* @return bool If no terms will return false, and if successful will return true.
function wp_update_term_count( $terms, $taxonomy, $do_deferred = false ) {
static $_deferred = array();
foreach ( (array) array_keys( $_deferred ) as $tax ) {
wp_update_term_count_now( $_deferred[ $tax ], $tax );
unset( $_deferred[ $tax ] );
if ( ! is_array( $terms ) ) {
$terms = array( $terms );
if ( wp_defer_term_counting() ) {
if ( ! isset( $_deferred[ $taxonomy ] ) ) {
$_deferred[ $taxonomy ] = array();
$_deferred[ $taxonomy ] = array_unique( array_merge( $_deferred[ $taxonomy ], $terms ) );
return wp_update_term_count_now( $terms, $taxonomy );
* Performs term count update immediately.
* @param array $terms The term_taxonomy_id of terms to update.
* @param string $taxonomy The context of the term.
* @return true Always true when complete.
function wp_update_term_count_now( $terms, $taxonomy ) {
$terms = array_map( 'intval', $terms );
$taxonomy = get_taxonomy( $taxonomy );
if ( ! empty( $taxonomy->update_count_callback ) ) {
call_user_func( $taxonomy->update_count_callback, $terms, $taxonomy );
$object_types = (array) $taxonomy->object_type;
foreach ( $object_types as &$object_type ) {
if ( str_starts_with( $object_type, 'attachment:' ) ) {
list( $object_type ) = explode( ':', $object_type );
if ( array_filter( $object_types, 'post_type_exists' ) == $object_types ) {
// Only post types are attached to this taxonomy.
_update_post_term_count( $terms, $taxonomy );
// Default count updater.
_update_generic_term_count( $terms, $taxonomy );
clean_term_cache( $terms, '', false );
* Removes the taxonomy relationship to terms from the cache.
* Will remove the entire taxonomy relationship containing term `$object_id`. The
* term IDs have to exist within the taxonomy `$object_type` for the deletion to
* @global bool $_wp_suspend_cache_invalidation
* @see get_object_taxonomies() for more on $object_type.
* @param int|array $object_ids Single or list of term object ID(s).
* @param array|string $object_type The taxonomy object type.
function clean_object_term_cache( $object_ids, $object_type ) {
global $_wp_suspend_cache_invalidation;
if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
if ( ! is_array( $object_ids ) ) {
$object_ids = array( $object_ids );
$taxonomies = get_object_taxonomies( $object_type );
foreach ( $taxonomies as $taxonomy ) {
wp_cache_delete_multiple( $object_ids, "{$taxonomy}_relationships" );
wp_cache_set_terms_last_changed();
* Fires after the object term cache has been cleaned.
* @param array $object_ids An array of object IDs.
* @param string $object_type Object type.
do_action( 'clean_object_term_cache', $object_ids, $object_type );
* Removes all of the term IDs from the cache.
* @global wpdb $wpdb WordPress database abstraction object.
* @global bool $_wp_suspend_cache_invalidation
* @param int|int[] $ids Single or array of term IDs.
* @param string $taxonomy Optional. Taxonomy slug. Can be empty, in which case the taxonomies of the passed
* term IDs will be used. Default empty.
* @param bool $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual
* term object caches (false). Default true.
function clean_term_cache( $ids, $taxonomy = '', $clean_taxonomy = true ) {
global $wpdb, $_wp_suspend_cache_invalidation;
if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
if ( ! is_array( $ids ) ) {
// If no taxonomy, assume tt_ids.
if ( empty( $taxonomy ) ) {
$tt_ids = array_map( 'intval', $ids );
$tt_ids = implode( ', ', $tt_ids );
$terms = $wpdb->get_results( "SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)" );
foreach ( (array) $terms as $term ) {
$taxonomies[] = $term->taxonomy;
wp_cache_delete_multiple( $ids, 'terms' );
$taxonomies = array_unique( $taxonomies );
wp_cache_delete_multiple( $ids, 'terms' );
$taxonomies = array( $taxonomy );
foreach ( $taxonomies as $taxonomy ) {
clean_taxonomy_cache( $taxonomy );
* Fires once after each taxonomy's term cache has been cleaned.
* @since 4.5.0 Added the `$clean_taxonomy` parameter.
* @param array $ids An array of term IDs.
* @param string $taxonomy Taxonomy slug.
* @param bool $clean_taxonomy Whether or not to clean taxonomy-wide caches
do_action( 'clean_term_cache', $ids, $taxonomy, $clean_taxonomy );
wp_cache_set_terms_last_changed();
* Cleans the caches for a taxonomy.
* @param string $taxonomy Taxonomy slug.
function clean_taxonomy_cache( $taxonomy ) {
wp_cache_delete( 'all_ids', $taxonomy );
wp_cache_delete( 'get', $taxonomy );
wp_cache_set_terms_last_changed();
// Regenerate cached hierarchy.
delete_option( "{$taxonomy}_children" );
_get_term_hierarchy( $taxonomy );
* Fires after a taxonomy's caches have been cleaned.
* @param string $taxonomy Taxonomy slug.
do_action( 'clean_taxonomy_cache', $taxonomy );
* Retrieves the cached term objects for the given object ID.
* Upstream functions (like get_the_terms() and is_object_in_term()) are
* responsible for populating the object-term relationship cache. The current
* function only fetches relationship data that is already in the cache.
* @since 4.7.0 Returns a `WP_Error` object if there's an error with
* any of the matched terms.
* @param int $id Term object ID, for example a post, comment, or user ID.
* @param string $taxonomy Taxonomy name.
* @return bool|WP_Term[]|WP_Error Array of `WP_Term` objects, if cached.
* False if cache is empty for `$taxonomy` and `$id`.
* WP_Error if get_term() returns an error object for any term.
function get_object_term_cache( $id, $taxonomy ) {
$_term_ids = wp_cache_get( $id, "{$taxonomy}_relationships" );
// We leave the priming of relationship caches to upstream functions.
if ( false === $_term_ids ) {
// Backward compatibility for if a plugin is putting objects into the cache, rather than IDs.
foreach ( $_term_ids as $term_id ) {
if ( is_numeric( $term_id ) ) {
$term_ids[] = (int) $term_id;
} elseif ( isset( $term_id->term_id ) ) {
$term_ids[] = (int) $term_id->term_id;
// Fill the term objects.
_prime_term_caches( $term_ids );
foreach ( $term_ids as $term_id ) {
$term = get_term( $term_id, $taxonomy );
if ( is_wp_error( $term ) ) {
* Updates the cache for the given term object ID(s).
* Note: Due to performance concerns, great care should be taken to only update
* term caches when necessary. Processing time can increase exponentially depending
* on both the number of passed term IDs and the number of taxonomies those terms
* Caches will only be updated for terms not already cached.
* @param string|int[] $object_ids Comma-separated list or array of term object IDs.
* @param string|string[] $object_type The taxonomy object type or array of the same.
* @return void|false Void on success or if the `$object_ids` parameter is empty,
* false if all of the terms in `$object_ids` are already cached.
function update_object_term_cache( $object_ids, $object_type ) {
if ( empty( $object_ids ) ) {
if ( ! is_array( $object_ids ) ) {
$object_ids = explode( ',', $object_ids );
$object_ids = array_map( 'intval', $object_ids );
$non_cached_ids = array();
$taxonomies = get_object_taxonomies( $object_type );
foreach ( $taxonomies as $taxonomy ) {
$cache_values = wp_cache_get_multiple( (array) $object_ids, "{$taxonomy}_relationships" );
foreach ( $cache_values as $id => $value ) {
if ( false === $value ) {
if ( empty( $non_cached_ids ) ) {
$non_cached_ids = array_unique( $non_cached_ids );
$terms = wp_get_object_terms(
'fields' => 'all_with_object_id',
'update_term_meta_cache' => false,
foreach ( (array) $terms as $term ) {
$object_terms[ $term->object_id ][ $term->taxonomy ][] = $term->term_id;
foreach ( $non_cached_ids as $id ) {
foreach ( $taxonomies as $taxonomy ) {
if ( ! isset( $object_terms[ $id ][ $taxonomy ] ) ) {
if ( ! isset( $object_terms[ $id ] ) ) {
$object_terms[ $id ] = array();
$object_terms[ $id ][ $taxonomy ] = array();
foreach ( $object_terms as $id => $value ) {
foreach ( $value as $taxonomy => $terms ) {
$cache_values[ $taxonomy ][ $id ] = $terms;
foreach ( $cache_values as $taxonomy => $data ) {
wp_cache_add_multiple( $data, "{$taxonomy}_relationships" );
* Updates terms in cache.
* @param WP_Term[] $terms Array of term objects to change.
* @param string $taxonomy Not used.
function update_term_cache( $terms, $taxonomy = '' ) {
foreach ( (array) $terms as $term ) {
// Create a copy in case the array was passed by reference.
// Object ID should not be cached.
unset( $_term->object_id );
$data[ $term->term_id ] = $_term;
wp_cache_add_multiple( $data, 'terms' );
* Retrieves children of taxonomy as term IDs.
* @param string $taxonomy Taxonomy name.
* @return array Empty if $taxonomy isn't hierarchical or returns children as term IDs.
function _get_term_hierarchy( $taxonomy ) {
if ( ! is_taxonomy_hierarchical( $taxonomy ) ) {
$children = get_option( "{$taxonomy}_children" );
if ( is_array( $children ) ) {
'fields' => 'id=>parent',
'update_term_meta_cache' => false,
foreach ( $terms as $term_id => $parent ) {
$children[ $parent ][] = $term_id;
update_option( "{$taxonomy}_children", $children );
* Gets the subset of $terms that are descendants of $term_id.
* If `$terms` is an array of objects, then _get_term_children() returns an array of objects.
* If `$terms` is an array of IDs, then _get_term_children() returns an array of IDs.
* @param int $term_id The ancestor term: all returned terms should be descendants of `$term_id`.
* @param array $terms The set of terms - either an array of term objects or term IDs - from which those that
* are descendants of $term_id will be chosen.
* @param string $taxonomy The taxonomy which determines the hierarchy of the terms.
* @param array $ancestors Optional. Term ancestors that have already been identified. Passed by reference, to keep
* track of found terms when recursing the hierarchy. The array of located ancestors is used
* to prevent infinite recursion loops. For performance, `term_ids` are used as array keys,
* with 1 as value. Default empty array.
* @return array|WP_Error The subset of $terms that are descendants of $term_id.
function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) {
$term_id = (int) $term_id;
$has_children = _get_term_hierarchy( $taxonomy );
if ( $term_id && ! isset( $has_children[ $term_id ] ) ) {
// Include the term itself in the ancestors array, so we can properly detect when a loop has occurred.
if ( empty( $ancestors ) ) {
$ancestors[ $term_id ] = 1;
foreach ( (array) $terms as $term ) {
if ( ! is_object( $term ) ) {
$term = get_term( $term, $taxonomy );
if ( is_wp_error( $term ) ) {
// Don't recurse if we've already identified the term as a child - this indicates a loop.
if ( isset( $ancestors[ $term->term_id ] ) ) {
if ( (int) $term->parent === $term_id ) {
$term_list[] = $term->term_id;
if ( ! isset( $has_children[ $term->term_id ] ) ) {
$ancestors[ $term->term_id ] = 1;
$children = _get_term_children( $term->term_id, $terms, $taxonomy, $ancestors );
$term_list = array_merge( $term_list, $children );