WordPress oEmbed is a really cool feature, which allows you to embed media from a supported oEmbed provider simply by adding the URL to that media on a line of its own. If you already understand oEmbed as a user, skip a head to the section How WordPress oEmbeds Work.
Example oEmbed
For example, if you put the following on its own line in WordPress
https://www.youtube.com/watch?v=cSj-etJL3nI
WordPress automatically replaces this with the actual video.
WordPress oEmbed in the Text Editor
WordPress Rendered oEmbed in the WYSIWYG Editor
If you add one of these oEmbed URLs when you’re using the WYSIWYG editor, you’ll see the video appear right within your editor.
Which Media Sites Can I Use for oEmbeds?
Twitter, YouTube, Vimeo, and Instagram are just some of the media providers supported.
See the full list of WordPress oEmbed supported sites.
How WordPress oEmbeds Work
WordPress analyzes the URL (e.g. https://www.youtube.com/watch?v=cSj-etJL3nI
) to determine, which supported media provider it came from (in this case YouTube) and then makes an API call to the URL that corresponds to that provider (in the case of YouTube, calls are made to http://www.youtube.com/oembed
) with additional parameters like what piece of media you want.
In the case of the example above, WordPress calls https://www.youtube.com/oembed?maxwidth=500&maxheight=750&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DcSj-etJL3nI&format=json and uses that information to create the markup to embed the video.
WordPress Caches oEmbed Results
Adding a call to a remote URL every time you load a page is a bad idea and will slow down your page significantly. The good news is WordPress has you covered and stores the resulting markup in post meta so the API call doesn’t have to occur each time.
You may be asking, “Why store the resulting markup as post meta? Wouldn’t a transient make more sense?” Post meta was chosen because the oEmbed markup should never be deleted based on being expired. If the markup is over one day old and the page is loaded on the backend, then the markup is updated (but if the lookup fails, the last good markup is not replaced). The markup is never updated when the page is loaded on the front-end. This behavior differs greatly from a transient, which expires and gets deleted automatically. See Mark Jaquith’s notes on how oEmbed caching works.
oEmbed Outside the Editor
Sometimes you want to embed media outside the editor (e.g. I recently did this because the content was displayed in multiple columns with CSS but the video appeared at the end and spanned all the columns). In this case, the media URL can be stored as a post meta value and the media URL can be programmatically changed into the markup for embedding.
Do NOT Use wp_oembed_get() without Caching
I’ve seen a lot of recommendations online to use wp_oembed_get()
in this situation. Using wp_oembed_get()
will make the call to the correct provider endpoint and render the proper markup to add the media to your page, however it will not cache the result. This means that every time your page attempts to load, WordPress will make an HTTP request to the media provider, which will prevent the page loading until the result is returned.
You can see the HTTP call being made each time the page loads if you run the Query Monitor plugin. You do not want to make an HTTP call every time your page loads.
How to Cache oEmbeds
Single Pages or Posts
If you are going to be displaying the video in a way that there is a single post ID associated with it, which should be the case if you’re using post meta to store the URL, you can use the __global__ $wp_embed->shortcode()
method.
e.g.
global $wp_embed;
$video_url = 'https://youtu.be/cSj-etJL3nI';
echo $wp_embed->shortcode( array(), $video_url );
Not on a Single Page or Posts
If you are loading an oEmbed video in an area where there is not a single post ID associated with it (e.g. in the header, footer, archive page, search results page, or 404 page) you’ll need to cache the result yourself. How this is handled will have a lot to do with where the video URL is coming from.
I imagine the most likely scenario is you’re storing it in a WordPress database option, in which case I’d probably add some code when the option is saved that makes the wp_oembed_get()
call and stores the result in another option. I haven’t actually had this come up on any of my projects (but hopefully these notes will help me if I do).
Image Credit
Image Modified from original by Cory Doctorow
Wow, extremely useful post. Thanks Sal! I didn’t realize the embed was making an external request each time.
Thanks. This is a great article on using WordPress as a oembed client. I’d be interested to know more about how to customize my site when it is used as an oembed provider. i.e. what does my content look like on other sites that embed it. Would you have any tips on that?
Thanks,
Ben
Hi Ben,
I haven’t done any work with creating an oEmbed provider, however I have noticed the html returned from the YouTube oEmbed endpoint is an iframe
Using an iframe would help you isolate the styles regardless of where the content is loaded, so that would be the first avenue I’d explore. I’d love to hear how it all works out.
Thanks for the super fast response, Sal,
I’m not following the connection. I’m probably not explaining myself properly. Let me try again with some more details.
I noticed that when I embed content from one of my sites on another site (in this case linkedin.com) the wrong image is shown. I’d like to be able to customize what the oembed of my site looks like but I can’t find any docs on that so not sure where to start poking around in the code to fix it. All the articles about oembed and wordpress seem to be like the one above and are only about embedding content from other sites (like your example of youtube) into wp sites.
Any idea where to start when customizing oembed going the other way?
Thanks,
Ben
Hi Ben,
In my experience, sites that display a preview (e.g. LinkedIn, Facebook, Twitter) use custom meta tags on the webpage rather than using this oEmbed functionality. Here are a list of some resources:
Thanks Sal, was using
wp_oembed_get()
in a custom plugin and noticed the constant Twitter API calls.Leveraging cache using
$wp_embed
is a useful tip !Thanks !
Still relevant in 2019. Very useful post, thank you Sal.
Thanks Sal. I would like to only allow certain oEmbeds so that authors are only able to include oEmbeds from a restricted list of oEmbed providers. What would be the best way to achieve this?
Hi Robby,
Off the top of my head, I don’t know how to do this. I do know there is a way to add additional oEmbed providers, so I’m guessing you could remove all of the oEmbed providers except the ones you want to permit.
It’s still the case that WP just does not cache oembeds that are not associated with a post?
Do you know how to detect if an oembed video got cached or not? When using the $wp_embed->shortcode method I would like to detect after if I need to cache the result manually or not.
I think its a really big flaw in WP if caching still is just not done in certain situations. I saw on that linked trak issue or another one that someone suggested to store them all on the metadata of some invisible “post” in the database. That seems a simple but perfectly fine solution to me but from what I read this has not happened yet. There should just be an internal post that holds all the oembed caches that can not be cached regularly.
Also, the post_id is actually AFAIK already available on single posts b4 entering the_loop so I guess this could mean that oembeds on single pages are even cached when in the header/footer or anywhere outside of the_content. If true the issue still remains for embeds in archive pages. What about text widgets with [[embed]] shortcodes? Are they cached?
Also WP has a video Widget and things, I am guessing that oembed is cached there as well, does a Widget is its own ‘post’ internally? Will look into the code more …