WordPress 7.0 ships a native Breadcrumbs block, which took long enough. It looks simple in the Site Editor, and it is, right up until you point it at a WooCommerce store or a multisite network with real custom taxonomies. Automatic hierarchy tends to fall apart there. Core shipped two Breadcrumb block filters for exactly that problem, and they are narrow enough to be useful.
I have hacked breadcrumb trails together with transients and long custom functions more times than I want to admit, usually because the theme had no idea which category was meant to be the primary one. These hooks change that. Breadcrumbs become data you can filter instead of a string of HTML you have to intercept, and the templates get shorter as a result.
Refining output with block_core_breadcrumbs_items
This is the filter you will reach for in about 90% of UI tweaks. It hands you the final array of items just before they render. Each entry in $breadcrumb_items takes a label, an optional url, and a security flag called allow_html.
Watch allow_html, because it defaults to false. Inject an icon or a span without flipping it to true and WordPress runs esc_html() over your markup, which breaks the layout. Work out what genuinely needs raw HTML before you ship.
add_filter( 'block_core_breadcrumbs_items', 'bbioon_inject_custom_shop_root' );
/**
* Injects a 'Shop' link at the start of the breadcrumb trail.
*
* @param array $breadcrumb_items Existing breadcrumb items.
* @return array Modified items.
*/
function bbioon_inject_custom_shop_root( $breadcrumb_items ) {
if ( is_post_type_archive( 'product' ) || is_singular( 'product' ) ) {
array_unshift( $breadcrumb_items, array(
'label' => __( 'Store Front', 'bbioon' ),
'url' => home_url( '/shop/' ),
'allow_html' => false,
) );
}
return $breadcrumb_items;
}
The logic filter: block_core_breadcrumbs_post_type_settings
The second of the Breadcrumb block filters is where the structural decisions get made. A post can sit in categories and tags at the same time, and a product can carry five terms, so the block has to pick a path. This hook is where you make that choice yourself, keyed on the post type or the post ID.
A client site I worked on had posts filed under both “News” and “Featured”. The breadcrumb kept choosing “Featured” because it sorted alphabetically, which cut straight through the SEO silos they had built. This filter let us pin the trail to the primary category instead.
add_filter( 'block_core_breadcrumbs_post_type_settings', 'bbioon_force_primary_taxonomy', 10, 3 );
/**
* Forces the breadcrumb trail to prefer a specific term.
*
* @param array $settings Empty default settings.
* @param string $post_type The current post type slug.
* @param int $post_id The current post ID.
* @return array Modified settings with 'taxonomy' and 'term' keys.
*/
function bbioon_force_primary_taxonomy( $settings, $post_type, $post_id ) {
if ( 'post' === $post_type ) {
$settings['taxonomy'] = 'category';
// You could pull a "Primary Category" from Yoast or RankMath here
$settings['term'] = 'industry-news';
}
return $settings;
}
If you have already been extending WordPress navigation blocks, the pattern will feel familiar. The fallback is the part worth knowing: when your preferred term does not exist, the block drops back to the first available term rather than rendering an empty trail.
If breadcrumb filter work is eating your dev hours, hand it over. I have been doing WordPress since the 4.x days.
Before you put it on a production site
The native Breadcrumbs block is a real performance win, mostly because it takes a third-party plugin out of the stack. It is not a drop-in-and-forget component though. Use the filters so the navigation matches the SEO structure you designed. The official GitHub PR and the WordPress 7.0 dev notes have the rest of the detail. Stay inside these hooks and your navigation should survive the next core update.