How can I clear oEmbed caches for YouTube on posts as they are loaded

How to trigger an oembed cache regeneration

The default cache time is 24 hours and we can adjust it with the oembed_ttl filter.

But as you’ve noticed, expired cache is not enough to trigger a cache regeneration.

The reason is this line in the WP_Embed class:

if ( $this->usecache || $cached_recently ) {

so to trigger a regeneration, we need both expired cache and the usecache property of the $wp_embed object to be false.

When we save a post, we also do an ajax call to wp_ajax_oembed_cache() that runs the WP_Embed::cache_oembed() method. This method sets the usecache property temporarly to false.

Example #1

We can force a cache regeneration for an expired cache with:

add_action( 'template_redirect', function()
{    
    if( is_single() )
        $GLOBALS['wp_embed']->cache_oembed( get_queried_object_id() );  
});

and we can further adjust the expire time to an hour with:

add_filter( 'oembed_ttl', function( $ttl )
{
    return HOUR_IN_SECONDS; // Adjust to your needs
} );

Note that we might experience a delay when loading the single posts, because of the cache regeneration. An ajax call might be a workaround. With this approach, the cache will always be ready for re-generation, when it expires. In the next example we try to address that by refreshing it only once.

Example #2

Here’s another approach on how to refresh the oEmbed HTML, on single post loads, but only once.

We set a fixed recache time (current) and when a single post is loaded, we compare it to the time the oEmbed HTML was last cached.

If the last cache time is before the recache time, then we need to regenerate it.

add_filter( 'oembed_ttl', function( $ttl, $url, $attr, $post_ID )
{
    // Only do this on single posts
    if( is_single() )
    {
        // Oembeds cached before this time, will be recached:
        $recache_time="2015-09-23 23:26:00";     // <-- Set this to the current time.

        // Get the time when oEmbed HTML was last cached (based on the WP_Embed class)
        $key_suffix    = md5( $url . serialize( $attr ) );
        $cachekey_time="_oembed_time_" . $key_suffix;
        $cache_time    = get_post_meta( $post_ID, $cachekey_time, true );

        // Get the cached HTML 
        $cachekey      = '_oembed_' . $key_suffix;
        $cache_html    = get_post_meta( $post_ID, $cachekey, true );

        // Check if we need to regenerate the oEmbed HTML:
        if(     
                $cache_time < strtotime( $recache_time )     // cache time check
             && false !== strpos( $cache_html, 'youtube' )   // contains "youtube" stuff 
             && ! did_action( 'wpse_do_cleanup' )             // let's just run this once 
             && 1 === $GLOBALS['wp_embed']->usecache
        ) {
            // What we need to skip the oembed cache part
            $GLOBALS['wp_embed']->usecache = 0; 
            $ttl = 0;               
            // House-cleaning
            do_action( 'wpse_do_cleanup' );
        }
    }
    return $ttl;
}, 10, 4 );

and then we might need this one too:

// Set the usecache attribute back to 1.
add_filter( 'embed_oembed_discover', function( $discover )
{
    if( did_action( 'wpse_do_cleanup' ) )
        $GLOBALS['wp_embed']->usecache = 1;
    return $discover;
} );

Hopefully you can adjust this further to your needs.

Leave a Comment