WordPress.org

WordPress Developer Blog

Customize WordPress embeds to match your theme

Customize WordPress embeds to match your theme

Have you ever thought about customizing your WordPress embeds?

Not that there’s anything wrong with the defaults. WordPress gives you a neutral, adaptable design that fits seamlessly into almost any layout. This is why many leave the default unchanged.

However, with a little effort, you can make your embeds reflect your brand, match your site’s design, and even display extra information—beyond the title and excerpt.

In this article, you’ll see several ways to tailor both the look and content of your WordPress embeds. Let’s dive in!

What are embeds?

Embeds let you include external content in your posts, including videos, polls, social media posts, and even content from other WordPress sites.

The YouTube videos you see on different websites are almost certainly embeds, except for a few that use custom players. Likewise, just as you can include YouTube videos on your website, others can embed your WordPress posts on theirs.

If a service is supported, you can embed a resource simply by pasting a URL into the Embed Block. If it’s not, you’ll have to use the Custom HTML Block to insert the embed code. The embed code nearly always contains an iframe tag.

In both cases, the front-end displays an iframe pointing to a simplified, embed-friendly version of the content at the canonical URL.

For example, the canonical URL of this article is the one in your browser’s address bar. If you append /embed/ to the URL, you’ll see how this post looks when embedded.

Essentially, a WordPress /embed/ endpoint serves a slightly different view of the same post.

YouTube works the same way, where you have the main, canonical video URL, such as https://www.youtube.com/watch?v=KLybH5YvIPQ, and the embed version at https://www.youtube.com/embed/KLybH5YvIPQ. Both load the same video, but they use different templates.

A brief history of embeds in WordPress

Since version 2.9, WordPress has used the oEmbed protocol to make embedding content from various services easy. This functionality improved further in version 4.0 with the addition of live previews for embeds in the editor.

With version 4.4, WordPress became an oEmbed provider, allowing other sites to embed posts from WordPress. Version 4.5 further improved embed templating.

Version 5.0 introduced the Block Editor, which came with a dedicated Embed block. Since then, WordPress has continued to add and remove services and make behind-the-scenes tweaks.

The default view

Before you start customizing embeds, let’s break down the default layout.

The WordPress embed looks like a card component that renders the post’s title and excerpt in the main area.

On one side of the embed footer, you’ll find the site’s icon and name. If no site icon is set, the WordPress logo appears as a fallback.

On the other side, if discussions are enabled, the comment count appears alongside a share button. Clicking the share button opens an overlay containing the post’s URL and HTML embed code.

The excerpt is either one you added manually, or auto-generated. If it’s auto-generated, it’s limited by word count and followed by a “Continue reading” call to action.

If the post has a featured image, it can appear above the title as a large image or below it as a floated image, depending on the image’s aspect ratio.

Lastly, when a nonexistent URL is embedded, the embed displays a 404 not-found error with a relevant title and message.

Tweaking the styles

Now that you’ve seen the variety of ways WordPress renders embeds, let’s start adding some personality with custom styles.

First, create a dedicated CSS file, assets/css/embed.css, in your theme’s folder. Then enqueue the file using the enqueue_embed_scripts hook by adding the following code to your functions.php:

function devblog_embed_enqueue_style() {
	wp_enqueue_style(
		'devblog-embed',
		get_theme_file_uri( 'assets/css/embed.css' ),
		array( 'wp-embed-template' )
	);
}

add_action( 'enqueue_embed_scripts', 'devblog_embed_enqueue_style' );

If adding code to your theme’s functions.php file doesn’t fit your project, feel free to include it in a custom plugin or code snippet plugin that works best for you.

By specifying wp-embed-template as a dependency, you ensure your styles load after the defaults, making it easier to override them without resorting to excessive CSS specificity.

Now, add this code to the CSS file to subtly adjust the spacing and apply a soft background to the footer:

.wp-embed-featured-image.rectangular {
	margin: -25px -25px 25px;
}

/* This specificity is needed to overwrite the defaults. */
p.wp-embed-heading {
	/* CSS logical properties are not used by the default embed stylesheet. */
	margin-bottom: 10px;
}

