I’m working on a web video service for agencies that I’ll be launching soon, and a feature I thought might be nice was to enable content to be embedded into web pages. Since WordPress 4.4, as long as you play by their rules, WordPress will support embedding of any compatible content.
How we got to now
When embedding videos from the likes of YouTube first became a thing, it involved pasting HTML code that was often very verbose. You had to use
object tags which involved multiple URLs and parameters. Now we use
iframes, effectively a window pointing to the embedded content. That only requires a little HTML which points to one resource; we let that resource figure out how to display the embedded content.
The trouble is, embedding
iframes means letting arbitrary and potentially dangerous code live within your CMS. WordPress mitigated against this by stripping out lots of HTML, and on WordPress.com, you’re even more restricted in the types of stuff you can add. Anything that looks like it might point to something malicious is removed, and in its place, we have oEmbed.
The idea of oEmbed is that you can turn a compatible URL into an
iframe on-the-fly, and only at the point of display. So to include an oEmbed resource, you use a shortcode (like
[oembed url="http://example.com/embedded-content"]) or in later versions of WordPress, just put the URL on its own line (so press Enter, paste in the URL of the video and press Enter again to continue writing). The CMS saves that code but then when you request the rendered page, it replaces that code with the embedded content.
But given how popular WordPress is, the developers were – and still are – reluctant to open the doors to let just anybody’s content become embeddable (regardless of whether you conformed to the oEmbed spec or not). You’d have to be a big enough player to contact WordPress and add your content to their whitelist (not every video, but your API address, which is what the CMS uses to figure out how to render your content). This is nice and secure, but fundamentally goes against the open, democratic nature of the web, so in version 4.4, they fixed that.
Additional to the API which turns a URL into an
iframe – it can be almost any arbitrary HTML by the way, but we’ll stick with
iframes since we’re talking video – content providers can add a
link tag to their web page’s metadata that basically says “this content supports oEmbed”. The idea being that, when a user types the URL to a video and hits Enter, the CMS requests that URL, looks for the tag, calls the API that’s been pointed to in that tag, and then caches the response so it can replace the video URL with the embed code. In WordPress’ case, it actually displays the
iframe directly in the WYSIWYG editor, so you can see what you’ve just embedded.
Providers like YouTube, Soundcloud and the like have never needed discovery to work with the big CMSs, because those big CMSs already whitelist a handful of providers. But now WordPress supports discovery – checking and heavily sanitising the HTML that is returned, lest it contain something dodgy – so anyone can embed their content.
The docs aren’t too clear on how your content is sanitised, but let me walk you through what I did, which has worked for me.
- Write an API endpoint that conforms as closely to the oEmbed spec as you can. I’m guessing WordPress prefers that you respond with JSON, but I’m unsure (that’s what I used anyway)
- Keep your
iframeHTML lean. You probably don’t want to add lots of styling to it… just go with
allowfulscreenif you want that. Make sure to use a width and height that respects the
maxheightparameters that form part of the oEmbed spec (in truth, I just supported
maxwidthand it works fine)
- In the HTML response that your
iframepoints to (the final leg of the journey, and where your video code actually lives), you need to add the following HTTP header:
X-Frame-Options: ALLOW-FROM *. This is really important, because it tells your browser that it’s OK to request the resource, if it lives on a different domain. You could, I suppose lock it down if you only wanted your content to be embeddable in certain places, but I doubt you’d want to do that.
There’s an oEmbed tester which may prove useful. I just did a bunch of trial and error, but if you’re pretty sure you’ve got it working and you want to double-check, that’s probably not a bad place to start.