5

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 :)

6

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 
             && ! do_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-cleanoing
            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( 1 === 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 '15 at 13:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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