.wp-embed-footer {
	margin: 25px -25px -25px;
	padding: 25px;
	background: #fafafa;
}

Use inline styles

If you only need to change one thing and prefer not to create a separate CSS file, you can use inline styles:

function devblog_embed_inline_style() {
	wp_add_inline_style(
		'wp-embed-template',
		<<<CSS
		.wp-embed-featured-image.rectangular {
			margin: -25px -25px 25px;
		}
		CSS
	);
}

add_action( 'embed_head', 'devblog_embed_inline_style' );

For inline styles, you must use the embed_head hook, because the enqueue_embed_scripts hook loads too late in the process.

Enforce consistent image format

Beyond adding your own styles, you can modify lots more. For instance, if you don’t want to display images in two different ways (above the title and floated), you can enforce a single option.

Suppose you want images to always appear above the title. You can override determined image shape using the embed_thumbnail_image_shape filter:

function devblog_embed_enforce_rectangular_image_shape() {
    return 'rectangular';
}

add_filter( 'embed_thumbnail_image_shape', 'devblog_embed_enforce_rectangular_image_shape' );

This change has a downside: square images that were previously floated may take up too much space, making your embed too tall. That’s why WordPress displays images in two ways by default.

You can address this by enforcing a specific image size for embeds. First, check whether you’ve already registered an appropriate image size (one that’s narrow in height).

If not, register a new image size and enforce it with the embed_thumbnail_image_size filter:

function devblog_register_embed_narrow_image_size() {
	add_image_size( 'devblog-embed-narrow', 640, 360, true );
}

add_action( 'after_setup_theme', 'devblog_register_embed_narrow_image_size' );

function devblog_embed_enforce_embed_narrow_thumbnail_image_size() {
	return 'devblog-embed-narrow';
}

add_filter( 'embed_thumbnail_image_size', 'devblog_embed_enforce_embed_narrow_thumbnail_image_size' );

When you register a new image size, you must regenerate the images, since WordPress by default doesn’t dynamically create them. You can regenerate the images with WP CLI or with a plugin.

Altering the excerpt conditionally

While WordPress provides filters for image size and shape, there isn’t a dedicated filter for every aspect. For example, there’s no embed-specific filter for the title or excerpt length.

However, you can shorten the excerpt specifically for embeds by using the excerpt_length filter along with the is_embed function:

function devblog_embed_shorter_excerpt_length( $length ) {
	return is_embed() ? 25 : $length;
}

add_filter( 'excerpt_length', 'devblog_embed_shorter_excerpt_length' );

This is a minor change, but it might be exactly what you need.

Remove or change the excerpt call to action

Besides adjusting the length of the excerpt, you can also remove the “Continue reading” call to action at the end. Because WordPress appends that CTA using a filter, you can remove it with one line of code:

remove_filter( 'excerpt_more', 'wp_embed_excerpt_more', 20 );

If you’d rather change the text instead of removing it, hook into excerpt_more and use the HTML API to set it to “Keep exploring”:

function devblog_embed_excerpt_call_to_action( $more_string ) {
	if ( ! is_embed() ) {
		return $more_string;
	}

	$processor = new WP_HTML_Tag_Processor( $more_string );

	if ( $processor->next_tag( 'a' ) ) {
		$processor->next_token();
		$processor->set_modifiable_text(
			__( 'Keep exploring', 'devblog' )
		);
	}

	return $processor->get_updated_html();
}

add_filter( 'excerpt_more', 'devblog_embed_excerpt_call_to_action', 21 );

Changing the site’s title

Another area you can customize is the site’s title and its logo.

Suppose you don’t have a logo for your personal blog and want to display the site title without the WordPress fallback logo. In that case, hook into embed_site_title_html:

function devblog_embed_only_site_title() {
	return sprintf(
		'<div class="wp-embed-site-title">%s</div>',
		esc_html( get_bloginfo( 'name' ) )
	);
}

add_filter( 'embed_site_title_html', 'devblog_embed_only_site_title' );

Adding extra content

Besides styling the embed and modifying its elements, you can also add extra pieces of content.

