Custom breadcrumbs with list of children (categories or pages)
Asked Answered
J

2

7

I am currently building my very first WordPress template (using Bootstrap 4) and I need to integrate breadcrumbs to my page. I can see that the theme we're currently using offers breadcrumbs as well, but as these are default breadcrumbs, it's by far not enough.

Default Breadcrumb, what I mean, is something simple as:
Home / Category / Subcategory / Page

What I need to build is more like:
Home / Category / Subcategory / Page as well, but when you hover Category oder Subcategory you should see the children of the currently selected option.

e.g. hovering HOME will display the available categories:

Home / Category / Subcategory / Page
  |
Category A
Category B
Category C


Or, to see the other available subcategories, it will look like this:

Home / Category / Subcategory / Page
         |
       Subcategory A
       Subcategory B
       Subcategory C

I have already build this for a static page. Code looks like this:

<div class="d-none d-md-block">
     <div class="dropdown">
          <div class="dropdown-menu">
               <a class="dropdown-item" href="~/Category1">Category 1</a>
               <a class="dropdown-item" href="~/Category2">Category 2</a>
               <a class="dropdown-item" href="~/Category3">Category 3</a>
          </div>

          <a class="dropdown-toggle" data-toggle="dropdown">
             Home
          </a>
     </div>

     <div class="dropdown">
          <div class="dropdown-menu">
               <a class="dropdown-item" href="~/Catgeory4/SubCat1">SubCat 1</a>
               <a class="dropdown-item" href="~/Catgeory4/SubCat2">SubCat 2</a>
               <a class="dropdown-item" href="~/Catgeory4/SubCat3">SubCat 3</a>
               <a class="dropdown-item" href="~/Catgeory4/SubCat4">SubCat 4</a>
          </div>

          <a class="dropdown-toggle" data-toggle="dropdown">
             Category 4
          </a>
     </div>

     <a href="~/Catgeory4/SubCat2/Page" class="crumb active">Page</a>
</div>

The problem is, that it's my first ever WordPress template and that I only have a basic idea of the wordpress specific php at all :-[ So if you know a plugin that offers this kind of structure, I will be glad to use this. If I have to build it inside the template, fine with me as well.. I just don't know how to get startetd here, so that it results in a dynamic piece of code...

PS (if it does help at all): this is the current get_breadrumb function from the base theme:

if ( ! function_exists( 'bizbuzz_get_breadcrumb' ) ) {
/**
 *  Header image / Slider.
 *
 * @since 1.0.0
 */
function bizbuzz_get_breadcrumb() {

    $enable_breadcrumb = bizbuzz_get_option( 'enable_breadcrumb' );
    if ( $enable_breadcrumb ) {
        $args = array(
            'separator'    => '>',
            'show_current' => 1,
            'show_on_home' => 0,
        );
        if ( is_home() || is_front_page() ) {

            if ( $args['show_on_home'] ) {
                ?>
                <div id="bizbuzz-breadcrumb">
                    <div class="rt-wrapper">
                        <?php bizbuzz_default_breadcrumb( $args ); ?>
                    </div>
                </div>
                <?php
            }
        } else {
            ?>
            <div id="bizbuzz-breadcrumb">
                <div class="rt-wrapper">
                    <?php bizbuzz_default_breadcrumb( $args ); ?>
                </div>
            </div>
            <?php
        }
     }
   }
}
Jingo answered 10/8, 2020 at 11:18 Comment(2)
Are you only using pages or do you have other CPTs and/or taxonomies? The latter, specifically, get a little bit more complicated.Pisciform
I use categories and related posts as well as single pages outside any categoryJingo
K
2

Try this code it's working from my side.

