Задача
Необходимо создать новый тип записей и таксономий, связанных между собой, с учётом иерархии таксономий с неограниченным уровнем вложенности.
А также настроить для них ЧПУ (человеку понятные url-адреса) следующего вида:
domain/catalog/category/tovar/
domain/catalog/category/sub-category/
domain/catalog/category/sub-category/tovar/
Решение
Используйте следующий код в function.php или в своём плагине:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
<?php //Регистрация нового типа записей add_action( 'init', 'register_post_types', 0 ); function register_post_types(){ register_post_type('tovar', array( 'label' => null, 'labels' => array( 'name' => 'Товары', // основное название для типа записи 'singular_name' => 'Товар', // название для одной записи этого типа 'add_new' => 'Добавить товар', // для добавления новой записи 'add_new_item' => 'Добавление товара', // заголовка у вновь создаваемой записи в админ-панели. 'edit_item' => 'Редактирование товара', // для редактирования типа записи 'new_item' => 'Новый товар', // текст новой записи 'view_item' => 'Смотреть товар', // для просмотра записи этого типа. 'search_items' => 'Искать товар', // для поиска по этим типам записи 'not_found' => 'Не найдено', // если в результате поиска ничего не было найдено 'not_found_in_trash' => 'Не найдено в корзине', // если не было найдено в корзине 'parent_item_colon' => '', // для родителей (у древовидных типов) 'menu_name' => 'Каталог', // название меню 'all_items' => 'Все товары', ), 'description' => '', 'public' => true, 'show_in_menu' => true, // показывать ли в меню адмнки 'show_in_rest' => null, // добавить в REST API. C WP 4.7 'rest_base' => null, // $post_type. C WP 4.7 'menu_position' => 4, 'menu_icon' => 'dashicons-list-view', 'hierarchical' => false, 'supports' => [ 'title', 'editor', 'thumbnail' ], // 'title','editor','author','thumbnail','excerpt','trackbacks','custom-fields','comments','revisions','page-attributes','post-formats' 'has_archive' => false, 'rewrite' => array( 'slug'=>'catalog', 'with_front' => false ), 'query_var' => true, ) ); } //Регистрация нового типа таксономий add_action( 'init', 'create_taxonomy', 0 ); function create_taxonomy(){ register_taxonomy( 'catalog', [ 'tovar' ], [ 'label' => '', // определяется параметром $labels->name 'labels' => [ 'name' => 'Категории', 'singular_name' => 'Категории', 'search_items' => 'Поиск категории', 'all_items' => 'Все категории', 'view_item ' => 'Показать категорию', 'parent_item' => 'Родительская категория', 'parent_item_colon' => 'Родительская категория:', 'edit_item' => 'Редактировать категорию', 'update_item' => 'Обновить категорию', 'add_new_item' => 'Добавить новую категорию', 'new_item_name' => 'Новая категория', 'menu_name' => 'Категории', ], 'description' => '', // описание таксономии 'public' => true, 'hierarchical' => true, 'rewrite' => array( 'slug'=>'catalog', 'hierarchical'=>true, 'with_front' => false ), 'capabilities' => array(), 'meta_box_cb' => null, // html метабокса. callback: `post_categories_meta_box` или `post_tags_meta_box`. false — метабокс отключен. 'show_admin_column' => false, // авто-создание колонки таксы в таблице ассоциированного типа записи. (с версии 3.5) 'show_in_rest' => null, // добавить в REST API 'rest_base' => null, // $taxonomy ] ); } //Изменяем структуру ссылок записей add_filter('post_type_link', 'products_permalink', 1, 2); function products_permalink( $permalink, $post ){ if( strpos($permalink, 'catalog') === FALSE )return $permalink; $terms = get_the_terms($post, 'catalog'); if( ! is_wp_error($terms) && !empty($terms) && is_object($terms[0]) ){ $taxonomy_slug = get_term_parents_list( $terms[0]->term_id, 'catalog', array( 'separator' => '/', 'format' => 'slug', 'link' => false, 'inclusive' => true, ) ); $taxonomy_slug = trim($taxonomy_slug, '/'); }else{$taxonomy_slug = 'categories';} return str_replace('catalog', 'catalog/'.$taxonomy_slug, $permalink ); } //Создаём новые правила перезаписи function taxonomy_slug_rewrite($wp_rewrite) { $rules = array(); $taxonomies = get_terms( array( 'taxonomy' => 'catalog', 'hide_empty' => false ) ); foreach($taxonomies as $taxonomy){ $taxonomy_slug = get_term_parents_list( $taxonomy->term_id, 'catalog', array( 'separator' => '/', 'format' => 'slug', 'link' => false, 'inclusive' => true, )); $rules['^catalog/'.$taxonomy_slug.'?$'] = 'index.php?'.$taxonomy->taxonomy.'='.$taxonomy->slug; } $rules['^catalog/([^/]*)/?$'] = 'index.php?catalog=$matches[1]'; $rules['^catalog/(.+?)/page/?([0-9]{1,})/?$'] = 'index.php?catalog=$matches[1]&paged=$matches[2]'; $rules['^catalog/(.+?)/([^/]*)/?$'] = 'index.php?tovar=$matches[2]'; $wp_rewrite->rules = $rules + $wp_rewrite->rules; } add_filter('generate_rewrite_rules', 'taxonomy_slug_rewrite'); //Обновляем правила перезаписи при создании/удалении/изменении таксономий add_action('created_catalog', 'hc_reset_rewrite_rules'); add_action('delete_catalog', 'hc_reset_rewrite_rules'); add_action('edited_catalog', 'hc_reset_rewrite_rules'); function hc_reset_rewrite_rules(){ flush_rewrite_rules(); } |
Таким образом был создан каталог товаров. Вы конечно можете использовать свои названия записей и таксономий и создать например портфолио работ или каталог проектов, на ваше усмотрение.
Разъяснения
Вся сложность создания таких url заключается в том, что система не может выдавать записи и таксономии одновременно через одинаковый слаг (в нашем случае catalog). Происходит это из-за того что для записей и таксономий создаются абсолютно одинаковые правила декодирования url-адресов, так называемые «правила перезаписи».
Чтобы преодолеть эту сложность, необходима функция создания таких правил и функция их перезаписи. Функция перезаписи должна срабатывать при создании/изменении/удалении таксономий для чего используем хуки WordPress.
Супер статья, огромное спасибо. Подскажите, а можно ли как-то удалить catalog из урла по итогу?
Если удалить "catalog" из url, система не поймёт где кастомные записи и таксономии, а где родные рубрики и записи. Даже если гипотетически предположить, что это бы работало, например создавая уникальное правило для каждой новой страницы, то в случае когда название рубрики и записи совпадёт с названием кастомной таксономии и кастомной записи — WordPress не сможет корректно отобразить страницу, сработало бы первое правило найденное в массиве. Именно чтобы не возникало таких багов мы отделяем кастомные подсистемы слагом.
Если в вашей системе есть только каталог, используйте стандартные рубрики и записи. Их можно кастомизировать для админ-панели при желании. Тогда от слага catalog можно было бы избавиться.
У меня такая проблема что я хочу вместо slug кастомной записи вставить динамеческую, которая формируется из родительских рубрик (категорий), например site.com/category/category-chld/post-name
Заменим слаг на %category% я получаю нужный результат в урле, но пост возвращает 404 ошибку…
Как с этим бороться?