Breadcrumb schema (BreadcrumbList JSON-LD) tells search engines the hierarchical path to a page, enabling breadcrumb trails in Google Search results. WordPress generates breadcrumbs structurally but does not output JSON-LD schema by default — adding it requires a few lines of PHP that read the current page’s ancestors.
Problem: Google Search Console shows WordPress category, tag, and custom taxonomy archive pages in search results but without breadcrumb rich results — the HTML breadcrumb navigation is not marked up with schema that Google can parse.
Solution: Output a BreadcrumbList JSON-LD block in wp_head — build the item array from get_the_archive_title(), get_term_parents_list(), and get_permalink(), then encode and echo it. For single posts, walk up the category hierarchy. Validate with Google's Rich Results Test.
The examples below generate BreadcrumbList JSON-LD for posts (using categories), pages (using parent pages), WooCommerce products, and custom post types with custom taxonomies.
$item ) {
$list_items[] = [
'@type' => 'ListItem',
'position' => $position + 1,
'name' => $item['name'],
'item' => $item['url'],
];
}
$schema = [
'@context' => 'https://schema.org',
'@type' => 'BreadcrumbList',
'itemListElement' => $list_items,
];
echo '' . "
";
}
function myplugin_build_breadcrumb_items(): array {
$items = [];
$items[] = [ 'name' => get_bloginfo( 'name' ), 'url' => home_url( '/' ) ];
if ( is_singular( 'post' ) ) {
// Add primary category
$cats = get_the_category();
if ( ! empty( $cats ) ) {
$cat = $cats[0];
// Walk up category ancestors
$ancestors = array_reverse( get_ancestors( $cat->term_id, 'category' ) );
foreach ( $ancestors as $ancestor_id ) {
$anc = get_term( $ancestor_id, 'category' );
$items[] = [ 'name' => $anc->name, 'url' => get_term_link( $anc ) ];
}
$items[] = [ 'name' => $cat->name, 'url' => get_term_link( $cat ) ];
}
$items[] = [ 'name' => get_the_title(), 'url' => get_permalink() ];
} elseif ( is_singular( 'page' ) ) {
// Walk up page parent chain
$ancestors = array_reverse( get_ancestors( get_the_ID(), 'page' ) );
foreach ( $ancestors as $ancestor_id ) {
$items[] = [ 'name' => get_the_title( $ancestor_id ), 'url' => get_permalink( $ancestor_id ) ];
}
$items[] = [ 'name' => get_the_title(), 'url' => get_permalink() ];
} elseif ( is_singular( 'product' ) ) {
$terms = get_the_terms( get_the_ID(), 'product_cat' );
if ( $terms && ! is_wp_error( $terms ) ) {
$cat = $terms[0];
$items[] = [ 'name' => $cat->name, 'url' => get_term_link( $cat ) ];
}
$items[] = [ 'name' => get_the_title(), 'url' => get_permalink() ];
}
return $items;
}
Also output a visible breadcrumb trail using the same data:
';
echo '';
$last = count( $items ) - 1;
foreach ( $items as $pos => $item ) {
$is_last = ( $pos === $last );
echo '- ';
if ( ! $is_last ) {
printf( '%s',
esc_url( $item['url'] ), esc_html( $item['name'] ) );
} else {
printf( '%s', esc_html( $item['name'] ) );
}
echo '';
echo '
';
if ( ! $is_last ) echo '';
}
echo '
';
}
NOTE: Test your breadcrumb schema with Google's Rich Results Test. The JSON-LD and microdata outputs are equivalent — use JSON-LD (the <script> block) if you want to keep markup semantic and schema separate, which is Google's recommended approach.