Как создать структуру перманентных ссылок с пользовательскими таксономиями и пользовательскими типами записей, например base-name/parent-tax/child-tax/custom-post-type-name

Вопрос или проблема

Я прочесал этот сайт и Google в поисках ответа, но ничего не нашел. В принципе, я хочу сделать ровно то, что спрашивается в этом посте, но мне нужна иерархическая таксономия. Ответ, данный в том посте, работает отлично, но только с одноуровневыми таксономиями. Возможно ли сделать то, что я хочу? Я попробовал миллион вариантов, но ни один не сработал, в лучшем случае я получаю правильные постоянные ссылки, но они выдают ошибку 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/ работает).

Есть ли какие-нибудь решения? Огромное спасибо, это сводит меня с ума уже около трех недель.

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

Этот пост и этот помогли мне, так что спасибо тем парням.

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

Сначала правильно задайте свои слаги при определении пользовательских типов постов и таксономий: для пользовательского типа поста это должно быть basename/%taxonomy_name%, а слаг для вашей таксономии должен быть просто basename. Не забудьте также добавить '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]'; // моя пользовательская структура всегда будет содержать имя поста в качестве 5-го сегмента URI
    $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, "https://wordpress.stackexchange.com/", true), $link); // см. пользовательскую функцию, описанную ниже
    }
    return $link;
}
add_filter('post_type_link', 'filter_post_type_link', 10, 2);

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

// моя собственная функция, чтобы сделать то, что делает get_category_parents для других таксономий
function get_taxonomy_parents($id, $taxonomy, $link = false, $separator="https://wordpress.stackexchange.com/", $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;    
}

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

Теперь все ‘должно’ работать, надеюсь! Создайте множество терминов таксономии и правильно вложите их, а затем создайте несколько постов пользовательского типа и правильно их категоризируйте. Вы также можете создать страницу со слагом basename, и все должно работать так, как я указал в своем вопросе. Вы можете также создать несколько страниц архивов пользовательской таксономии, чтобы контролировать, как они выглядят, и добавить какой-нибудь плагин виджета таксономии для отображения ваших вложенных категорий в боковой панели.

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

Обратите внимание на этот плагин (теперь на GitHub). Он предоставляет иерархические URL для категорий, но вы можете легко адаптировать его для любой таксономии.

Создание правил основывается на рекурсивной функции.

Для работы с разным уровнем вложенности,

/basename/top-cat/ -> Архив верхней категории
/basename/top-cat/post-name/ -> Пост в верхней категории
/basename/top-cat/child-cat/ -> Архив дочерней категории
/basename/top-cat/child-cat/post-name/ -> Пост в дочерней категории

В конечном итоге я использовал решение Джеффа без фильтра rewrite_rules_array. Вместо этого я использовал фильтр request, чтобы проверить, является ли последняя часть URL допустимым именем поста и добавить его в переменные запроса.

Например,

function vk_query_vars($qvars){
    if(is_admin()) return $qvars;
    $custom_taxonomy = 'product_category';
    if(array_key_exists($custom_taxonomy, $qvars)){
        $custom_post_type="product";

        $pathParts = explode("https://wordpress.stackexchange.com/", $qvars[$custom_taxonomy]);
        $numParts = sizeof($pathParts);

        $lastPart = array_pop($pathParts);
        $post = get_page_by_path($lastPart, OBJECT, $custom_post_type);
        if( $post && !is_wp_error($post) ){
            $qvars['p'] = $post->ID;
            $qvars['post_type'] = $custom_post_type;
        }
    }
    return $qvars;
}
add_filter('request', 'vk_query_vars');

Вот мой взгляд на решение Джеффа. Фильтр rewrite_rules_array может не понадобиться в зависимости от вашего применения. Это упрощает filter_post_type_link и не требует дополнительных функций. Он использует встроенный get_term_parents_list()

function PLUGIN_filter_post_type_link($post_link, $post)
{
    $postTypes = ['CUSTOM-POST-TYPE'];
    $taxonomy = 'TAXONOMY';

    /* если тип поста совпадает */
    if (in_array($post->post_type, $postTypes, $strict=true)) {
        /* если таксономия назначена */
        if ($terms = get_the_terms($post->ID, $taxonomy)
        ) {
            $args = [
                'format' => 'slug',
                'separator' => "https://wordpress.stackexchange.com/",
                'link' => false,
                'inclusive' => true,
            ];

            return str_replace(
                "%{$taxonomy}%",
                rtrim(
                    get_term_parents_list($terms[0]->term_id, $taxonomy, $args),
                    "/"
                ),
                $post_link);
        }
        /* удаление таксономии и косой черты из post_link */
        return str_replace("%{$taxonomy}%/", '', $post_link);
    }
    return $post_link;
}

