Хлібні крихти worpdress від Kama_Breadcrumbs з itemprop="position"

Код для виведення шаблону 

<?php if( function_exists('kama_breadcrumbs') ) kama_breadcrumbs(); ?>

код, який потрібно додати function.php

/**
 * Хлібні крихти для WordPress (breadcrumbs)
 *
 * @param string [$sep = ''] Розділювач. За замовчуванням ' " '
 * @param array [$l10n = array()] Для локалізації. Див. змінну $default_l10n.
 * @param array [$args = array()] Опції. Див. змінну $def_args
 * @return string Виводить на екран HTML код
 *
 * version 3.3.2
 */
function kama_breadcrumbs( $sep = ' » ', $l10n = array(), $args = array() ){
  $kb = новий Kama_Breadcrumbs;
  echo $kb->get_crumbs( $sep, $l10n, $args );
}

class Kama_Breadcrumbs {

  public $arg;

  // Локалізація
  static $l10n = array(
    'home' => 'Головна',
    'paged' => 'Сторінка %d',
    '_404' => 'Помилка 404',
    'search' => 'Результати пошуку за запитом - <b>%s</b>',
    'author' => 'Архів автора: <b>%s</b>',
    'year' => 'Архів за <b>%d</b> рік',
    'month' => 'Архів за: <b>%s</b>',
    'day' => '',
    'attachment' => 'Медіа: %s',
    'tag' => 'Записи позначки: <b>%s</b>',
    'tax_tag' => '%1$s з "%2$s" за тегом: <b>%3$s</b>',
    // tax_tag виведе: 'тип_запису з "назва_такси" за тегом: имя_терміна'.
    // Якщо потрібні окремі холдери, наприклад, тільки ім'я терміна, пишемо так: 'записи за тегом: %3$s'
  );

  // Параметри за замовчуванням
  static $args = array(
    'on_front_page' => true, // виводити крихти на головній сторінці
    'show_post_title' => true, // чи показувати назву запису наприкінці (останній елемент). Для записів, сторінок, вкладень
    'show_term_title' => true, // чи показувати назву елемента таксономії наприкінці (останній елемент). Для міток, рубрик та інших такс
    'title_patt' => '<span class="kb_title">%s</span>', // шаблон для останнього заголовка. Якщо увімкнено: show_post_title або show_term_title
    'last_sep' => true, // показувати останній роздільник, коли заголовок наприкінці не відображається
    'markup' => 'schema.org', // 'markup' - мікророзмітка. Можливо: 'rdf.data-vocabulary.org', 'schema.org', '' - без мікророзмітки
                       // або можна вказати свій масив розмітки:
                       // array( 'wrappatt'=>'<div class="kama_breadcrumbs">%s</div>', 'linkpatt'=>'<a href="%s">%s< /a>', 'sep_after'=>'', )
    'priority_tax' => array('category'), // пріоритетні таксономії, коли потрібно запис у кількох таксах
    'priority_terms' => array(), // 'priority_terms' - пріоритетні елементи таксономії, коли запис знаходиться в декількох елементах однієї такси одночасно.
                    // Наприклад: array( 'category'=>array(45,'term_name'), 'tax_name'=>array(1,2,'name') )
                    // 'category' - такса для якої вказуються пріор. елементи: 45 - ID терміна та 'term_name' - ярлик.
                    // порядок 45 і 'term_name' має значення: що раніше тим важливіше. Усі зазначені терміни важливіші за невказані...
    'nofollow' => false, // додавати rel=nofollow до посилань?

    // службові
    'sep' => '',
    'linkpatt' => '',
    'pg_end' => '',
  );