function custom_breadcrumbs()
{
    // Set variables for later use
    $here_text        = __( 'You are currently here!' );
    $home_link        = home_url('/');
    $home_text        = __( 'Home' );
    $link_before      = '<span typeof="v:Breadcrumb">';
    $link_after       = '</span>';
    $link_attr        = ' rel="v:url" property="v:title"';
    $link             = $link_before . '<a' . $link_attr . ' href="%1$s">%2$s</a>' . $link_after;
    $delimiter        = ' &raquo; ';              // Delimiter between crumbs
    $before           = '<span class="current">'; // Tag before the current crumb
    $after            = '</span>';                // Tag after the current crumb
    $page_addon       = '';                       // Adds the page number if the query is paged
    $breadcrumb_trail = '';
    $category_links   = '';

    /** 
     * Set our own $wp_the_query variable. Do not use the global variable version due to 
     * reliability
     */
    $wp_the_query   = $GLOBALS['wp_the_query'];
    $queried_object = $wp_the_query->get_queried_object();

    // Handle single post requests which includes single pages, posts and attatchments
    if ( is_singular() ) 
    {
        /** 
         * Set our own $post variable. Do not use the global variable version due to 
         * reliability. We will set $post_object variable to $GLOBALS['wp_the_query']
         */
        $post_object = sanitize_post( $queried_object );

        // Set variables 
        $title          = apply_filters( 'the_title', $post_object->post_title );
        $parent         = $post_object->post_parent;
        $post_type      = $post_object->post_type;
        $post_id        = $post_object->ID;
        $post_link      = $before . $title . $after;
        $parent_string  = '';
        $post_type_link = '';

        if ( 'post' === $post_type ) 
        {
            // Get the post categories
            $categories = get_the_category( $post_id );
            if ( $categories ) {
                // Lets grab the first category
                $category  = $categories[0];

                $category_links = get_category_parents( $category, true, $delimiter );
                $category_links = str_replace( '<a',   $link_before . '<a' . $link_attr, $category_links );
                $category_links = str_replace( '</a>', '</a>' . $link_after,             $category_links );
            }
        }

        if ( !in_array( $post_type, ['post', 'page', 'attachment'] ) )
        {
            $post_type_object = get_post_type_object( $post_type );
            $archive_link     = esc_url( get_post_type_archive_link( $post_type ) );

            $post_type_link   = sprintf( $link, $archive_link, $post_type_object->labels->singular_name );
        }

        // Get post parents if $parent !== 0
        if ( 0 !== $parent ) 
        {
            $parent_links = [];
            while ( $parent ) {
                $post_parent = get_post( $parent );

                $parent_links[] = sprintf( $link, esc_url( get_permalink( $post_parent->ID ) ), get_the_title( $post_parent->ID ) );

                $parent = $post_parent->post_parent;
            }

            $parent_links = array_reverse( $parent_links );

            $parent_string = implode( $delimiter, $parent_links );
        }

        // Lets build the breadcrumb trail
        if ( $parent_string ) {
            $breadcrumb_trail = $parent_string . $delimiter . $post_link;
        } else {
            $breadcrumb_trail = $post_link;
        }

        if ( $post_type_link )
            $breadcrumb_trail = $post_type_link . $delimiter . $breadcrumb_trail;

        if ( $category_links )
            $breadcrumb_trail = $category_links . $breadcrumb_trail;
    }

    // Handle archives which includes category-, tag-, taxonomy-, date-, custom post type archives and author archives
    if( is_archive() )
    {
        if (    is_category()
             || is_tag()
             || is_tax()
        ) {
            // Set the variables for this section
            $term_object        = get_term( $queried_object );
            $taxonomy           = $term_object->taxonomy;
            $term_id            = $term_object->term_id;
            $term_name          = $term_object->name;
            $term_parent        = $term_object->parent;
            $taxonomy_object    = get_taxonomy( $taxonomy );
            $current_term_link  = $before . $taxonomy_object->labels->singular_name . ': ' . $term_name . $after;
            $parent_term_string = '';

            if ( 0 !== $term_parent )
            {
                // Get all the current term ancestors
                $parent_term_links = [];
                while ( $term_parent ) {
                    $term = get_term( $term_parent, $taxonomy );

                    $parent_term_links[] = sprintf( $link, esc_url( get_term_link( $term ) ), $term->name );

                    $term_parent = $term->parent;
                }

                $parent_term_links  = array_reverse( $parent_term_links );
                $parent_term_string = implode( $delimiter, $parent_term_links );
            }

            if ( $parent_term_string ) {
                $breadcrumb_trail = $parent_term_string . $delimiter . $current_term_link;
            } else {
                $breadcrumb_trail = $current_term_link;
            }

        } elseif ( is_author() ) {

            $breadcrumb_trail = __( 'Author archive for ') .  $before . $queried_object->data->display_name . $after;

        } elseif ( is_date() ) {
            // Set default variables
            $year     = $wp_the_query->query_vars['year'];
            $monthnum = $wp_the_query->query_vars['monthnum'];
            $day      = $wp_the_query->query_vars['day'];

            // Get the month name if $monthnum has a value
            if ( $monthnum ) {
                $date_time  = DateTime::createFromFormat( '!m', $monthnum );
                $month_name = $date_time->format( 'F' );
            }

            if ( is_year() ) {

                $breadcrumb_trail = $before . $year . $after;

            } elseif( is_month() ) {

                $year_link        = sprintf( $link, esc_url( get_year_link( $year ) ), $year );

                $breadcrumb_trail = $year_link . $delimiter . $before . $month_name . $after;

            } elseif( is_day() ) {

                $year_link        = sprintf( $link, esc_url( get_year_link( $year ) ),             $year       );
                $month_link       = sprintf( $link, esc_url( get_month_link( $year, $monthnum ) ), $month_name );

                $breadcrumb_trail = $year_link . $delimiter . $month_link . $delimiter . $before . $day . $after;
            }

        } elseif ( is_post_type_archive() ) {

            $post_type        = $wp_the_query->query_vars['post_type'];
            $post_type_object = get_post_type_object( $post_type );

            $breadcrumb_trail = $before . $post_type_object->labels->singular_name . $after;

        }
    }   

    // Handle the search page
    if ( is_search() ) {
        $breadcrumb_trail = __( 'Search query for: ' ) . $before . get_search_query() . $after;
    }

    // Handle 404's
    if ( is_404() ) {
        $breadcrumb_trail = $before . __( 'Error 404' ) . $after;
    }

    // Handle paged pages
    if ( is_paged() ) {
        $current_page = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : get_query_var( 'page' );
        $page_addon   = $before . sprintf( __( ' ( Page %s )' ), number_format_i18n( $current_page ) ) . $after;
    }

    $breadcrumb_output_link  = '';
    $breadcrumb_output_link .= '<div class="breadcrumb">';
    if (    is_home()
         || is_front_page()
    ) {
        // Do not show breadcrumbs on page one of home and frontpage
        if ( is_paged() ) {
            $breadcrumb_output_link .= $here_text . $delimiter;
            $breadcrumb_output_link .= '<a href="' . $home_link . '">' . $home_text . '</a>';
            $breadcrumb_output_link .= $page_addon;
        }
    } else {
        $breadcrumb_output_link .= $here_text . $delimiter;
        $breadcrumb_output_link .= '<a href="' . $home_link . '" rel="v:url" property="v:title">' . $home_text . '</a>';
        $breadcrumb_output_link .= $delimiter;
        $breadcrumb_output_link .= $breadcrumb_trail;
        $breadcrumb_output_link .= $page_addon;
    }
    $breadcrumb_output_link .= '</div><!-- .breadcrumbs -->';

    return $breadcrumb_output_link;
}
add_shortcode('custom_breadcrumbs','custom_breadcrumbs');