You can use two hooks for this: one immediately after the excerpt (embed_content), and another in the row that contains the comment and share icons (embed_content_meta).

Add the published date

You might choose to display the publication date only for posts, since pages are fairly static.

Since every post type uses the same embed template, use a conditional tag to append the date with the embed_content action:

function devblog_embed_post_posted_on() {
	if ( ! is_single() ) {
		return;
	}

	$time = sprintf(
		'<time datetime="%1$s">%2$s</time>',
		esc_attr( get_the_date( DATE_W3C ) ),
		esc_html( get_the_date() )
	);

	printf(
		'<p class="wp-embed-posted-on">%s</p>',
		sprintf(
			/* translators: %s: Publish date. */
			esc_html__( 'Posted on %s', 'devblog' ),
			$time // phpcs:ignore WordPress.Security.EscapeOutput
		)
	);
}

add_action( 'embed_content', 'devblog_embed_post_posted_on' );

Then, add these styles to previously created CSS file to create spacing between the post date and the excerpt:

/* This specificity is needed to overwrite the defaults. */
p.wp-embed-posted-on {
	margin-top: 10px;
}

Add a like button

There are not many examples of extending the row with the comment and share icons, but here’s one idea: if your website includes a feature for liking posts, you could add a like button to the embed.

You can hook into the action embed_content_meta to render the markup:

function devblog_embed_like_button() {
	if ( is_404() ) {
		return;
	}
	?>
	<div class="wp-embed-like">
		<button class="wp-embed-like-button"
				aria-label="<?php esc_attr_e( 'Like', 'devblog' ); ?>">
			<span class="dashicons dashicons-heart"></span>
		</button>
	</div>
	<?php
}

add_action( 'embed_content_meta', 'devblog_embed_like_button', 9 );

This HTML follows a structure similar to the sharing button that WordPress already gives you in embeds.

Likewise, to stay as close as possible to the existing WordPress code, you can add these styles:

.wp-embed-like {
	display: inline;
	margin-right: 10px;
}

.wp-embed-like-button {
	margin: -8px 0 0;
	padding: 0;
	background: transparent;
	border: none;
	cursor: pointer;
	outline: none;
}

.wp-embed-like-button .dashicons {
	padding: 4px;
	top: 8px;
}

.wp-embed-like-button:focus .dashicons,
.wp-embed-like-button:focus .dashicons {
	box-shadow: 0 0 0 2px #2271b1;
	outline: 2px solid transparent;
	border-radius: 100%;
}

.wp-embed-like-button:hover .dashicons-heart {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Crect x='0' fill='none' width='20' height='20'/%3E%3Cg%3E%3Cpath fill='%232271b1' d='M10 17.12c3.33-1.4 5.74-3.79 7.04-6.21 1.28-2.41 1.46-4.81.32-6.25-1.03-1.29-2.37-1.78-3.73-1.74s-2.68.63-3.63 1.46c-.95-.83-2.27-1.42-3.63-1.46s-2.7.45-3.73 1.74c-1.14 1.44-.96 3.84.34 6.25 1.28 2.42 3.69 4.81 7.02 6.21z'/%3E%3C/g%3E%3C/svg%3E");
}

.dashicons-heart {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Crect x='0' fill='none' width='20' height='20'/%3E%3Cg%3E%3Cpath fill='%238c8f94' d='M10 17.12c3.33-1.4 5.74-3.79 7.04-6.21 1.28-2.41 1.46-4.81.32-6.25-1.03-1.29-2.37-1.78-3.73-1.74s-2.68.63-3.63 1.46c-.95-.83-2.27-1.42-3.63-1.46s-2.7.45-3.73 1.74c-1.14 1.44-.96 3.84.34 6.25 1.28 2.42 3.69 4.81 7.02 6.21z'/%3E%3C/g%3E%3C/svg%3E");
}

This is not the most modern CSS, but it aligns with the styles WordPress core uses for embeds.

Implementing actual Like button functionality goes beyond this article, but here’s how you would style the button.

Removing existing elements

Beyond adding elements, you can also remove existing ones you don’t need.

