Как создать структуру ЧПУ с пользовательскими типами записей и таксономиями?

Мне нужна иерархическая таксономия. Можно ли делать то, что я хочу? Я пробовал много чего, но в итоге не работает. В лучшем случае я могу получить правильные постоянные ссылки, но по ним ошибка 404.

/basename/ 
/basename/top-cat/
/basename/top-cat/child-cat/
/basename/top-cat/child-cat/grandchild-cat/
/basename/top-cat/child-cat/grandchild-cat/post-name/

Знаю, что нужно использовать 'rewrite' => array( 'slug' => 'tax-name', 'with_front' => true, 'hierarchical' => true ), чтобы получить иерархические слаги, которые прекрасно работают на страницах архива, но пользовательские посты выдают 404. Если я удаляю 'hierarchical' => true, то теряю иерархические URL (только /basename/grandchild-cat/post-name/ работает).

Есть какие-либо решения?

Понравилась статья? Поделиться с друзьями:
WPAsk
Ответов: 2
  1. Jeff

    После объединения кучки других ответов я получил это работает! Вот решение для тех, кто тоже с этим стокнулся:

    Обратите внимание, что весь этот код, а также ваш первоначальный тип записи и код регистрации таксономии находятся в вашем файле functions.php.

    Сначала сделайте правильные свои слагы при определении своих пользовательских типов постов и таксономий: для пользовательского типа поста это должно быть basename/%taxonomy_name% а слаг для вашей таксономии должен быть просто базовым именем. Не забудьте также добавить 'hierarchical' => true в массив таксономии, чтобы получить вложенные термины в вашем URL. Также убедитесь, что для query_var установлено значение true в обоих случаях.

    Вам нужно добавить новое правило перезаписи, чтобы WordPress знал, как интерпретировать вашу структуру URL. В моем случае пользовательский тип записи URI всегда будет 5-м сегментом URI, поэтому я определил свое правило соответствующим образом. Обратите внимание, что вам, возможно, придется изменить это, если вы используете больше или меньше сегментов URI. Если у вас будут разные уровни вложенных терминов, вам нужно написать функцию, чтобы проверить, является ли последний сегмент uri пользовательским типом записи или термином таксономии, чтобы узнать, какое правило добавить.

    add_filter('rewrite_rules_array', 'mmp_rewrite_rules');
    function mmp_rewrite_rules($rules) {
        $newRules  = array();
        $newRules['basename/(.+)/(.+)/(.+)/(.+)/?$'] = 'index.php?custom_post_type_name=$matches[4]'; 
        $newRules['basename/(.+)/?$']                = 'index.php?taxonomy_name=$matches[1]'; 
    
        return array_merge($newRules, $rules);
    }
    

    Затем вам нужно добавить этот код, чтобы WordPress знал, как обрабатывать %taxonomy_name% в вашем пользовательском типе записи:

    function filter_post_type_link($link, $post)
    {
        if ($post->post_type != 'custom_post_type_name')
            return $link;
    
        if ($cats = get_the_terms($post->ID, 'taxonomy_name'))
        {
            $link = str_replace('%taxonomy_name%', get_taxonomy_parents(array_pop($cats)->term_id, 'taxonomy_name', false, '/', true), $link); 
        }
        return $link;
    }
    add_filter('post_type_link', 'filter_post_type_link', 10, 2);
    

    Я создал пользовательскую функцию на основе собственного get_category_parents:

    // моя собственная функция, чтобы делать то, что get_category_parents делает для других таксономий
    function get_taxonomy_parents($id, $taxonomy, $link = false, $separator = '/', $nicename = false, $visited = array()) {    
        $chain = '';   
        $parent = &get_term($id, $taxonomy);
    
        if (is_wp_error($parent)) {
            return $parent;
        }
    
        if ($nicename)    
            $name = $parent -> slug;        
    else    
            $name = $parent -> name;
    
        if ($parent -> parent && ($parent -> parent != $parent -> term_id) && !in_array($parent -> parent, $visited)) {    
            $visited[] = $parent -> parent;    
            $chain .= get_taxonomy_parents($parent -> parent, $taxonomy, $link, $separator, $nicename, $visited);
    
        }
    
        if ($link) {
          
        } else    
            $chain .= $name . $separator;    
        return $chain;    
    }
    

    Затем вам нужно очистить ваши постоянные ссылки (просто загрузите страницу настроек постоянных ссылок).

    Теперь все должно работать.

    Надеюсь, что это поможет вам!

    1. Jeff

      Не уверен, не увидев ваш код, но поищите место, где вы вручную определяете косую черту перед названием вашего поста. Если не можете отследить, где вы добавляете дополнительную косую черту, то можете просто убрать последний символ из возвращенного значения функции get_taxonomy_parents, вызванной в filter_post_type_link. Удачи.

Добавить ответ

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: