A few years ago, Google deprecated the old vocabulary-data
breadcrumb list schema and replaced it with the official Schema.org BreadcrumbList
one.
Structured data schemas such as schema.org and data-vocabulary.org are used to define shared meaningful structures for markup-based applications on the Web. With the increasing usage and popularity of schema.org, we decided to focus our development on a single SD scheme.
Google Webmaster Central Blog
Table of Contents
Now, the new schema is live. If you are getting warnings when checking for breadcrumbs rich results or via your Google Search Console, here’s what you need to do:
Old schema (before)
<p>
<span itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="https://www.example.com/" itemprop="url"><small itemprop="title">Home</small></a>
</span> »
<span itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="https://www.example.com/about/" itemprop="url"><small itemprop="title">About</small></a>
</span> »
<span itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="https://www.example.com/contact/" itemprop="url"><small itemprop="title">Contact</small></a>
</span>
</p>
New schema (after)
<ol itemscope itemtype="https://schema.org/BreadcrumbList">
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a href="https://www.example.com" itemprop="item"><span itemprop="name">Home</span></a>
<meta itemprop="position" content="1">
</li>
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a href="https://www.example.com/about/" itemprop="item"><span itemprop="name">About</span></a>
<meta itemprop="position" content="2">
</li>
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a href="https://www.example.com/contact/" itemprop="item"><span itemprop="name">Contact</span></a>
<meta itemprop="position" content="3">
</li>
</ol>
Note the more structured architecture, allowing for a parent element, no more rogue separators – use CSS for that – and a new numbering sequence.
Test your site now – https://search.google.com/test/rich-results – and see if your breadcrumbs are correctly implemented.
Additional reading
https://developers.google.com/search/docs/appearance/structured-data/breadcrumb
How to add breadcrumbs programmatically
These days, I like to roll my own breadcrumbs and customize them the way I want. And this is because I have a custom, hand-made WordPress theme, and I don’t need to update it or overwrite it.
So, here are 2 ways to add breadcrumbs programmatically. Only use one solution
Solution #1
function saturn_breadcrumbs() {
if ( ! is_page() || is_front_page() ) {
return;
}
global $post;
$ancestors = array_reverse( get_post_ancestors( $post->ID ) );
$before = '<nav class="entry-breadcrumbs" itemscope itemtype="https://schema.org/BreadcrumbList">';
$after = '</nav>';
$home = '<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"><a href="' . esc_url( home_url( "/" ) ) . '" class="home-link" itemprop="item" rel="home"><span itemprop="name">' . __( 'Home', 'saturn' ) . '</span></a></span>';
$breadcrumb = '';
if ( $ancestors ) {
foreach ( $ancestors as $ancestor ) {
$breadcrumb .= '<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"><a href="' . esc_url( get_permalink( $ancestor ) ) . '" itemprop="item"><span itemprop="name">' . esc_html( get_the_title( $ancestor ) ) . '</span></a></span>';
}
}
$breadcrumb .= '<span class="current-page" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"><span itemprop="name">' . esc_html( get_the_title( $post->ID ) ) . '</span></span>';
return $before . $home . $breadcrumb . $after;
}
Solution #2
function saturn_breadcrumbs() {
$taxonomy = is_category() ? 'category' : get_query_var( 'taxonomy' );
$is_taxonomy_hierarchical = is_taxonomy_hierarchical( $taxonomy );
$post_type = is_page() ? 'page' : get_query_var( 'post_type' );
$is_post_type_hierarchical = is_post_type_hierarchical( $post_type );
if ( ! ( $is_post_type_hierarchical || $is_taxonomy_hierarchical ) || is_front_page() ) {
return;
}
$breadcrumb = '';
if ( $is_post_type_hierarchical ) {
$post_id = get_queried_object_id();
$ancestors = array_reverse( get_post_ancestors( $post_id ) );
if ( $ancestors ) {
foreach ( $ancestors as $ancestor ) {
$breadcrumb .= '<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"><a href="' . esc_url( get_permalink( $ancestor ) ) . '" itemprop="item"><span itemprop="name">' . esc_html( get_the_title( $ancestor ) ) . '</span></a></span>';
}
}
$breadcrumb .= '<span class="current-page" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"><span itemprop="name">' . esc_html( get_the_title( $post_id ) ) . '</span></span>';
} elseif ( $is_taxonomy_hierarchical ) {
$current = get_term( get_queried_object_id(), $taxonomy );
if ( is_wp_error( $current ) ) {
return;
}
if ( $current->parent ) {
$breadcrumb = saturn_get_term_parents( $current->parent, $taxonomy );
}
$breadcrumb .= '<span class="current-category" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"><span itemprop="name">' . esc_html( $current->name ) . '</span></span>';
}
$home = '<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem"><a href="' . esc_url( home_url( '/' ) ) . '" class="home-link" itemprop="item" rel="home"><span itemprop="name">' . esc_html__( 'Home', 'saturn' ) . '</span></a></span>';
return '<nav class="entry-breadcrumbs" itemscope itemtype="https://schema.org/BreadcrumbList">' . $home . $breadcrumb . '</nav>';
}
And this is how to return the parents for a given taxonomy term ID. Note that the helper function below is required for solution #2.
/**
* Return the parents for a given taxonomy term ID.
*
* @param int $term Taxonomy term whose parents will be returned.
* @param string $taxonomy Taxonomy name that the term belongs to.
* @param array $visited Terms already added to prevent duplicates.
*
* @return string A list of links to the term parents.
*/
function saturn_get_term_parents( $term, $taxonomy, $visited = [] ) {
$parent = get_term( $term, $taxonomy );
if ( is_wp_error( $parent ) ) {
return $parent;
}
$chain = '';
if ( $parent->parent && ( $parent->parent != $parent->term_id ) && ! in_array( $parent->parent, $visited ) ) {
$visited[] = $parent->parent;
$chain .= saturn_get_term_parents( $parent->parent, $taxonomy, $visited );
}
$chain .= '<a href="' . esc_url( get_category_link( $parent->term_id ) ) . '">' . $parent->name . '</a>';
return $chain;
}
If you want to have full control over the breadcrumbs’ placement, use a shortcode:
add_shortcode( 'saturn-breadcrumbs', 'saturn_breadcrumbs' );