For example, here’s how you can remove the comment and share buttons that WordPress adds with the embed_content_meta action:

remove_action( 'embed_content_meta', 'print_embed_comments_button' );

remove_action( 'embed_content_meta', 'print_embed_sharing_button' );

If you remove the share button, you should also remove the corresponding markup for the sharing dialog. These two elements go together, but they are added using separate hooks:

remove_action( 'embed_footer', 'print_embed_sharing_dialog' );

Custom embeds

What if you’d rather build a custom embed from scratch, and the available hooks and filters aren’t enough?

In that situation, you can create a custom template. That gives you complete control over the output and structure, allowing you to design an embed layout that perfectly fits your needs.

Remember—your embeds will appear on other websites. Make practical design choices, so they integrate well with various styles. Sometimes, a modern and fresh look is all you need.

Template files

Where do you find the template files related to embeds? If your website uses the default embeds, you won’t find them in your theme folder.

Theme-compat files

The template files for embeds are in the /wp-includes/theme-compat/ folder of your WordPress installation. They include:

  • embed-404.php
  • embed-content.php
  • embed.php
  • footer-embed.php
  • header-embed.php

To override any of these, copy the ones you need into your theme folder and edit them. Theme files take priority over the theme-compat files, which serve as fallbacks.

Template hierarchy

By default, every post type (post, page) shares the same template file, embed.php.

You’ve already seen how to use conditional tags for code specific to certain post types. However, sometimes you might need a dedicated template for a specific post type.

For example, you can create an embed-page.php template file specifically for pages, or an embed-product.php template file for a custom post type called product.

A good example of a post-type-specific embed template is the plugin embed on WordPress.org.

The embed-plugin.php includes information specific to plugins, such as the author, rating, and “tested up to” version. These are details that wouldn’t make sense for regular posts or pages.

Site Editor and Block Themes support

Right now, the Editor doesn’t really support editing embeds.

Even if you’re working with a block theme that uses HTML files for the templates, you still need to add PHP files for custom embed templates.

Load templates files from a plugin

But you’re not restricted to storing your embed template files in your theme folder.

If you want to reuse a template across multiple projects, you can move it into a plugin and load it from there.

To get started, create a simple plugin with the following file structure:

/plugins/devblog-embed-template/
├── index.php
└── templates/
    └── embed.php

In the index.php file, add the necessary plugin header and use the embed_template filter to change the location of the template:

<?php
/**
 * Plugin Name: Developer Blog Embed Template
 */

function devblog_embed_template() {
	return plugin_dir_path( __FILE__ ) . 'templates/embed.php';
}

add_filter( 'embed_template', 'devblog_embed_template' );

Finally, add your custom embed template code to the templates/embed.php file.

This is the simplest approach, but it isn’t the most foolproof and doesn’t support post-type–specific files.

For more flexibility, modify the plugin as follows:

function devblog_embed_template( $template_path, $type, $template_candidates ) {
	foreach ( $template_candidates as $template_candidate ) {
		$local_template_path = plugin_dir_path( __FILE__ ) . 'templates/' . $template_candidate;

		if ( file_exists( $local_template_path ) ) {
			return $local_template_path;
		}
	}

	return $template_path;
}

add_filter( 'embed_template', 'devblog_embed_template', 10, 3 );

With this approach, you can also create post-type–specific template files in your plugin, such as /templates/embed-page.php.

WordPress will check your plugin’s folder first; if no matching file is found there, it will fall back to the theme, and then ultimately to the default files in theme-compat if needed.

Have fun!

Now that you’ve seen all the ways you can customize WordPress embeds, it’s time to put these ideas into action. Treat this as your invitation to experiment, using the suggestions in this article as a starting point.

And if you’ve ever felt the current default embed design could use a refresh, the code could stand an update, or Site Editor integration might be more seamless, now is a great time to get involved.

Even sharing feedback and ideas can spark meaningful change.

Props to @marybaum and @areziaal for reviewing the draft and offering feedback.

Categories: , ,

Leave a Reply

Your email address will not be published. Required fields are marked *