Ответ или решение

Для создания структуры постоянных ссылок (читай: permalink) с использованием пользовательских таксономий и пользовательских типов записей в WordPress, позволяющих формировать URL вида base-name/parent-tax/child-tax/custom-post-type-name, необходимо выполнить несколько шагов, начиная с регистрации пользовательских типов записей и таксономий, и заканчивая добавлением правил перезаписи для корректной работы URL.

Шаг 1: Регистрация пользовательских типов записей и таксономий

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

// Регистрация пользовательского типа записи
function register_custom_post_type() {
    register_post_type('custom_post_type_name', array(
        'labels' => array(
            'name' => 'Custom Posts',
            'singular_name' => 'Custom Post',
        ),
        'public' => true,
        'rewrite' => array('slug' => 'basename/%taxonomy_name%'),
        'has_archive' => true,
        'supports' => array('title', 'editor', 'thumbnail'),
    ));
}
add_action('init', 'register_custom_post_type');

// Регистрация иерархической таксономии
function register_custom_taxonomy() {
    register_taxonomy('taxonomy_name', 'custom_post_type_name', array(
        'labels' => array(
            'name' => 'Taxonomies',
            'singular_name' => 'Taxonomy',
        ),
        'public' => true,
        'hierarchical' => true,
        'rewrite' => array('slug' => 'basename', 'with_front' => false),
    ));
}
add_action('init', 'register_custom_taxonomy');

Шаг 2: Добавление правил перезаписи

WordPress использует систему правил перезаписи (rewrite rules) для интерпретации URL. Чтобы корректно обрабатывать ваши настраиваемые URL, добавьте следующее:

function custom_rewrite_rules($rules) {
    $new_rules = array();
    // Правило для доступа к пользовательским записям
    $new_rules['basename/(.+)/(.+)/(.+)/(.+)/?$'] = 'index.php?taxonomy_name=$matches[1]&custom_post_type_name=$matches[4]';
    // Правила для архивов таксономий
    $new_rules['basename/(.+)/?$'] = 'index.php?taxonomy_name=$matches[1]';

    return array_merge($new_rules, $rules);
}
add_filter('rewrite_rules_array', 'custom_rewrite_rules');

Шаг 3: Формирование ссылок на записи

Теперь вам нужно убедиться, что ссылки на ваши пользовательские записи формируются правильно. Используйте следующий фильтр:

function filter_post_type_link($link, $post) {
    if ($post->post_type != 'custom_post_type_name') return $link;

    if ($terms = get_the_terms($post->ID, 'taxonomy_name')) {
        $link = str_replace('%taxonomy_name%', get_term_parents_list(array_pop($terms)->term_id, 'taxonomy_name', array('format' => 'slug', 'separator' => '/', 'link' => false)), $link);
    }
    return $link;
}
add_filter('post_type_link', 'filter_post_type_link', 10, 2);

Шаг 4: Обновление правил постоянных ссылок

После внесения всех изменений обязательно обновите настройки постоянных ссылок в админке WordPress. Для этого просто зайдите в Настройки -> Постоянные ссылки и нажмите кнопку Сохранить изменения без необходимости вносить изменения.

Шаг 5: Создание пользовательских страниц

Теперь вы можете создавать страницы и пользовательские записи, используя разработанную структуру URL. Вы можете также дополнить функциональность, добавив архивные страницы для ваших таксономий и настроив внешний вид выводимых данных.

Дополнительные рекомендации

  • Проверьте работу всех ссылок и убедитесь, что ваша навигация работает корректно.
  • Если вы хотите вывести таксономические категории в сайдбаре, рассмотрите возможность использования виджетов или плагинов для таксономий.
  • Для динамического формата URL в зависимости от уровня вложенности категорий может потребоваться использование дополнительных функций для обработки запросов.

Следуя данным шагам, вы сможете создать более сложную иерархическую структуру постоянных ссылок в WordPress, включающую пользовательские таксономии и типы записей.

Оцените материал
Добавить комментарий

Капча загружается...