X-Frame-Options and WordPress post embeds

WordPress 4.4 simplified the process of embedding WordPress content on other sites with the introduction of post embeds. From the feature’s announcement post:

WordPress has been operating as an oEmbed consumer for quite some time now, allowing users to easily embed content from other sites. Starting with version 4.4, WordPress becomes an oEmbed provider as well, allowing any oEmbed consumer to embed posts from WordPress sites.

The problem

As exciting as this feature is, it ran into an incompatibility with my server configuration. I’ve set the X-Frame-Options header to SAMEORIGIN near-universally within my nginx configuration, thereby blocking other sites from displaying my sites in frames; instead, my sites can only display their own content inside of frames. I’ve done so as a security measure against “clickjacking.” This header has no impact on my use of WordPress, nor on visitors’ interaction with my sites, but as I discovered, it breaks post embeds in an awkward way.

When another site tries to embed a post I’ve published, the X-Frame-Options: SAMEORIGIN header tells the browser to check that the domain hosting the original content matches that of the site hosting the embed. If the domains don’t match, the browser refuses to load the embedded URL. As I reported in Trac ticket #35894, the embed failure causes WordPress to display a blank space without any relevant information about the embedded post.

Broken post embed
Broken post embed

WordPress 4.5 will improve how it handles this situation, but I was also curious if there were any configuration changes I could make to improve this experience.

A solution

The first suggestion came from Gary Pendergast, Core Contributor and fellow Automattician, via the aforementioned Trac ticket:

Side note that may be relevant to your interests (if you’d like to maintain the SAMEORIGIN restriction whilst allowing embeds) – URLs intended to embedded in an iframe include an X-WP-embed: true header, which you can detect in nginx and remove the X-Frame-Options: SAMEORIGIN rule for that case.

I considered this approach, but quickly abandoned it as it requires significant modifications to my nginx configurations. Given how I’ve structured them (in part to ensure header consistency), the X-Frame-Options header is set in several locations where I can’t use an if statement to check for the X-WP-embed header. Instead, I would need to use an nginx map to specify a less-restrictive X-Frame-Options header. Frankly, I don’t care enough about supporting embeds to bother with this level of changes.

A simpler solution

Next I looked at how WordPress generates the post-embed markup, quickly learning that I could exclude the unsupported iframe with one line of code.

remove_filter( 'oembed_response_data', 'get_oembed_response_data_rich', 10, 4 );

Thanks to the above, WordPress returns the post embed as a simple title and link, rather than a rich snippet that will fail to load.

There is but one minor difference between the markup the above modification generates and what WordPress would otherwise produce as a fallback: the fallback is wrapped in a blockquote tag. While I could add the blockquote myself via the oembed_response_data filter, again, I just don’t care enough; access logs reflect that I’m the only one requesting embeds, and that was just to test what I’ve written about here.

Leave a Reply