3

I have a page that is calling in the content from other posts (a custom post type, specifically) and inserting it into the page. It all works great, but I'm losing the functionality of WordPress taking youtube (and other embeddable links) and automatically inserting the embedded video.

I've tried apply_filters( 'the_content', $my_content );, but I think that filter isn't even available via admin-ajax.php.

I of course already call do_shortcode( $my_content ), but what can I use, in similar fashion, to get the embeddable links to embed?

UPDATE:

In response to bonger's answer, I've updated the code to this:

wpautop( do_shortcode( $wp_embed->run_shortcode( $my_content ) ) )

($wp_embed was globalized before this line of code)

Note that the wpautop() and do_shortcode() are totally irrelevant to this issue, but I put them in here just for completeness. This code is outputting the youtube url as a link to the youtube video, but not embedding the video in the page.

  • I globalized $post and $wp_embed objects in my ajax callback, and then in my content I added do_shortcode( $wp_embed->autoembed( get_the_content( '' ) ) ). This did the trick. Thanks for the pointers :) – dingo_d Nov 28 '16 at 8:45
4

I think the solution is amazingly simple here:

You're just missing a single line of code in your ajax callback, namely:

global $post;

where I assume you're using:

$post = get_post( $post_id );

The reason is that there's a global post check in the WP_Embed::shortcode() method.

More details in my answer here.

  • Whoah, that did it. Simply globalizing $post. Uncanny. Thanks so much! – Joel Worsham Jan 25 '15 at 16:54
  • 1
    Glad to hear it worked for you - it's a weird solution, I know ;-) – birgire Jan 26 '15 at 15:03
  • I was just about to jump out the window! Thanks, you saved my life :) – Darren Cooney Feb 15 '17 at 22:07
  • @DarrenCooney thanks for commenting, I'm glad to hear it helped ;-) – birgire Feb 15 '17 at 22:55
0

I think there's some weirdness with [embed] shortcodes where you have to run them through WP_Embed::run_shortcode(), eg

    if ( strpos( $my_content, '[embed]' ) !== false ) {
        global $wp_embed;
        $my_content = $wp_embed->run_shortcode( $my_content );
    }
    $my_content = do_shortcode( $my_content );

Update: however as no providers are registered this won't work as you noticed(!), so I think the easiest thing to do is to call wp_oembed_get() direct:

            $args = array();
            global $content_width;
            $args['width'] = $content_width ? $content_width : 300;
            // Simplistic parse - look for a url on its own line.
            $lines = explode( "\n", $my_content );
            foreach ( $lines as $i => $line ) {
                $line = trim( $line );
                if ( stripos( $line, 'http' ) === 0 ) {
                    if ( $oembed_html = wp_oembed_get( $line, $args ) ) {
                        $lines[$i] = $oembed_html;
                    }
                }
            }
            $my_content = implode( "\n", $lines );

You may want to use transients to avoid repeated calls to the provider - here's a version of stuff I use:

// Wrapper around wp_oembed_get() to use transients.
function wpse175427_oembed_get( $url, $args ) {
    global $wpse175427_oembed_transient_expiration;
    if ( $wpse175427_oembed_transient_expiration ) {
        $transient_key = md5( $url . '_' . wpse175427_reduce_array( $args ) );
        if ( $oembed_html = get_transient( $transient_key ) ) {
            return $oembed_html;
        }
    }

    //add_filter( 'oembed_fetch_url', 'wpse175427_oembed_fetch_url', 10, 3 );
    //add_filter( 'oembed_result', 'wpse175427_oembed_result', 10, 3 );
    if ( $oembed_html = wp_oembed_get( $url, $args ) ) {
        if ( $wpse175427_oembed_transient_expiration ) {
            set_transient( $transient_key, $oembed_html, $wpse175427_oembed_transient_expiration );
        }
        return $oembed_html;
    }
    return '';
}

// Helper to stringify args array (for transient key).
function wpse175427_reduce_array( $arr ) {
    $ret = array();
    foreach ( $arr as $key => $val ) {
        $ret[] = '`' . $key  . '`=`' . $val . '`';
    }
    return implode( ',', $ret );
}

Then set the global in your ajax callback, eg

            global $wpse175427_oembed_transient_expiration;
            $wpse175427_oembed_transient_expiration = DAY_IN_SECONDS;

and call wpse175427_oembed_get() instead of wp_oembed_get().

  • Hmmm, didn't seem to work. I also meant moreso for inline video links. Although I even attempted wrapping them in embed and then doing this. It seems to just be making it a link. – Joel Worsham Jan 21 '15 at 18:14
  • Okay none of the providers are registered. I'll update the answer with calling wp_oembed_get() directly... – bonger Jan 23 '15 at 1:24
  • 1
    I think you're making it more complex than it has to be, just declare $post as global in the ajax callback, where $post = get_post( $post_id ), and you're done ;-) – birgire Jan 24 '15 at 15:30
  • @birgire Ah, excellent! – bonger Jan 24 '15 at 15:47
-1

try to use get_the_content(), like:

$my_content = get_the_content();
$my_content = apply_filters('the_content', $my_content);
  • Getting the content is not the issue. I already have the content. Also, I've already stated that filters don't work via AJAX. – Joel Worsham Jan 21 '15 at 18:09

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.