Integrating Hybrid Breadcrumbs into WordPress themes

Hybrid Breadcrumbs is one of the most advanced and robust breadcrumb trail scripts ever created for WordPress. I designed it to handle most scenarios out of the box with little-to-no configuration.

It is a continuation of my original Breadcrumb Trail plugin/script that I’ve been working on and building since 2009. After maintaining this script for nearly a decade, I realized that we needed a different way of handling the code so that it was flexible enough to handle new things in the future and more custom scenarios that developers need.

In this tutorial, I’m going to walk you through everything from installing the Hybrid Breadcrumbs package into your WordPress theme to configuring it for your needs.


Note that you must have Composer installed on your system. You’ll need that if you want to install PHP packages.

First, you need to navigate to your theme folder via the command line utility on your computer:

cd path/to/wp-content/themes/<your-theme-name>

Then, use Composer to install the package.

composer require justintadlock/hybrid-breadcrumbs

If you’re already loading the Composer autoloader file, you’re finished with installation (the Mythic starter theme already does this). If not, you’ll need to add the following to your theme’s functions.php file.

if ( file_exists( get_parent_theme_file_path( 'vendor/autoload.php' ) ) ) {
    require_once( get_parent_theme_file_path( 'vendor/autoload.php' ) );

Basic usage

There are two primary methods for working with Hybrid Breadcrumbs.

Static class

The first and simplest method is to use the Hybrid\Breadcrumbs\Trail static class. To use it, simply drop the following code in your theme’s header template or the location that you want it to go.

<?php Hybrid\Breadcrumbs\Trail::display() ?>

That’ll get you set up with the default configuration. Most themes would be perfectly fine only using that single line of code and doing nothing else.

Here’s a quick overview of the available methods in the static class:

// Returns a new instance of the Hybrid\Breadcrumbs\Breadcrumbs class.
Trail::breadcrumbs( array $args = [] );

// Makes a breadcrumb trail and returns an instance of the Hybrid\Breadcrumbs\Breadcrumbs.
Trail::make( array $args = [] );

// Returns an array of Hybrid\Breadcrumbs\Crumb\* objects.
Trail::all( array $args = [] );

// Displays the HTML output of the breadcrumb trail if it exists.
Trail::display( array $args = [] );

// Returns the HTML output of the breadcrumb trail or an empty string.
Trail::render( array $args = [] );

The static class is simply syntactic sugar, so to speak, to make it easy for theme authors to output stuff in their theme. It’s a wrapper for using an object (below). Most of this tutorial will use the static class for simplicity.

Note that from this point forward in the tutorial when referencing the “Hybrid\Breadcrumbs\Trail” class, I’ll simply use “Trail” instead of the fully-qualified name.


If you prefer working with objects instead of static classes, the following code would accomplish the same thing:

    $trail = new Hybrid\Breadcrumbs\Breadcrumbs();

Here’s a quick overview of the public methods available:

// Create a new Breadcrumbs object.
$trail = new \Hybrid\Breadcrumbs\Breadcrumbs( array $args = [] );

// Makes the breadcrumb trail and returns an instance of the object.

// Returns an array of Hybrid\Breadcrumbs\Crumb\* objects.

// Displays the HTML output of the breadcrumb trail if it exists.

// Returns the HTML output of the breadcrumb trail or an empty string.


There may be times where you want to configure how things are output. You could even build theme options to give the user control over some of this.

The $args parameter shown in the classes and methods above is the only parameter you need to worry about. It’s an array of configuration options at your disposal. The following is one example of how you’d use that:

Trail::display( [
    'show_on_front'  => true,
    'show_trail_end' => false
] );

Let’s dive into the options and what they do.

Changing the HTML output

There are 6 options for altering the HTML output:

  • before – HTML to display before. Defaults to ''.
  • after – HTML to display after. Defaults to ''.
  • container_tag – HTML tag to use for the container. Defaults to nav.
  • title_tag – HTML tag to use for the title. Defaults to h2.
  • list_tag – HTML tag to use for the list. Defaults to ul.
  • item_tag – HTML tag to use for each breadcrumb. Defaults to li.

All of this is fairly straightforward stuff for most theme authors. It should be similar to working with any WordPress template tag.

The following is an example of changing the container tag to a <div> and the list tag to a <ol>.

Trail::display( [
    'container_tag' => 'div',
    'list_tag'      => 'ol'
] );

Changing the CSS classes

I know that theme authors can be a bit opinionated about what classes they use. I tried to keep this flexible enough to allow for customization. By default, it uses a BEM-style naming system and is meant for use in component-based systems.

There are 4 classes you have control over:

  • container_class – Class to use for the container. Defaults to breadcrumbs.
  • title_class – Class to use for the title. Defaults to breadcrumbs__title.
  • list_class – Class to use for the list. Defaults to breadcrumbs__trail.
  • item_class – Class to use for each breadcrumb. Defaults to breadcrumbs__crumb.

It’s worth noting that the item_class gets additional “modifier” classes attached to it. Let’s suppose you changed it like so:

Trail::display( [
    'item_class' => 'crumb'
] );

You’ll end up with a list item that looks like this:

<li class="crumb crumb--{$modifier}">

Boolean switches

There are three options for enabling/disabling something via a boolean.

  • show_on_front – Whether to show the breadcrumb trail on the site front page. Defaults to false.
  • show_trail_end – Whether to display the final breadcrumb in the trail. Defaults to true.
  • network – Whether to include the main site at the beginning of the trail on multisite. Defaults to false.

These should be fairly straightforward. Just set an option to true or false. For example, let’s say you didn’t want to display the final item in the breadcrumb trail (the current page). You’d use the following code.

Trail::display( [
    'show_trail_end' => false
] );

Single post taxonomies

Sometimes, you might want to show a particular taxonomy term when viewing a single post. A common example of this is to show the category for the current single post.

  • post_taxonomy – An array of key/value pairs where the key is the post type slug and the value is the taxonomy slug.

Generally speaking, I recommend not touching this option for publicly-released themes. It’s often best to leave the script to handle this based on how the user has their rewrite rules set up. For client/personal work and CPTs, you might want to manually set these if not reflected in the rewrite rules (permalinks).

Let’s say you want to always display the primary category for a post. Use the following:

Trail::display( [
    'post_taxonomy' => [
        'post' => 'category'
] );

Note: by default, Hybrid Breadcrumbs will check the permalink structure for the “post” post type and automatically use the category taxonomy if the structure is set to “/%postname%”.

Custom labels

The final option available is for customizing the crumb and other labels.

  • labels – An array of key/value pairs where the key is an ID for a label and the value is the internationalized text label shown on the front end.

Below is a list of all the default labels. Feel free to change these as you wish.

$defaults = [
    'title'               => __( 'Browse:',                               'hybrid-core' ),
    'aria_label'          => _x( 'Breadcrumbs', 'breadcrumbs aria label', 'hybrid-core' ),
    'home'                => __( 'Home',                                  'hybrid-core' ),
    'error_404'           => __( '404 Not Found',                         'hybrid-core' ),
    'archives'            => __( 'Archives',                              'hybrid-core' ),
    // Translators: %s is the search query.
    'search'              => __( 'Search results for: %s',                'hybrid-core' ),
    // Translators: %s is the page number.
    'paged'               => __( 'Page %s',                               'hybrid-core' ),
    // Translators: %s is the page number.
    'paged_comments'      => __( 'Comment Page %s',                       'hybrid-core' ),
    // Translators: Minute archive title. %s is the minute time format.
    'archive_minute'      => __( 'Minute %s',                             'hybrid-core' ),
    // Translators: Weekly archive title. %s is the week date format.
    'archive_week'        => __( 'Week %s',                               'hybrid-core' ),

    // "%s" is replaced with the translated date/time format.
    'archive_minute_hour' => '%s',
    'archive_hour'        => '%s',
    'archive_day'         => '%s',
    'archive_month'       => '%s',
    'archive_year'        => '%s',

Note that the default textdomain is set to ‘hybrid-core’. If developing a theme based off Hybrid Core, such as the Mythic starter theme, this is not an issue. However, if using Hybrid Breadcrumbs elsewhere, you’ll need to do something like the one theme with two textdomains trick if you want translations to work.

Sass + BEM

If you’re a Sass fan, you should feel right at home styling the breadcrumbs output. Here’s a quick bit of starter code to jump-start things for you.

// Wrapper element.
.breadcrumbs {

    // Title. Note that this is the heading that says "Browse:". The code
    // puts it inline with the trail.
    &__title {
        display:   inline-block;
        margin:    0 0 1.5rem;
        font-size: inherit;

    // List.
    &__trail {
        list-style: none;
        display:    inline-block;
        margin:     0 0 1.5rem;

    // Individual crumbs.
    &__crumb {
        display: inline-block;

        // Add separators.
        &::after {
            content: "\002F";
            padding: 0 0.5em;

        &:last-of-type::after {
            display: none;

Fully controlling the output

Some theme authors may not be fully satisfied with the output options available. That’s OK. We’ve got you covered. The Trail::all() method will return an array of Hybrid\Breadcrumbs\Crumb\* objects for you to do with as you please.

Here’s a quick example of how that might work:

<?php if ( $crumbs = Trail::all() ) : ?>

    <ol class="crumbs">

        <?php foreach ( Trail::all() as $crumb ) : ?>

            <li class="crumbs__crumb">
                <a href="<?php echo esc_url( $crumb->url() ) ?>"><?php echo esc_html( $crumb->label() ) ?></a>

        <?php endforeach ?>


<?php endif ?>

The $crumb object has the following public methods.

  • $crumb->label() – Returns the text label.
  • $crumb->url() – Returns the URL to the crumb.
  • $crumb->type() – Returns the type of crumb (e.g., post, home, term, etc.).

Advanced OOP

Hybrid Breadcrumbs is a purely object-oriented approach to handling breadcrumbs. While this tutorial is focused on the 90% of use cases that most theme authors will need, I do want developers to be aware that you can dig into this and build some more complex setups that I can’t fully cover in this tutorial.

What I’m prepared to do is run through an overview of how things work. I encourage anyone who’s interested to dig into the code. It’s well documented.

First, everything within the src/Contracts directory should be your source of truth. This folder houses all of the interfaces, which give a broad overview of what is available. The rest of the code is simply the implementation of the contracts.

Everything runs through the primary Hybrid\Breadcrumbs\Breadcrumbs class. The instance of Breadcrumbs gets passed around between any class that uses it. Essentially, it acts as a manager to tie our three main types of classes together:

  • Query classes are ran depending on what the currently-queried WordPress page is. Each query class will typically call one or more Build or Crumb classes.
  • Build classes do much of the work in figuring out which crumbs to show. They perform a wide range of tasks based on the given scenario.
  • Crumb classes are objects that represent a given breadcrumb item, such as a single post or home page crumb. These are the things that get output.

Each query, build, and crumb class can be filtered on the fly via one of the following hooks. You merely need to return the class name that you prefer to use for any given type.

  • hybrid/breadcrumbs/query/{$type}
  • hybrid/breadcrumbs/build/{$type}
  • hybrid/breadcrumbs/crumb/{$type}

You can do a whole crap-ton of customization with these hooks. Of course, the entire package is object-oriented, so literally every class can be extended or overwritten in some way.

Breadcrumbs. Your way.

I hope that I covered enough of the basics to get you started using Hybrid Breadcrumbs.

There are many advanced topics we could cover, and I’d be happy to help people individually with those. I didn’t think the majority of theme authors would ever need to use those more advanced techniques outside of highly-custom client work. Even then, the best way to get into those things would be reading the code itself.

If you need help, just hop into the support forums or our Slack chat.