I have a site with tons of posts hundreds/thousands of which have YouTube videos embedded. Most use the default [embed]youtube_url[embed] format and the actual embed code is stored in the oEmbed postmeta fields.

I switched the site to HTTPS and a new domain, and now the old videos don't show unless I resave the post. I don't want to resave every post for obvious reasons and I don't want to go into the database and blindly delete all of the oEmbed caches at once, which are the only other options I've found while searching.

What I want is a filter on the oEmbed system that will update the YouTube oEmbed caches as posts are actually loaded, basically just a way of invalidating the caches while the posts are being loaded.

Ideally it would only apply to YouTube embeds (though be open for re-use) and would let me check the date of the post to avoid refetching oEmbed output for posts created after the HTTPS switch.

Seems like this is something many of us need for many reasons, so hopefully there's an elegant way :)


1 Answer 1


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:
                $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.

  • 1
    Wow THANK YOU for all this work!!! Just wanted to say that right away while I work on using this :D
    – jerclarke
    Sep 24, 2015 at 13:55
  • I think I spotted 2 mistakes in this code. Whats ! do_action(). Should be ! did_action(). Also in the discover filter why specifically check for 1 === did_action()? This means it will file only when the action is fired once. It may fire more then once even if not intended for whatever reason. So it should also simply be did_action() or 0 !== did_action() if you want to be strict about it as its return 0 if the action was never fired. Is it even necessary to do the check for the action in the discover filter at all? Why not just (re)enabled the cache there no matter what? Jan 18, 2020 at 8:25
  • Why do this Example #2 in single pages only? The $post_ID gets passed to the oembed_ttl filter so it should work even on archive pages right? Many themes use full content archive pages, I do not see the point of the cache regen trigger to just single pages in case I am right. Jan 18, 2020 at 11:29
  • Found yet another stupid wrong check. 1 === $GLOBALS['wp_embed']->usecache how did you come up with this checks? After a hour of painful trail an error I find out that my $GLOBALS['wp_embed']->usecache actually contains a boolean true value! Jan 18, 2020 at 17:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.