Skip to content

Instantly share code, notes, and snippets.

@chipbennett
Last active August 29, 2015 13:58
Show Gist options
  • Save chipbennett/10013478 to your computer and use it in GitHub Desktop.
Save chipbennett/10013478 to your computer and use it in GitHub Desktop.
Breadcrumb Navigation
<?php
/**
* Add navigation breadcrumb
*/
function wp_nav_breadcrumb( $args = array() ) {
$defaults = array(
'wrapper' => 'div',
'wrapper_id' => 'breadcrumbs',
'wrapper_class' => '',
'container' => 'nav',
'container_id' => 'crumbs',
'container_class' => '',
'current_before' => '<strong>',
'current_after' => '</strong>',
'delimiter' => ' &raquo; ',
'home_text' => __( 'Home' ),
'blog_text' => __( 'Blog' ),
'error404_text' => __( 'Page Not Found' ),
'search_text' => __( 'Search Results' ),
'category_archive_text' => __( 'Category Archive' ),
'tag_archive_text' => __( 'Tag Archive' ),
'post_format_archive_text' => __( 'Post Format Archive' ),
'tax_archive_text' => __( 'Taxonomy Archive' ),
'author_archive_text' => __( 'Posts Published By' ),
'date_archive_text' => __( 'Posts Published in %s' ),
'post_type_archive_text' => __( 'Post Type Archive' ),
'paged_archive_text' => sprintf( __( 'Page %s' ), get_query_var( 'paged' ) ),
'paged_post_text' => sprintf( __( 'Page %s' ), get_query_var( 'page' ) ),
'show_category_hierarchy' => true,
'show_tax_hierarchy' => true,
'show_page_hierarchy' => true,
'attachment_tax' => false,
'single_post_tax' => 'category',
'single_post_type_tax' => false,
'output' => 'string',
'echo' => true
);
/**
* Parse arguments
*/
$args = wp_parse_args( $defaults, $args );
/**
* Filter arguments
*/
$args = apply_filters( 'wp_nav_breadcrumb_args', $args );
$args = (object) $args;
/**
* Early filter override
*/
$breadcrumbs = apply_filters( 'pre_wp_nav_breadcrumb', NULL );
if ( NULL !== $breadcrumbs ) {
if ( $args->echo ) {
echo $breadcrumbs;
} else {
return $breadcrumbs;
}
}
/**
* Get breadcrumb context
*/
$context = wp_nav_breadcrumb_context( $args );
/**
* Construct the breadcrumbs array, with late filter override
*/
$breadcrumbs = apply_filters( 'wp_nav_breadcrumb', wp_nav_breadcrumb_construct( $args, $context ) );
/**
* Output breadcrumb
*/
$output = ( 'string' == $args->output ? implode( '', array_values( $breadcrumbs ) : $breadcrumbs );
if ( $args->echo && 'string' == $args->output ) {
echo $output;
} else {
return $output;
}
}
/**
* Get breadcrumb context
*/
function wp_nav_breadcrumb_context( $args ) {
$defaults = array(
'base_link' => '<a href="' . home_url( '/' ) . '">' . $args->home_text . '</a>',
'hierarchy' => $args->delimiter,
'current_location' => '',
'pagination' => false
);
// Base link
if ( is_front_page() ) {
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_front_page', array(
'base_link' => false,
'hierarchy' => false,
'current_location' => $defaults->base_link
) )
);
}
// Define current location for 404 Error page
elseif ( is_404() ) {
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_404', array(
'hierarchy' => false,
'current_location' => $args->error404_text
) )
);
}
// Define current location for Search Results page
elseif ( is_search() ) {
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_search', array(
'hierarchy' => $args->search_textt . $args->delimiter,
'current_location' => get_search_query()
) )
);
}
// Define current location for the blog posts index
elseif ( is_home() ) ) {
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_blog', array(
'hierarchy' => false,
'current_location' => ( ! is_paged() ? $args->blog_text : '<a href="' . get_permalink( get_option( 'page_for_posts' ) ) . '">' . $args->blog_text . '</a>' );
) )
);
}
// Define current location for archive pages
elseif( is_archive() ) {
// Define Category Hierarchy Crumbs for Category Archive
if ( is_category() ) {
$hierarchy = $args->category_archive_text . $args->delimiter;
if ( $args->show_category_hierarchy ) {
global $wp_query;
$cat_obj = $wp_query->get_queried_object();
$cat = get_category( $cat_obj->term_id );
$parentCat = get_category ($cat->parent );
if ( $cat->parent != 0 ) {
$hierarchy .= get_category_parents( $parentCat, TRUE, $args->delimiter );
}
}
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_category', array(
'hierarchy' => $hierarchy,
'current_location' => single_cat_title( '' , FALSE )
) )
);
}
// Define current location for Tag Archives
elseif ( is_tag() ) {
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_tag', array(
'hierarchy' => $args->tag_archive_text . $args->delimiter,
'current_location' => single_tag_title( '' , FALSE )
) )
);
}
// Define current location for Post Format Archives
elseif ( is_tax( 'post_format' ) ) {
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_post_format', array(
'hierarchy' => $args->post_format_archive_text . $args->delimiter,
'current_location' => get_post_format_string( get_post_format() )
) )
);
}
// Define current location for Custom Taxonomy Archives
elseif ( is_tax() ) {
$hierarchy = $args->tax_archive_text . $args->delimiter;
if ( $args->show_tax_hierarchy ) {
global $wp_query;
$custom_tax = $wp_query->query_vars['taxonomy'];
$custom_tax_object = get_taxonomy( $custom_tax );
$post_type_object = get_post_type_object( get_post_type() );
$custom_tax_link = '<a href="' . get_post_type_archive_link( $post_type_object->name ) . '">' . $post_type_object->labels->name . '</a>';
$hierarchy = $custom_tax_link . $args->delimiter . $args->tax_archive_text . $args->delimiter;
}
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_tax', array(
'hierarchy' => $hierarchy,
'current_location' => single_term_title( '', false );
) )
);
}
// Define current location for Author Archives
elseif ( is_author() ) {
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_author', array(
'hierarchy' => $args->author_archive_text . $args->delimiter;,
'current_location' => get_the_author_meta( 'display_name', get_query_var( 'author' ) )
) )
);
}
// Define Crumbs for Day/Year/Month Date-based Archives
elseif ( is_date() ) {
$year_string = sprintf(
'<a href="%1$s">%2$s</a>',
get_year_link( get_the_time( 'Y' ) ),
get_the_time( 'Y' )
);
$month_string = sprint(
'<a href="%1$s">%2$s</a>',
get_month_link( get_the_time( 'Y' ), get_the_time( 'm' ) ),
get_the_time( 'F' )
);
// Define Year/Month Hierarchy Crumbs for Day Archive
if ( is_day() ) {
$date_string = $year_string . $args->delimiter . $month_string . $args->delimiter;
$currentLocation = get_the_time('d');
}
// Define Year Hierarchy Crumb for Month Archive
elseif ( is_month() ) {
$date_string = $year_string . $args->delimiter;
$currentLocation = get_the_time( 'F' );
}
// Set CurrentLocation for Year Archive
elseif ( is_year() ) {
$date_string = '';
$currentLocation = get_the_time( 'Y' );
}
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_date', array(
'hierarchy' => sprintf( $args->date_archive_text, $date_string ),
'current_location' => $currentLocation
) )
);
}
// Define current location for Custom Post Type Archives
elseif ( is_post_type_archive( get_post_type() ) ) {
$post_type_object = get_post_type_object( get_post_type() );
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_post_type_archive', array(
'hierarchy' => $args->post_type_archive_text . $args->delimiter,
'current_location' => $post_type_object->labels->name
) )
);
}
// Define pagination for paged Archive pages
if ( get_query_var( 'paged' ) ) {
$context['pagination'] = $args->delimiter . $args->paged_archive_text;
}
}
// Define current location for singular pages
elseif ( is_singular() ) {
if ( is_page() & ! is_front_page() ) {
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_page', array(
'hierarchy' => ( $args->show_page_hierarchy ? wp_nav_breadcrumb_page_hierarchy( $args->delimiter ) : false ),
'current_location' => get_the_title()
) )
);
}
// Define Category and Parent Post Crumbs for Post Attachments
elseif ( is_attachment() ) {
if ( $args->attachment_tax ) {
if ( 'category' == $args->attachment_tax ) {
$hierarchy = wp_nav_breadcrumb_cat_hierarchy( $args->delimiter );
} else if ( 'post_tag' == $args->attachment_tax ) {
$hierarchy = wp_nav_breadcrumb_tag_hierarchy( $args->delimiter );
} else if ( 'post_format' == $args->attachment_tax ) {
$hierarchy = wp_nav_breadcrumb_post_format_hierarchy( $args->delimiter );
} else {
$hierarchy = wp_nav_breadcrumb_tax_hierarchy( $args->attachment_tax, $args->delimiter );
}
}
// Get parent post
global $post;
$parent = get_post( $post->post_parent );
$hierarchy .= '<a href="' . get_permalink ( $parent->ID ) . '">' . $parent->post_title . '</a> ' . $args->delimiter;
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_attachment', array(
'hierarchy' => $hierarchy,
'current_location' => get_the_title()
) )
);
}
// Define Category Hierarchy Crumbs for Single Posts
elseif ( is_singular( 'post' ) ) {
if ( $args->single_post_tax ) {
if ( 'category' == $args->single_post_tax ) {
$hierarchy = wp_nav_breadcrumb_cat_hierarchy( $args->delimiter );
} else if ( 'post_tag' == $args->single_post_tax ) {
$hierarchy = wp_nav_breadcrumb_tag_hierarchy( $args->delimiter );
} else if ( 'post_format' == $args->single_post_tax ) {
$hierarchy = wp_nav_breadcrumb_post_format_hierarchy( $args->delimiter );
} else {
$hierarchy = wp_nav_breadcrumb_tax_hierarchy( $args->single_post_tax, $args->delimiter );
}
}
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_single_blog_post', array(
'hierarchy' => $hierarchy,
'current_location' => get_the_title()
) )
);
}
// Define current location for Custom Post Types
elseif ( is_singular( get_post_type() ) ) {
$post_type_object = get_post_type_object( get_post_type() );
$hierarchy .= '<a href="' . get_post_type_archive_link( $post_type_object->name ) . '">' . $post_type_object->labels->name . '</a>' . $args->delimiter;
if ( $args->single_post_type_tax ) {
global $post;
if ( $args->single_post_type_tax && in_array( $post->post_type, get_object_taxonomies( $post->post_type, $args->single_post_type_tax ) ) ) {
$hierarchy .= wp_nav_breadcrumb_tax_hierarchy( $args->single_post_type_tax, $args->delimiter );
} else {
$taxonomies = get_object_taxonomies( get_post_type() );
$tax = ( ! empty( $taxonomies ) ? $taxonomies[0] : false );
if ( $tax ) {
$hierarchy .= wp_nav_breadcrumb_tax_hierarchy( $tax, $args->delimiter );
}
}
}
$context = wp_parse_args(
$defaults,
apply_filters( 'wp_nav_breadcrumb_single_post_type', array(
'hierarchy' => $hierarchy,
'current_location' => get_the_title()
) )
);
}
// Define pagination for singular pages
if ( get_query_var( 'page' ) ) {
$context['pagination'] = $args->delimiter . $args->paged_post_text;
}
}
// Return $context
return ( isset( $context ) ? $context : $defaults );
}
/**
* Breadcrumb construct
*/
function wp_nav_breadcrumb_construct( $args, $context ) {
$breadcrumbs = array();
// Opening wrapper
$wrapper_id = ( $args->wrapper_id ? ' id="' . esc_attr( $args->wrapper_id ) . '"';
$wrapper_class = ( $args->wrapper_class ? ' class="' . esc_attr( $args->wrapper_class ) . '"';
$breadcrumbs['wrapper_open'] = '<' . $args->wrapper . $wrapper_id . $wrapper_class . '>';
// Opening container
$container_id = ( $args->container_id ? ' id="' . esc_attr( $args->container_id ) . '"';
$container_class = ( $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"';
$breadcrumbs['container_open'] = '<' . $args->container . $container_id . $container_class . '>';
// Base link
if ( $context['base_link'] ) {
$breadcrumbs['base_link'] = $context['base_link'];
}
// Contextual hierarchy
$breadcrumbs['hierarchy'] = $context['hierarchy'];
// Opening element that wraps the current page breadcrumb link
$breadcrumbs['current_before'] = $args->current_before;
// Current location
$breadcrumbs['current_location'] = $context['current_location'];
//Closing element that wraps the current page breadcrumb link
$breadcrumbs['current_after'] = $args->current_after;
// Pagination
if ( $context['pagination'] ) {
$breadcrumbs['pagination'] = $context['pagination'];
}
// Closing element that wraps entire breadcrumb output
$breadcrumbs['container_close'] = '</' . $args->container . '>';
// Closing breadcrumb element
$breadcrumbs['wrapper_close'] = '</' . $args->wrapper . '>';
// Return $breadcrumbs
return $breadcrumbs;
}
/**
* Page hierarchy
*/
function wp_nav_breadcrumb_page_hierarchy( $delimiter ) {
global $post;
if ( ! $post->post_parent ) {
return false;
} else {
$hierarchy = false;
$parent_id = $post->post_parent;
$pagecrumbs = array();
while ( $parent_id ) {
$page = get_page( $parent_id );
$pagecrumbs[] = '<a href="' . get_permalink( $page->ID ) . '">' . get_the_title( $page->ID ) . '</a>';
$parent_id = $page->post_parent;
}
$pagecrumbs = array_reverse( $pagecrumbs );
foreach ( $pagecrumbs as $crumb ) {
$hierarchy .= $crumb . $delimiter;
}
return $hierarchy;
}
}
/**
* Category hierarchy
*/
function wp_nav_breadcrumb_cat_hierarchy( $delimiter ) {
global $post;
// Ensure post type supports 'category' taxonomy
if ( ! in_array( $post->post_type, get_object_taxonomies( $post->post_type, 'category' ) ) ) {
return false;
} else {
$hierarchy = false;
$cats = get_the_category();
$cat = ( ! empty( $cats ) ? $cats[0] : false );
// Determine if category is hierarchical
if ( $cat ) {
$hierarchy .= get_category_parents( $cat->ID, TRUE, $delimiter );
}
return $hierarchy;
}
}
/**
* Tag hierarchy
*/
function wp_nav_breadcrumb_tag_hierarchy( $delimiter ) {
global $post;
// Ensure post type supports 'post_tag' taxonomy
if ( ! in_array( $post->post_type, get_object_taxonomies( $post->post_type, 'post_tag' ) ) ) {
return false;
} else {
$tags = get_the_tags( $post->ID );
if ( ! $tags ) {
return false;
}
return '<a href="' . get_tag_link( $tags[0]->ID ) . '">' . $tags[0]->name . '</a>' . $delimiter;
}
}
/**
* Post Format hierarchy
*/
function wp_nav_breadcrumb_post_format_hierarchy( $delimiter ) {
global $post;
// Ensure post type supports 'post_tag' taxonomy
if ( ! in_array( $post->post_type, get_object_taxonomies( $post->post_type, 'post_format' ) ) || ! get_post_format( $post->ID ) ) {
return false;
} else {
$post_format = get_post_format( $post->ID );
return '<a href="' . get_post_format_link( $post_format ) . '">' . get_post_format_string( $post_format ) . '</a>' . $delimiter;
}
}
/**
* Tax hierarchy
*/
function wp_nav_breadcrumb_tax_hierarchy( $tax, $delimiter ) {
global $post;
// Ensure post type supports 'category' taxonomy
if ( ! in_array( $post->post_type, get_object_taxonomies( $post->post_type, $tax ) ) ) {
return false;
} else {
$hierarchy = false;
$terms = get_the_terms( $post->ID, $tax );
if ( ! $terms ) {
return false;
}
if ( $terms[0]->parent ) {
// Get term hierarchy
$parent_id = $terms[0]->parent;
$term_crumbs = array();
while ( $parent_id ) {
$crumb = get_term_by( 'id', $parent_id, $tax );
$term_crumbs[] = '<a href="' . get_term_link( $crumb->term_id ) . '">' . $crumb->name . '</a>';
$parent_id = $crumb->parent;
}
$term_crumbs = array_reverse( $term_crumbs );
foreach ( $term_crumbs as $crumb ) {
$hierarchy .= $crumb . $delimiter;
}
}
$hierarchy .= '<a href="' . get_term_link( $terms[0]->ID ) . '">' . $terms[0]->name . '</a>' . $delimiter;
return $hierarchy;
}
}
@chipbennett
Copy link
Author

Broke out contextual breadcrumbs into subordinate functions. H/T @Kaiser

@chipbennett
Copy link
Author

Added args array and defaults, in preparation of making args array filterable, and refactoring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment