Heartbeat API oEmbed

By default running content through the_content filter automatically checks for oEmbed content. However when returning data through heartbeat_received the filter for oEmbed doesn’t seem to work.

For example –

function test_heartbeat_received( $response, $data ) {
    if( $data['test_heartbeat'] == 'test' ) {
        $content = "https://twitter.com/WordPress/status/456502643738030080";

        // Doesn't work
        global $wp_embed;
        $content = $wp_embed->autoembed( $content );
        $response['test_heartbeat'] = $content;

        // Also doesn't work
        $response['test_heartbeat'] = apply_filters( 'the_content', $content );
    }
    return $response;
}
add_filter( 'heartbeat_received', 'test_heartbeat_received', 10, 2 );
add_filter( 'heartbeat_nopriv_received', 'test_heartbeat_received', 10, 2 );

Doing the exact same without using Heartbeat seems to work. The content filter is being applied as the formatting exists, just without oEmbed.

Any suggestions?

Thanks!

2 Answers
2

The problem:

The reason why this isn’t working, is this part of the WP_Embed::shortcode() method:

 if( $post_ID ) {
    .... cut ...

    // Use oEmbed to get the HTML
    $html = wp_oembed_get( $url, $attr );

    ... cut ...
 }

When trying to autoembed with the Heartbeat API the $post_ID is null, so wp_oembed_get() is never activated.

No Caching:

When you autoembed the Twitter link in the post editor, for a given $post_ID, the oembed HTML is cached in the post meta table under a key like this: _oembed_7bc759c5dcea2e4b77c939fc109996fb and a value like this:

<blockquote class="twitter-tweet" width="550">
   <p>
      WordPress 3.9 “Smith” is now available with a smoother media editing experience, 
      live widget previews, and more: 
      <a href="http://t.co/mEbgUFdpyG">http://t.co/mEbgUFdpyG</a>
   </p>
   &mdash; WordPress (@WordPress) 
   <a href="https://twitter.com/WordPress/statuses/456502643738030080">April 16, 2014</a>  
</blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Each oembed link gets it’s own row in the post meta table, well if it’s not part of the default oembed handlers.

This caching mechanism is skipped when the $post_ID is missing, so you might want to consider some caching for your setup.

Possible workarounds:

i) You need to take all the matches of '|^\s*(https?://[^\s"]+)\s*$|im', within your string, and run it through the wp_oembed_get() function and replace the links from the original string.

ii) We could also associate it with a given post, within the test_heartbeat_received callback:

global $wp_embed, $post;
$post = get_post( 3147 ); // Post ID: 3147

$content = $wp_embed->autoembed( $content );
$response['test_heartbeat'] = $content;

to get around the missing $post_ID part and use the default caching for that post. You just have to remember that the oembed cache clears when you update that post.

If you try for example two Twitter links, with the above method:

$content = "
    <div>
        
    </div>
    <div> 
         
    </div>
    ";

then after the autoembed process, you get two rows in the post meta table, assigned to post_id: 3147:

oembed rows

Leave a Comment