  function get_crumbs( $sep, $l10n, $args ){
    global $post, $wp_query, $wp_post_types;

    self::$args['sep'] = $ sep;

    // Фільтрує дефолти та зливає
    $loc = (object) array_merge( apply_filters('kama_breadcrumbs_default_loc', self::$l10n ), $l10n );
    $arg = (object) array_merge( apply_filters('kama_breadcrumbs_default_args', self::$args ), $args );

    $arg->sep = '<span class="kb_sep">'. $arg->sep .'</span>'; // доповнимо

    // спростимо
    $sep = & $arg->sep;
    $this->arg = & $arg;

    // мікророзмітка ---
    if(1){
      $mark = & $arg->markup;

      // Розмітка за замовчуванням
      if( ! $mark ) $mark = array(
        'wrappatt' => '<div class="kama_breadcrumbs">%s</div>',
        'linkpatt' => '<a href="%s">%s</a>',
        'sep_after' => '',
      );
      // rdf
      elseif( $mark === 'rdf.data-vocabulary.org' ) $mark = array(
        'wrappatt' => '<div class="kama_breadcrumbs" prefix="v: http://rdf.data-vocabulary.org/#">%s</div>',
        'linkpatt' => '<span typeof="v:Breadcrumb"><a href="%s" rel="v:url" property="v:title">%s</a>',
        'sep_after' => '</span>', // закриваємо span після роздільника!
      );
      // schema.org
      elseif( $mark === 'schema.org' ) $mark = array(
        'wrappatt' => '<div class="kama_breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList">%s</div>',
        'linkpatt' => '<span itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="%s" itemprop="item"><span itemprop="name"&gt ;%s</span><meta itemprop="position" content="$d"></a></span>',
        'sep_after' => '',
      );

      elseif( ! is_array($mark) )
        die( __CLASS__ .': "markup" parameter must be array...');

      $wrappatt = $mark['wrappatt'];
      $arg->linkpatt = $arg->nofollow ? str_replace('<a','<a rel="nofollow"', $mark['linkpatt']) : $mark['linkpatt'];
      $arg->sep .= $mark['sep_after']."\n";
    }

    $linkpatt = $arg->linkpatt; // спростимо

    $q_obj = get_queried_object();

    // може це архів порожньої такси?
    $ ptype = null;
    if( empty($post) ){
      if( isset($q_obj->taxonomy) )
        $ptype = & $wp_post_types[ get_taxonomy($q_obj->taxonomy)->object_type[0] ];
    }
    else $ptype = & $wp_post_types[ $post->post_type ];

    // paged
    $arg->pg_end = '';
    if( ($paged_num = get_query_var('paged')) || ($paged_num = get_query_var('page')) )
      $arg->pg_end = $sep . sprintf( $loc->paged, (int) $paged_num );

    $pg_end = $arg->pg_end; // спростимо

    // ну, з богом...
    $out = '';

    if( is_front_page() ){
      return $arg->on_front_page ? sprintf( $wrappatt, ( $paged_num ? sprintf($linkpatt, get_home_url(), $loc->home) . $pg_end : $loc->home ) ) : '';
    }
    // сторінка записів, коли головною встановлена ​​окрема сторінка.
    elseif( is_home() ) {
      $out = $paged_num? ( sprintf( $linkpatt, get_permalink($q_obj), esc_html($q_obj->post_title) ) . $pg_end ) : esc_html($q_obj->post_title);
    }
    elseif( is_404() ){
      $out = $loc->_404;
    }
    elseif( is_search() ){
      $out = sprintf( $loc->search, esc_html( $GLOBALS['s'] ) );
    }
    elseif( is_author() ){
      $tit = sprintf( $loc->author, esc_html($q_obj->display_name) );
      $out = ( $paged_num ? sprintf( $linkpatt, get_author_posts_url( $q_obj->ID, $q_obj->user_nicename ) . $pg_end, $tit ) : $tit );
    }
    elseif( is_year() || is_month() || is_day() ){
      $y_url = get_year_link( $year = get_the_time('Y') );

      if( is_year() ){
        $tit = sprintf( $loc->year, $year );
        $out = ( $paged_num ? sprintf($linkpatt, $y_url, $tit) . $pg_end : $tit );
      }
      // month day
      else {
        $ y_link = sprintf ($ linkpatt, $ y_url, $ year);
        $m_url = get_month_link( $year, get_the_time('m') );

        if( is_month() ){
          $tit = sprintf( $loc->month, get_the_time('F') );
          $out = $y_link. $ sep . ( $paged_num ? sprintf( $linkpatt, $m_url, $tit ) . $pg_end : $tit );
        }
        elseif( is_day() ){
          $m_link = sprintf( $linkpatt, $m_url, get_the_time('F'));
          $out = $y_link. $ sep . $m_link. $ sep . get_the_time('l');
        }
      }
    }
    // Деревоподібні записи
    elseif( is_singular() && $ptype->hierarchical ){
      $out = $this->_add_title( $this->_page_crumbs($post), $post );
    }
    // Такси, плоскі записи та вкладення
    else {
     
      $term = $q_obj; // таксономії

      // визначаємо термін для записів (включаючи вкладення attachments)
      if( is_singular() ){
        // Змінимо $post, щоб визначити термін батька вкладення
        if( is_attachment() && $post->post_parent ){
          $save_post = $post; // збережемо
          $post = get_post($post->post_parent);
        }

        // враховує якщо вкладення прикріплюються до деревоподібних - все буває :)
        $taxonomies = get_object_taxonomies( $post->post_type );
        // залишимо лише деревоподібні та публічні, чи мало...
        $taxonomies = array_intersect( $taxonomies, get_taxonomies( array('hierarchical' => true, 'public' => true) ) );

        if( $taxonomies ){
          // сортуємо за пріоритетом
          if( ! empty($arg->priority_tax) ){
            usort( $taxonomies, function($a,$b)use($arg){
              $a_index = array_search($a, $arg->priority_tax);
              if( $a_index === false ) $a_index = 9999999;

              $b_index = array_search($b, $arg->priority_tax);
              if( $b_index === false ) $b_index = 9999999;

              return ($b_index === $a_index)? 0 : ($ b_index < $a_index? 1: -1); // менше індекс - вище
            } );
          }

          // пробуємо отримати терміни, у порядку пріоритету такс
          foreach( $taxonomies as $taxname ){
            if( $terms = get_the_terms( $post->ID, $taxname ) ){
              // Перевіримо пріоритетні терміни для такси
              $prior_terms = & $arg->priority_terms[ $taxname ];
              if( $prior_terms && count($terms) > 2 ){
                foreach( (array) $prior_terms as $term_id ){
                  $filter_field = is_numeric($term_id)? 'term_id': 'slug';
                  $_terms = wp_list_filter( $terms, array($filter_field=>$term_id) );

                  if( $_terms ){
                    $term = array_shift($_terms);
                    break;
                  }
                }
              }
              else
                $ Term = array_shift ($ Terms);

              break;
            }
          }
        }

        if( isset($save_post) ) $post = $save_post; // Повернемо назад (для вкладень)
      }

      // Висновок

      // всі види записів з термінами чи терміни
      if( $term && isset($term->term_id) ){
        $term = apply_filters('kama_breadcrumbs_term', $term);

        // attachment
        if( is_attachment() ){
          if( ! $post->post_parent )
            $out = sprintf( $loc->attachment, esc_html($post->post_title) );
          else {
            if( ! $out = apply_filters('attachment_tax_crumbs', '', $term, $this ) ){
              $_crumbs = $this->_tax_crumbs( $term, 'self' );
              $parent_tit = sprintf( $linkpatt, get_permalink($post->post_parent), get_the_title($post->post_parent) );
              $_out = implode( $sep, array($_crumbs, $parent_tit) );
              $out = $this->_add_title( $_out, $post );
            }
          }
        }
        // single
        elseif( is_single() ){
         
          if( ! $out = apply_filters('post_tax_crumbs', '', $term, $this ) ){
            $_crumbs = $this->_tax_crumbs( $term, 'self' );
            $out = $this->_add_title( $_crumbs, $post );
          }
        }
        // не деревоподібна такса (мітки)
        elseif( ! is_taxonomy_hierarchical($term->taxonomy) ){
          // мітка
          if( is_tag() )
            $out = $this->_add_title('', $term, sprintf( $loc->tag, esc_html($term->name) ) );
          // Такса
          elseif( is_tax() ){
            $post_label = $ptype->labels->name;
            $tax_label = $GLOBALS['wp_taxonomies'][ $term->taxonomy ]->labels->name;
            $out = $this->_add_title('', $term, sprintf( $loc->tax_tag, $post_label, $tax_label, esc_html($term->name) ) );
          }
        }
        // Деревоподібна такса (рибрики)
        else {
          if( ! $out = apply_filters('term_tax_crumbs', '', $term, $this ) ){
            $_crumbs = $this->_tax_crumbs( $term, 'parent' );
            $out = $this->_add_title( $_crumbs, $term, esc_html($term->name) );
          }
        }
      }
      // Вложення від запису без термінів
      elseif( is_attachment() ){
        $parent = get_post($post->post_parent);
        $parent_link = sprintf( $linkpatt, get_permalink($parent), esc_html($parent->post_title) );
        $_out = $parent_link;

        // Вкладення від запису деревоподібного типу запису
        if( is_post_type_hierarchical($parent->post_type) ){
          $parent_crumbs = $this->_page_crumbs($parent);
          $_out = implode( $sep, array( $parent_crumbs, $parent_link ) );
        }

        $out = $this->_add_title( $_out, $post );
      }
      // записи без термінів
      elseif( is_singular() ){
        $out = $this->_add_title('', $post);
      }
    }

    // Заміна посилання на архівну сторінку для типу запису
    $home_after = apply_filters('kama_breadcrumbs_home_after', '', $linkpatt, $sep, $ptype );

    if( '' === $home_after ){
      // Посилання на архівну сторінку типу запису для окремих сторінок цього типу; архівів цього; таксономій пов'язаних із цим типом.
      if( $ptype && $ptype->has_archive && ! in_array( $ptype->name, array('post','page','attachment') )
        && ( is_post_type_archive() || is_singular() || (is_tax() && in_array($term->taxonomy, $ptype->taxonomies)) )
      ){
        $pt_title = $ptype->labels->name;

        // перша сторінка архіву типу запису
        if( is_post_type_archive() && ! $paged_num )
          $home_after = sprintf( $this->arg->title_patt, $pt_title );

        // singular, paged post_type_archive, tax
        else{
          
          // $ Posioo = 1;
          $home_after = sprintf( $linkpatt, get_post_type_archive_link($ptype->name), $pt_title, $posioo-- );

          $home_after .= ( ($paged_num && ! is_tax()) ? $pg_end : $sep ); // пагінація
        }
      }
    }

    $before_out = sprintf( $linkpatt, home_url(), $loc->home , $posioo--) . ( $home_after ? $sep.$home_after : ($out ? $sep : '') );

    $out = apply_filters('kama_breadcrumbs_pre_out', $out, $sep, $loc, $arg);

    $out = sprintf($wrappatt, $before_out. $out);
            
            $count_link = count(explode('$d',$out));
            
            $ iii = 1;
            foreach (explode('$d',$out) як $value) {
              $replace_out .= $value.$iii++;
              
            }
             $out = substr($replace_out, 0, -1);
             
    return apply_filters('kama_breadcrumbs', $out, $sep, $loc, $arg);
  }

