Introduction
If you want your WordPress site to rank higher on Google, you need to master how to add SEO-friendly meta tags dynamically in WordPress using PHP. Meta tags tell search engines what your pages are about. Therefore, getting them right is one of the most impactful things you can do for your SEO.
However, many beginners rely on plugins alone. While plugins like Yoast SEO are excellent, understanding the PHP approach gives you far more control. For example, you can generate unique meta descriptions for every post automatically β without touching each page individually.
In this guide, you will learn everything step by step. Whether you are a beginner or an intermediate developer, this tutorial is for you.

1. What Are Meta Tags and Why Do They Matter?
Meta tags are snippets of HTML code placed inside the <head> section of your web page. Search engines like Google read these tags. However, your website visitors never see them directly.
Think of meta tags like a label on a product box. The box (your webpage) holds the content. The label (meta tags) tells people β and search engines β what is inside.
The most important meta tags for SEO are:
- Meta Title β the clickable headline in search results
- Meta Description β the short summary below the title in search results
- Robots Meta Tag β tells search engines to index or skip a page
- Canonical Tag β prevents duplicate content issues
- Open Graph Tags β controls how your page looks when shared on Facebook
- Twitter Card Tags β controls appearance on Twitter/X
Therefore, adding these tags correctly and dynamically is essential for every WordPress site.
2. Types of SEO Meta Tags in WordPress
Before writing any PHP, it helps to understand what each tag does.
Meta Description
<meta name="description" content="Your page summary here." />This is the short text that appears under your title in Google search results. Although it does not directly affect rankings, it strongly affects click-through rates (CTR). A compelling description brings more visitors.
Robots Meta Tag
<meta name="robots" content="index, follow" />This tag tells Google whether to index your page and follow its links. For most pages, you want index, follow. However, for thank-you pages or admin pages, you might use noindex, nofollow.
Open Graph Tags
Open Graph tags make your content look great on social media. For example:
<meta property="og:title" content="Your Page Title" />
<meta property="og:description" content="Your page description." />
<meta property="og:image" content="https://yoursite.com/image.jpg" />Twitter Card Tags
Similarly, Twitter Card tags control how your links appear on Twitter/X:
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Your Page Title" />3. How WordPress Handles Meta Tags by Default
By default, WordPress adds very few meta tags. It includes a basic charset and viewport tag. However, it does not automatically add meta descriptions, Open Graph tags, or Twitter Cards.
Therefore, you have two options:
- Use a plugin like Yoast SEO or Rank Math
- Write custom PHP in your theme’s
functions.php
The PHP approach is lighter and faster. It also gives you full control. For example, you can pull the post excerpt automatically as the meta description β no manual input needed.
4. How to Add SEO-Friendly Meta Tags Dynamically in WordPress Using PHP
Now let us get to the core of this guide Follow these steps carefully.
β οΈ Important: Always back up your site before editing
functions.php. A syntax error can break your site. Consider using a child theme to be safe.Step 1 β Hook Into
wp_headWordPress uses a system of hooks to insert code at specific points. The
wp_headhook fires inside the<head>tag β exactly where meta tags belong.Add this to your
functions.phpfile:
function my_custom_meta_tags() {
// Your meta tag code goes here
}
add_action( 'wp_head', 'my_custom_meta_tags' );This tells WordPress to run your function every time the <head> section loads.
Step 2 β Write the PHP Function
Now, expand the function to output a robots meta tag and a basic charset declaration:
function my_custom_meta_tags() {
echo '<meta name="robots" content="index, follow" />' . "\n";
}
add_action( 'wp_head', 'my_custom_meta_tags' );This is simple but effective. However, the real power comes in the next step β dynamic meta descriptions.
Step 3 β Add a Dynamic Meta Description
A dynamic meta description changes automatically based on the current page. For example, it pulls the post excerpt on blog posts. On the homepage, it shows your site description.
Here is how to do it:
function my_custom_meta_tags() {
global $post;
// Default meta description
$description = get_bloginfo( 'description' );
// Use post excerpt on singular pages
if ( is_singular() && has_excerpt( $post->ID ) ) {
$description = get_the_excerpt();
}
// Use category description on category pages
if ( is_category() ) {
$description = strip_tags( category_description() );
}
// Sanitize the output
$description = esc_attr( wp_strip_all_tags( $description ) );
echo '<meta name="description" content="' . $description . '" />' . "\n";
echo '<meta name="robots" content="index, follow" />' . "\n";
}
add_action( 'wp_head', 'my_custom_meta_tags' );What is happening here?
get_bloginfo('description')β pulls your site tagline as the fallback descriptionis_singular()β checks if we are on a single post or pageget_the_excerpt()β grabs the post excerpt automaticallyis_category()β detects category archive pagesesc_attr()β sanitizes the output to prevent security issues
Therefore, every page now gets a relevant, unique meta description β dynamically and automatically.
Step 4 β Add Open Graph Meta Tags
Open Graph tags help your content look great when shared on Facebook, LinkedIn, and other platforms.
Add these inside your function:
// Open Graph Tags
$og_title = get_the_title();
$og_url = get_permalink();
$og_image = get_the_post_thumbnail_url( $post->ID, 'large' );
$og_description = $description; // Reuse the meta description from Step 3
if ( is_front_page() ) {
$og_title = get_bloginfo( 'name' );
$og_url = home_url( '/' );
}
echo '<meta property="og:type" content="website" />' . "\n";
echo '<meta property="og:title" content="' . esc_attr( $og_title ) . '" />' . "\n";
echo '<meta property="og:description" content="' . esc_attr( $og_description ) . '" />' . "\n";
echo '<meta property="og:url" content="' . esc_url( $og_url ) . '" />' . "\n";
if ( $og_image ) {
echo '<meta property="og:image" content="' . esc_url( $og_image ) . '" />' . "\n";
}Key functions explained:
get_the_title()β returns the current page or post titleget_permalink()β returns the full URL of the current postget_the_post_thumbnail_url()β grabs the featured image URLesc_url()β sanitizes URLs to prevent security vulnerabilities
Step 5 β Add Twitter Card Meta Tags
Twitter Cards make your shared links appear with a large image preview. This significantly improves engagement.
Add this inside your function:
// Twitter Card Tags<br>echo '<meta name="twitter:card" content="summary_large_image" />' . "\n";<br>echo '<meta name="twitter:title" content="' . esc_attr( $og_title ) . '" />' . "\n";<br>echo '<meta name="twitter:description" content="' . esc_attr( $og_description ) . '" />' . "\n";<br><br>if ( $og_image ) {<br> echo '<meta name="twitter:image" content="' . esc_url( $og_image ) . '" />' . "\n";<br>}Complete Final Function
Here is the full, clean version of the function with all tags combined:
function my_custom_meta_tags() {
global $post;
// --- Meta Description ---
$description = get_bloginfo( 'description' );
if ( is_singular() && has_excerpt( $post->ID ) ) {
$description = get_the_excerpt();
}
if ( is_category() ) {
$description = strip_tags( category_description() );
}
$description = esc_attr( wp_strip_all_tags( $description ) );
// --- Page Title & URL ---
$og_title = is_front_page() ? get_bloginfo( 'name' ) : get_the_title();
$og_url = is_front_page() ? home_url( '/' ) : get_permalink();
$og_image = get_the_post_thumbnail_url( $post->ID ?? 0, 'large' );
// --- Output Meta Tags ---
echo '<meta name="description" content="' . $description . '" />' . "\n";
echo '<meta name="robots" content="index, follow" />' . "\n";
// Open Graph
echo '<meta property="og:type" content="website" />' . "\n";
echo '<meta property="og:title" content="' . esc_attr( $og_title ) . '" />' . "\n";
echo '<meta property="og:description" content="' . $description . '" />' . "\n";
echo '<meta property="og:url" content="' . esc_url( $og_url ) . '" />' . "\n";
if ( $og_image ) {
echo '<meta property="og:image" content="' . esc_url( $og_image ) . '" />' . "\n";
}
// Twitter Card
echo '<meta name="twitter:card" content="summary_large_image" />' . "\n";
echo '<meta name="twitter:title" content="' . esc_attr( $og_title ) . '" />' . "\n";
echo '<meta name="twitter:description" content="' . $description . '" />' . "\n";
if ( $og_image ) {
echo '<meta name="twitter:image" content="' . esc_url( $og_image ) . '" />' . "\n";
}
}
add_action( 'wp_head', 'my_custom_meta_tags', 1 );π‘ Tip: The
1inadd_action( 'wp_head', 'my_custom_meta_tags', 1 )sets a high priority. This ensures your tags load before other scripts. Therefore, social media scrapers see them first.5. How to Customize Meta Tags for Different Post Types
WordPress supports many content types β posts, pages, WooCommerce products, custom post types, and more. Fortunately, you can handle each one differently using conditional tags.
Useful Conditional Tags:
Condition Function Homepage is_front_page()Blog index is_home()Single post is_single()Static page is_page()Category archive is_category()Tag archive is_tag()Author archive is_author()Search results is_search()404 page is_404()For example, you might want to add
noindexto search result pages:if ( is_search() ) { echo '<meta name="robots" content="noindex, follow" />' . "\n"; } else { echo '<meta name="robots" content="index, follow" />' . "\n"; }Similarly, for WooCommerce product pages, you can pull the product short description:
if ( is_singular('product') ) { global $product; $description = esc_attr( wp_strip_all_tags( $product->get_short_description() ) ); }
6. How Themes and the Gutenberg Editor Affect Meta Tags
Your WordPress theme and the Gutenberg editor can both affect how meta tags work. Here is what you need to know.
Theme Conflicts
Some themes β especially older ones β add their own meta tags. Therefore, check your theme’s header.php file. Look for <meta name="description" tags. If you find them, remove or disable them. Otherwise, Google may see duplicate meta descriptions.
Gutenberg and Block Editor Customization
The Gutenberg block editor uses a block-based approach to content. However, it does not automatically generate meta tags. Your PHP function handles that independently.
That said, block editor customization and theme settings do affect what content is available for meta tags. For example:
- If your theme supports featured images,
get_the_post_thumbnail_url()will work correctly for Open Graph images. - Themes built with
theme.json(block themes) often strip out custom PHP fromfunctions.phpin certain contexts. However,wp_headhooks still work reliably. - Full-width blocks and wide alignment settings in Gutenberg do not affect meta tags directly. However, they affect your page layout, which can influence user engagement signals that Google tracks.
Using theme.json for Meta-Related Settings
In modern block themes, theme.json controls design settings like WordPress layout width, full width blocks, and typography. However, it does not handle meta tags directly. Therefore, always use functions.php for your dynamic PHP meta tag code.
7. Common Issues and How to Fix Them
Even experienced developers run into problems. Here are the most common issues β and how to solve them.
Issue 1 β Meta Description Is Blank
Cause: The post has no excerpt and the site tagline is empty.
Fix: Add a fallback to the post content:
if ( empty( $description ) && is_singular() ) {
$description = wp_trim_words( get_the_content(), 30, '...' );
}Issue 2 β Duplicate Meta Tags
Cause: Your theme or a plugin is also outputting meta tags.
Fix: Check header.php and dequeue conflicting plugins. You can also use this check:
// Prevent Yoast from outputting its own tags if you're writing custom ones<br>// (Only do this if you're replacing Yoast entirely)<br>// add_filter('wpseo_metadesc', '__return_false');Issue 3 β Open Graph Image Not Showing
Cause: The post has no featured image set.
Fix: Add a default fallback image:
$default_image = get_template_directory_uri() . '/images/default-og.jpg';
$og_image = get_the_post_thumbnail_url( $post->ID ?? 0, 'large' ) ?: $default_image;Issue 4 β Special Characters Breaking Meta Tags
Cause: Post titles or excerpts contain quotes, ampersands, or HTML entities.
Fix: Always use esc_attr() around any output inside HTML attributes:
echo '<meta name="description" content="' . esc_attr( $description ) . '" />';Issue 5 β Tags Not Appearing in Page Source
Cause: A caching plugin is serving a stale version of the page.
Fix: Clear your site cache after making changes to functions.php. Most caching plugins like WP Rocket, W3 Total Cache, or LiteSpeed Cache have a “Clear All Cache” button in the dashboard.
FAQ
Not necessarily. If you build a complete custom PHP solution, you can skip Yoast SEO for meta tags. However, Yoast also offers readability analysis, XML sitemaps, and breadcrumbs. Therefore, many developers use both β but disable Yoast’s meta output to avoid duplicates.
Yes, absolutely. The Gutenberg block editor only affects how you build the content of your pages. Meta tags are added to the <head> via wp_head hooks, which run independently. Therefore, switching to Gutenberg will not break your PHP meta tags.
It is safer to use a child theme. If you edit a parent theme’s functions.php and then update the theme, your changes will be overwritten. A child theme protects your custom code. Alternatively, use a plugin like Code Snippets to add PHP without touching theme files at all.
Add this inside your my_custom_meta_tags() function:$canonical = is_singular() ? get_permalink() : home_url( add_query_arg( array() ) ); echo '<link rel="canonical" href="' . esc_url( $canonical ) . '" />' . "\n";
This tells Google the preferred URL for each page and prevents duplicate content penalties.
Conclusion
You now know exactly how to add SEO-friendly meta tags dynamically in WordPress using PHP. This approach is powerful, flexible, and does not rely on heavy plugins. Moreover, it works perfectly alongside the Gutenberg block editor and modern block themes.
Here is a quick recap:
- β
Hook into
wp_headusingadd_action() - β Generate dynamic meta descriptions using post excerpts and site info
- β Add Open Graph tags for better social media sharing
- β Add Twitter Card tags for rich link previews
- β Handle different post types with conditional tags
- β
Sanitize all output with
esc_attr()andesc_url()
Ready to Take the Next Step?
Start by copying the complete function into your child theme’s functions.php. Then, test your pages using the Facebook Open Graph Debugger and Google’s Rich Results Test.
