Breadcrumbs serve two purposes on a WordPress site: they help visitors understand where they are within your site’s hierarchy, and they give Google structured data it can use to display breadcrumb trails directly in search results. When Google shows a breadcrumb in a SERP snippet, for example nahnuplugins.com › SEO › Auto-Submit Sitemap, it typically pulls that from BreadcrumbList schema rather than the raw URL. This snippet adds that schema automatically to your page head with no plugin dependency.
The Code
Add this to your functions.php or a site-specific plugin. It hooks into wp_head and outputs a JSON-LD BreadcrumbList script block for singular posts, taxonomy archives, and custom post type archives.
How It Works
The snippet builds an array of ListItem objects, each representing one level of the breadcrumb trail. The home page is always the first item. After that, the logic branches based on the current page type.
On singular posts, it checks for a primary category using get_the_terms(). If the post belongs to a category, that category is inserted as the middle crumb between Home and the post title. This mirrors the breadcrumb structure most themes display visually. If the post has no category, such as a custom post type without a taxonomy, the middle crumb is skipped and the trail goes directly from Home to the post.
On category and taxonomy archives, the queried term is added as the final crumb after Home. On custom post type archives, the post type’s label and archive URL are used instead.
The if ( count( $items ) < 2 ) return; guard prevents outputting schema for pages where only the Home item was built, for example, the front page itself, which is already excluded at the top of the function.
The final schema is encoded using wp_json_encode() with JSON_UNESCAPED_SLASHES and JSON_UNESCAPED_UNICODE flags to keep URLs readable and avoid unnecessary escaping of non-ASCII characters.
Verifying the Output
After adding this snippet, visit any post on your site and view the page source. You should see a <script type="application/ld+json"> block near the top of the <head> containing your breadcrumb data. You can also paste the URL into Google’s Rich Results Test tool at search.google.com/test/rich-results to confirm Google can parse the schema and that it’s eligible for breadcrumb display in search results.
When to Use This
This snippet is most valuable on sites without an SEO plugin that generates breadcrumb schema automatically, or on sites where you want lightweight schema output without relying on a plugin’s full schema suite. If you’re already using a plugin like SlimSEO with schema support, check whether it outputs BreadcrumbList schema before adding this to avoid duplicates.
It pairs well with a visual breadcrumb shortcode or block in your theme, the schema and the visual breadcrumb trail can coexist and serve complementary purposes for search engines and users respectively.
add_action( 'wp_head', function() {
if ( is_front_page() || is_home() ) return;
$items = [];
$pos = 1;
// Home
$items[] = [
'@type' => 'ListItem',
'position' => $pos++,
'name' => get_bloginfo( 'name' ),
'item' => home_url( '/' ),
];
if ( is_singular() ) {
// Category middle crumb for posts
$terms = get_the_terms( get_the_ID(), 'category' );
if ( $terms && ! is_wp_error( $terms ) ) {
$term = array_shift( $terms );
$items[] = [
'@type' => 'ListItem',
'position' => $pos++,
'name' => $term->name,
'item' => get_term_link( $term ),
];
}
$items[] = [
'@type' => 'ListItem',
'position' => $pos++,
'name' => get_the_title(),
'item' => get_permalink(),
];
} elseif ( is_category() || is_tax() ) {
$term = get_queried_object();
$items[] = [
'@type' => 'ListItem',
'position' => $pos++,
'name' => $term->name,
'item' => get_term_link( $term ),
];
} elseif ( is_post_type_archive() ) {
$obj = get_queried_object();
$items[] = [
'@type' => 'ListItem',
'position' => $pos++,
'name' => $obj->label,
'item' => get_post_type_archive_link( $obj->name ),
];
}
if ( count( $items ) < 2 ) return;
$schema = [
'@context' => 'https://schema.org',
'@type' => 'BreadcrumbList',
'itemListElement' => $items,
];
echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . '</script>' . "\n";
} );