  function _page_crumbs( $post ){
    $parent = $post->post_parent;

    $crumbs = array();
    while( $parent ){
      $ page = get_post ($ parent);
      $crumbs[] = sprintf( $this->arg->linkpatt, get_permalink($page), esc_html($page->post_title) );
      $parent = $page->post_parent;
    }

    return implode( $this->arg->sep, array_reverse($crumbs) );
  }

  function _tax_crumbs( $term, $start_from = 'self' ){
    $ termlinks = array ();
    $term_id = ($start_from === 'parent') ? $term->parent : $term->term_id;
    while( $term_id ){
      $term = get_term( $term_id, $term->taxonomy);
      $termlinks[] = sprintf( $this->arg->linkpatt, get_term_link($term), esc_html($term->name) );
      $term_id = $term->parent;
    }

    if( $termlinks )
      return implode( $this->arg->sep, array_reverse($termlinks) ) /*. $this->arg->sep*/;
    return '';
  }

  // додає заголовок до переданого тексту, з урахуванням всіх опцій. Додає роздільник на початок, якщо треба.
  function _add_title( $add_to, $obj, $term_title = '' ){
    $arg = & $this->arg; // спростимо...
    $title = $term_title? $term_title : esc_html($obj->post_title); // $term_title чиститися окремо, теги можуть бути...
    $show_title = $term_title? $arg->show_term_title : $arg->show_post_title;

    // пагінація
    if( $arg->pg_end ){
      $link = $term_title? get_term_link($obj) : get_permalink($obj);
      $add_to .= ($add_to ? $arg->sep : '') . sprintf( $arg->linkpatt, $link, $title ) . $arg->pg_end;
    }
    // доповнюємо - ставимо sep
    elseif( $add_to ){
      if( $show_title )
        $add_to .= $arg->sep . sprintf( $arg->title_patt, $title );
      elseif( $arg->last_sep )
        $add_to .= $arg->sep;
    }
    // sep буде потім...
    elseif( $show_title )
      $add_to = sprintf( $arg->title_patt, $title );

    return $add_to;
  }

}

/**
 * Зміни:
 * 3.3 – нові хуки: attachment_tax_crumbs, post_tax_crumbs, term_tax_crumbs. Дозволяють доповнити крихти таксономій.
 * 3.2 - баг з роздільником, з відключеним 'show_term_title'. Стабілізував логіку.
 * 3.1 - баг з esc_html() для заголовка термінів - з тегами виходило криво...
 * 3.0 - Обернув у клас. Додав опції: 'title_patt', 'last_sep'. Доопрацював код. Додав пагінацію для постів.
 * 2.5 - ADD: Опція 'show_term_title'
 * 2.4 - Дрібні правки коду
 * 2.3 - ADD: Сторінка записів, коли для головної встановлено окрему сторінку.
 * 2.2 - ADD: Link to post type archive on taxonomies page
 * 2.1 - ADD: $sep, $loc, $args params to hooks
 * 2.0 - ADD: у фільтр 'kama_breadcrumbs_home_after' доданий четвертий аргумент $ptype
 * 1.9 - ADD: фільтр 'kama_breadcrumbs_default_loc' для зміни локалізації за умовчанням
 * 1.8 - FIX: нотатки, коли в рубриці немає записів
 * 1.7 - Поліпшено роботу з пріоритетними таксономіями.
 */