Display breadcrumbs code

echo do_shortcode('[custom_breadcrumbs]');
Kistner answered 13/10, 2020 at 10:52 Comment(3)
the function has to be placed inside functions.php and the echo custom_breadcrumbs() call where we want to display the links, right?Jingo
Tested it, but did not work for me. Looks like the old breadcrumbs, no slide toogleJingo
@Jingo It worked for me but I have 1 question is it possible to get the breadcrumbs in posts like Home>Category>Subcategory>Post Title? Currently, it shows as Home>Category>Post Title.Bloodroot
P
1

Here's the basic function that hopefully should get you or someone else in the right direction:

function so_63339155_get_page_hierarchy($post = null): array
{
    // Make sure we have something
    $post = get_post($post);
    if (!$post) {
        return [];
    }

    // This will get all Post IDs of the "parent" objects
    $ancestors = get_post_ancestors($post);
    if (0 === count($ancestors)) {
        return [];
    }

    $ret = [];
    foreach ($ancestors as $postId) {
        // Grab the children for the page.
        // NOTE: This can take additional arguments such as sort order and visibility
        $ret[$postId] = get_children($postId);
    }

    return $ret;
}

Querying the site's hierarchy and getting object data for a lot of posts can be a little expensive, so you might want to check into some caching.

The above code uses the native hierarchy system for pages and should work for any CPT that is based off of the page type. It does not support taxonomy terms, that is a similar but different beast. It also does not take the home/front page on the beginning or the current page on the end, but that can be adapted pretty easily, too.

The result is an array whose keys are Post IDs for the parents and whose values are WP_Post objects of the children, so get_post() will need to be called one more time on the keys, and you'll want to call get_permalink() to get the URLs.

Pisciform answered 13/8, 2020 at 19:45 Comment(2)
To be honest: I have absolutly no idea how to make something similiar to my static code out of your code :-(Jingo
Thank you @ChrisHaas for the additional comments. A bit easier to understand now. But how and where do I call "function so_63339155_get_page_hierarchy($post = null): array" in my context ??Jingo

© 2022 - 2024 — McMap. All rights reserved.