* oEmbed API: Top-level oEmbed functionality
* Registers an embed handler.
* Should probably only be used for sites that do not support oEmbed.
* @global WP_Embed $wp_embed
* @param string $id An internal ID/name for the handler. Needs to be unique.
* @param string $regex The regex that will be used to see if this handler should be used for a URL.
* @param callable $callback The callback function that will be called if the regex is matched.
* @param int $priority Optional. Used to specify the order in which the registered handlers will
function wp_embed_register_handler( $id, $regex, $callback, $priority = 10 ) {
$wp_embed->register_handler( $id, $regex, $callback, $priority );
* Unregisters a previously-registered embed handler.
* @global WP_Embed $wp_embed
* @param string $id The handler ID that should be removed.
* @param int $priority Optional. The priority of the handler to be removed. Default 10.
function wp_embed_unregister_handler( $id, $priority = 10 ) {
$wp_embed->unregister_handler( $id, $priority );
* Creates default array of embed parameters.
* The width defaults to the content width as specified by the theme. If the
* theme does not specify a content width, then 500px is used.
* The default height is 1.5 times the width, or 1000px, whichever is smaller.
* The {@see 'embed_defaults'} filter can be used to adjust either of these values.
* @global int $content_width
* @param string $url Optional. The URL that should be embedded. Default empty.
* Indexed array of the embed width and height in pixels.
* @type int $0 The embed width.
* @type int $1 The embed height.
function wp_embed_defaults( $url = '' ) {
if ( ! empty( $GLOBALS['content_width'] ) ) {
$width = (int) $GLOBALS['content_width'];
$height = min( ceil( $width * 1.5 ), 1000 );
* Filters the default array of embed dimensions.
* Indexed array of the embed width and height in pixels.
* @type int $0 The embed width.
* @type int $1 The embed height.
* @param string $url The URL that should be embedded.
return apply_filters( 'embed_defaults', compact( 'width', 'height' ), $url );
* Attempts to fetch the embed HTML for a provided URL using oEmbed.
* @param string $url The URL that should be embedded.
* @param array|string $args {
* Optional. Additional arguments for retrieving embed HTML. Default empty.
* @type int|string $width Optional. The `maxwidth` value passed to the provider URL.
* @type int|string $height Optional. The `maxheight` value passed to the provider URL.
* @type bool $discover Optional. Determines whether to attempt to discover link tags
* at the given URL for an oEmbed provider when the provider URL
* is not found in the built-in providers list. Default true.
* @return string|false The embed HTML on success, false on failure.
function wp_oembed_get( $url, $args = '' ) {
$oembed = _wp_oembed_get_object();
return $oembed->get_html( $url, $args );
* Returns the initialized WP_oEmbed object.
* @return WP_oEmbed object.
function _wp_oembed_get_object() {
static $wp_oembed = null;
if ( is_null( $wp_oembed ) ) {
$wp_oembed = new WP_oEmbed();
* Adds a URL format and oEmbed provider URL pair.
* @param string $format The format of URL that this provider can handle. You can use asterisks
* @param string $provider The URL to the oEmbed provider.
* @param bool $regex Optional. Whether the `$format` parameter is in a RegEx format. Default false.
function wp_oembed_add_provider( $format, $provider, $regex = false ) {
if ( did_action( 'plugins_loaded' ) ) {
$oembed = _wp_oembed_get_object();
$oembed->providers[ $format ] = array( $provider, $regex );
WP_oEmbed::_add_provider_early( $format, $provider, $regex );
* Removes an oEmbed provider.
* @param string $format The URL format for the oEmbed provider to remove.
* @return bool Was the provider removed successfully?
function wp_oembed_remove_provider( $format ) {
if ( did_action( 'plugins_loaded' ) ) {
$oembed = _wp_oembed_get_object();
if ( isset( $oembed->providers[ $format ] ) ) {
unset( $oembed->providers[ $format ] );
WP_oEmbed::_remove_provider_early( $format );
* Determines if default embed handlers should be loaded.
* Checks to make sure that the embeds library hasn't already been loaded. If
* it hasn't, then it will load the embeds library.
* @see wp_embed_register_handler()
function wp_maybe_load_embeds() {
* Filters whether to load the default embed handlers.
* Returning a falsey value will prevent loading the default embed handlers.
* @param bool $maybe_load_embeds Whether to load the embeds library. Default true.
if ( ! apply_filters( 'load_default_embeds', true ) ) {
wp_embed_register_handler( 'youtube_embed_url', '#https?://(www.)?youtube\.com/(?:v|embed)/([^/]+)#i', 'wp_embed_handler_youtube' );
* Filters the audio embed handler callback.
* @param callable $handler Audio embed handler callback function.
wp_embed_register_handler( 'audio', '#^https?://.+?\.(' . implode( '|', wp_get_audio_extensions() ) . ')$#i', apply_filters( 'wp_audio_embed_handler', 'wp_embed_handler_audio' ), 9999 );
* Filters the video embed handler callback.
* @param callable $handler Video embed handler callback function.
wp_embed_register_handler( 'video', '#^https?://.+?\.(' . implode( '|', wp_get_video_extensions() ) . ')$#i', apply_filters( 'wp_video_embed_handler', 'wp_embed_handler_video' ), 9999 );
* YouTube iframe embed handler callback.
* Catches YouTube iframe embed URLs that are not parsable by oEmbed but can be translated into a URL that is.
* @global WP_Embed $wp_embed
* @param array $matches The RegEx matches from the provided regex when calling
* wp_embed_register_handler().
* @param array $attr Embed attributes.
* @param string $url The original URL that was matched by the regex.
* @param array $rawattr The original unmodified attributes.
* @return string The embed HTML.
function wp_embed_handler_youtube( $matches, $attr, $url, $rawattr ) {
$embed = $wp_embed->autoembed( sprintf( 'https://youtube.com/watch?v=%s', urlencode( $matches[2] ) ) );
* Filters the YoutTube embed output.
* @see wp_embed_handler_youtube()
* @param string $embed YouTube embed output.
* @param array $attr An array of embed attributes.
* @param string $url The original URL that was matched by the regex.
* @param array $rawattr The original unmodified attributes.
return apply_filters( 'wp_embed_handler_youtube', $embed, $attr, $url, $rawattr );
* Audio embed handler callback.
* @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
* @param array $attr Embed attributes.
* @param string $url The original URL that was matched by the regex.
* @param array $rawattr The original unmodified attributes.
* @return string The embed HTML.
function wp_embed_handler_audio( $matches, $attr, $url, $rawattr ) {
$audio = sprintf( '[audio src="%s" /]', esc_url( $url ) );
* Filters the audio embed output.
* @param string $audio Audio embed output.
* @param array $attr An array of embed attributes.
* @param string $url The original URL that was matched by the regex.
* @param array $rawattr The original unmodified attributes.
return apply_filters( 'wp_embed_handler_audio', $audio, $attr, $url, $rawattr );
* Video embed handler callback.
* @param array $matches The RegEx matches from the provided regex when calling wp_embed_register_handler().
* @param array $attr Embed attributes.
* @param string $url The original URL that was matched by the regex.
* @param array $rawattr The original unmodified attributes.
* @return string The embed HTML.
function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) {
if ( ! empty( $rawattr['width'] ) && ! empty( $rawattr['height'] ) ) {
$dimensions .= sprintf( 'width="%d" ', (int) $rawattr['width'] );
$dimensions .= sprintf( 'height="%d" ', (int) $rawattr['height'] );
$video = sprintf( '[video %s src="%s" /]', $dimensions, esc_url( $url ) );
* Filters the video embed output.
* @param string $video Video embed output.
* @param array $attr An array of embed attributes.
* @param string $url The original URL that was matched by the regex.
* @param array $rawattr The original unmodified attributes.
return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr );
* Registers the oEmbed REST API route.
function wp_oembed_register_route() {
$controller = new WP_oEmbed_Controller();
$controller->register_routes();
* Adds oEmbed discovery links in the website <head>.
function wp_oembed_add_discovery_links() {
$output .= '<link rel="alternate" type="application/json+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink() ) ) . '" />' . "\n";
if ( class_exists( 'SimpleXMLElement' ) ) {
$output .= '<link rel="alternate" type="text/xml+oembed" href="' . esc_url( get_oembed_endpoint_url( get_permalink(), 'xml' ) ) . '" />' . "\n";
* Filters the oEmbed discovery links HTML.
* @param string $output HTML of the discovery links.
echo apply_filters( 'oembed_discovery_links', $output );
* Adds the necessary JavaScript to communicate with the embedded iframes.
function wp_oembed_add_host_js() {
wp_enqueue_script( 'wp-embed' );
* Retrieves the URL to embed a specific post in an iframe.
* @param int|WP_Post $post Optional. Post ID or object. Defaults to the current post.
* @return string|false The post embed URL on success, false if the post doesn't exist.
function get_post_embed_url( $post = null ) {
$post = get_post( $post );
$embed_url = trailingslashit( get_permalink( $post ) ) . user_trailingslashit( 'embed' );
$path_conflict = get_page_by_path( str_replace( home_url(), '', $embed_url ), OBJECT, get_post_types( array( 'public' => true ) ) );
if ( ! get_option( 'permalink_structure' ) || $path_conflict ) {
$embed_url = add_query_arg( array( 'embed' => 'true' ), get_permalink( $post ) );
* Filters the URL to embed a specific post.
* @param string $embed_url The post embed URL.
* @param WP_Post $post The corresponding post object.
return esc_url_raw( apply_filters( 'post_embed_url', $embed_url, $post ) );
* Retrieves the oEmbed endpoint URL for a given permalink.
* Pass an empty string as the first argument to get the endpoint base URL.
* @param string $permalink Optional. The permalink used for the `url` query arg. Default empty.
* @param string $format Optional. The requested response format. Default 'json'.
* @return string The oEmbed endpoint URL.
function get_oembed_endpoint_url( $permalink = '', $format = 'json' ) {
$url = rest_url( 'oembed/1.0/embed' );
if ( '' !== $permalink ) {
'url' => urlencode( $permalink ),
'format' => ( 'json' !== $format ) ? $format : false,
* Filters the oEmbed endpoint URL.
* @param string $url The URL to the oEmbed endpoint.
* @param string $permalink The permalink used for the `url` query arg.
* @param string $format The requested response format.
return apply_filters( 'oembed_endpoint_url', $url, $permalink, $format );
* Retrieves the embed code for a specific post.
* @param int $width The width for the response.
* @param int $height The height for the response.
* @param int|WP_Post $post Optional. Post ID or object. Default is global `$post`.
* @return string|false Embed code on success, false if post doesn't exist.
function get_post_embed_html( $width, $height, $post = null ) {
$post = get_post( $post );
$embed_url = get_post_embed_url( $post );
$output = '<blockquote class="wp-embedded-content"><a href="' . esc_url( get_permalink( $post ) ) . '">' . get_the_title( $post ) . "</a></blockquote>\n";
$output .= "<script type='text/javascript'>\n";
$output .= "<!--//--><![CDATA[//><!--\n";
$output .= file_get_contents( ABSPATH . WPINC . '/js/wp-embed.js' );
* If you're looking at a src version of this file, you'll see an "include"
* statement below. This is used by the `npm run build` process to directly
* include a minified version of wp-embed.js, instead of using the
* file_get_contents() method from above.
* If you're looking at a build version of this file, you'll see a string of
* minified JavaScript. If you need to debug it, please turn on SCRIPT_DEBUG
* and edit wp-embed.js directly.
/*! This file is auto-generated */
!function(d,l){"use strict";var e=!1,n=!1;if(l.querySelector)if(d.addEventListener)e=!0;if(d.wp=d.wp||{},!d.wp.receiveEmbedMessage)if(d.wp.receiveEmbedMessage=function(e){var t=e.data;if(t)if(t.secret||t.message||t.value)if(!/[^a-zA-Z0-9]/.test(t.secret)){for(var r,i,a,s=l.querySelectorAll('iframe[data-secret="'+t.secret+'"]'),n=l.querySelectorAll('blockquote[data-secret="'+t.secret+'"]'),o=new RegExp("^https?:$","i"),c=0;c<n.length;c++)n[c].style.display="none";for(c=0;c<s.length;c++)if(r=s[c],e.source===r.contentWindow){if(r.removeAttribute("style"),"height"===t.message){if(1e3<(a=parseInt(t.value,10)))a=1e3;else if(~~a<200)a=200;r.height=a}if("link"===t.message)if(i=l.createElement("a"),a=l.createElement("a"),i.href=r.getAttribute("src"),a.href=t.value,o.test(a.protocol))if(a.host===i.host)if(l.activeElement===r)d.top.location.href=t.value}}},e)d.addEventListener("message",d.wp.receiveEmbedMessage,!1),l.addEventListener("DOMContentLoaded",t,!1),d.addEventListener("load",t,!1);function t(){if(!n){n=!0;for(var e,t,r=-1!==navigator.appVersion.indexOf("MSIE 10"),i=!!navigator.userAgent.match(/Trident.*rv:11\./),a=l.querySelectorAll("iframe.wp-embedded-content"),s=0;s<a.length;s++){if(!(e=a[s]).getAttribute("data-secret"))t=Math.random().toString(36).substr(2,10),e.src+="#?secret="+t,e.setAttribute("data-secret",t);if(r||i)(t=e.cloneNode(!0)).removeAttribute("security"),e.parentNode.replaceChild(t,e)}}}}(window,document);
$output .= "\n//--><!]]>";
$output .= "\n</script>";
'<iframe sandbox="allow-scripts" security="restricted" src="%1$s" width="%2$d" height="%3$d" title="%4$s" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" class="wp-embedded-content"></iframe>',
/* translators: 1: Post title, 2: Site title. */
__( '“%1$s” — %2$s' ),
* Filters the embed HTML output for a given post.
* @param string $output The default iframe tag to display embedded content.
* @param WP_Post $post Current post object.
* @param int $width Width of the response.