Как правильно присвоить шаблон страницы для кастомного типа записи?
Салют всем!
Задача: присвоить шаблон страницы для кастомного типа записи
Ожидание: пост кастомного типа записи открывается по адресу "домен/страна/город/университет/каталог-курсов/курс", где "страна" и "город" это кастомные таксономии присвоенные для поста кастомного типа записи "университет", а "курс" это кастомного типа записи "курсы"
Вводные:
Регистрация кастомного типа записи "курсы":
register_post_type( 'courses', [ 'label' => null, 'labels' => [ 'name' => 'Courses', // основное название для типа записи 'singular_name' => 'Course', // название для одной записи этого типа 'add_new' => 'Add Course', // для добавления новой записи 'add_new_item' => 'Add Course', // заголовка у вновь создаваемой записи в админ-панели. 'edit_item' => 'Edit Course', // для редактирования типа записи 'new_item' => 'New Course', // текст новой записи 'view_item' => 'View Course', // для просмотра записи этого типа. 'search_items' => 'Search Course', // для поиска по этим типам записи 'not_found' => 'Not found Course', // если в результате поиска ничего не было найдено 'not_found_in_trash' => 'Not found Course in trash', // если не было найдено в корзине 'parent_item_colon' => '', // для родителей (у древовидных типов) 'menu_name' => 'Courses', // название меню ], 'description' => 'Educate Online Courses', 'public' => true, // 'publicly_queryable' => null, // зависит от public // 'exclude_from_search' => null, // зависит от public // 'show_ui' => null, // зависит от public 'show_in_nav_menus' => true, // зависит от public 'show_in_menu' => null, // показывать ли в меню админки // 'show_in_admin_bar' => null, // зависит от show_in_menu 'show_in_rest' => null, // добавить в REST API. C WP 4.7 'rest_base' => null, // $post_type. C WP 4.7 'menu_position' => null, 'menu_icon' => 'dashicons-welcome-learn-more', //'capability_type' => 'post', //'capabilities' => 'post', // массив дополнительных прав для этого типа записи //'map_meta_cap' => null, // Ставим true чтобы включить дефолтный обработчик специальных прав 'hierarchical' => true, 'supports' => [ 'title','editor','author','thumbnail','excerpt','trackbacks','custom-fields','comments','revisions','page-attributes','post-formats' ], // 'title','editor','author','thumbnail','excerpt','trackbacks','custom-fields','comments','revisions','page-attributes','post-formats' 'taxonomies' => true, 'has_archive' => 'courses', 'rewrite' => array( 'slug' => 'universities/%country%/%city%/%university%/courses', 'with_front' => true, 'feeds' => false, 'pages' => true, ), 'query_var' => true, ] ); |
register_post_type( 'courses', [ 'label' => null, 'labels' => [ 'name' => 'Courses', // основное название для типа записи 'singular_name' => 'Course', // название для одной записи этого типа 'add_new' => 'Add Course', // для добавления новой записи 'add_new_item' => 'Add Course', // заголовка у вновь создаваемой записи в админ-панели. 'edit_item' => 'Edit Course', // для редактирования типа записи 'new_item' => 'New Course', // текст новой записи 'view_item' => 'View Course', // для просмотра записи этого типа. 'search_items' => 'Search Course', // для поиска по этим типам записи 'not_found' => 'Not found Course', // если в результате поиска ничего не было найдено 'not_found_in_trash' => 'Not found Course in trash', // если не было найдено в корзине 'parent_item_colon' => '', // для родителей (у древовидных типов) 'menu_name' => 'Courses', // название меню ], 'description' => 'Educate Online Courses', 'public' => true, // 'publicly_queryable' => null, // зависит от public // 'exclude_from_search' => null, // зависит от public // 'show_ui' => null, // зависит от public 'show_in_nav_menus' => true, // зависит от public 'show_in_menu' => null, // показывать ли в меню админки // 'show_in_admin_bar' => null, // зависит от show_in_menu 'show_in_rest' => null, // добавить в REST API. C WP 4.7 'rest_base' => null, // $post_type. C WP 4.7 'menu_position' => null, 'menu_icon' => 'dashicons-welcome-learn-more', //'capability_type' => 'post', //'capabilities' => 'post', // массив дополнительных прав для этого типа записи //'map_meta_cap' => null, // Ставим true чтобы включить дефолтный обработчик специальных прав 'hierarchical' => true, 'supports' => [ 'title','editor','author','thumbnail','excerpt','trackbacks','custom-fields','comments','revisions','page-attributes','post-formats' ], // 'title','editor','author','thumbnail','excerpt','trackbacks','custom-fields','comments','revisions','page-attributes','post-formats' 'taxonomies' => true, 'has_archive' => 'courses', 'rewrite' => array( 'slug' => 'universities/%country%/%city%/%university%/courses', 'with_front' => true, 'feeds' => false, 'pages' => true, ), 'query_var' => true, ] );
Важный момент: реврайт для слага 'slug' => 'universities/%country%/%city%/%university%/courses',
Так же, создал в проекте файл для кастомного типа записи single-courses.php.
Что я делал: добавил код для изменения структуры ссылок для типа записи Courses:
function custom_post_type_permalink($permalink, $post, $leavename) { if ($post->post_type == 'universities') { $countries = get_the_terms($post->ID, 'country'); $cities = get_the_terms($post->ID, 'city'); if ($countries && !is_wp_error($countries) && $cities && !is_wp_error($cities)) { $country = $countries[0]->slug; $city = $cities[0]->slug; $permalink = str_replace('%country%', $country, $permalink); $permalink = str_replace('%city%', $city, $permalink); } } elseif ($post->post_type == 'subjects') { $schools = get_the_terms($post->ID, 'schools'); $disciplines = get_the_terms($post->ID, 'disciplines'); if ($schools && !is_wp_error($schools) && $disciplines && !is_wp_error($disciplines)) { $school = $schools[0]->slug; $discipline = $disciplines[0]->slug; $permalink = str_replace('%schools%', $school, $permalink); $permalink = str_replace('%disciplines%', $discipline, $permalink); } } elseif ($post->post_type == 'courses') { $countries = wp_get_post_terms($post->ID, 'country'); $cities = wp_get_post_terms($post->ID, 'city'); $university = wp_get_post_terms($post->ID, 'universities'); if (!empty($countries) && !empty($cities) && !empty($university)) { $country_slug = $countries[0]->slug; $city_slug = $cities[0]->slug; $university_slug = $university[0]->slug; $permalink = str_replace('%country%', $country_slug, $permalink); $permalink = str_replace('%city%', $city_slug, $permalink); $permalink = str_replace('%university%', $university_slug, $permalink); } } return $permalink; } add_filter('post_type_link', 'custom_post_type_permalink', 10, 3); // Фильтр для изменения ссылок на таксономии function custom_taxonomy_permalink($termlink, $term, $taxonomy) { if ($taxonomy == 'country' || $taxonomy == 'city') { $country = null; $city = null; if ($taxonomy == 'country') { $country = $term->slug; } elseif ($taxonomy == 'city') { $country_term = get_term($term->parent, 'country'); if ($country_term && !is_wp_error($country_term)) { $country = $country_term->slug; } $city = $term->slug; } if ($country) { $termlink = str_replace('%country%', $country, $termlink); } if ($city) { $termlink = str_replace('%city%', $city, $termlink); } } elseif ($taxonomy == 'schools' || $taxonomy == 'disciplines' || $taxonomy == 'universities') { $school = null; $discipline = null; if ($taxonomy == 'schools') { $school = $term->slug; } elseif ($taxonomy == 'disciplines') { $school_term = get_term($term->parent, 'schools'); if ($school_term && !is_wp_error($school_term)) { $school = $school_term->slug; } $discipline = $term->slug; } elseif ($taxonomy == 'universities') { // Для таксономии universities, необходимо сделать дополнительную замену $termlink = str_replace('%university%', $term->slug, $termlink); } if ($school) { $termlink = str_replace('%schools%', $school, $termlink); } if ($discipline) { $termlink = str_replace('%disciplines%', $discipline, $termlink); } } return $termlink; } add_filter('term_link', 'custom_taxonomy_permalink', 10, 3); |
function custom_post_type_permalink($permalink, $post, $leavename) { if ($post->post_type == 'universities') { $countries = get_the_terms($post->ID, 'country'); $cities = get_the_terms($post->ID, 'city'); if ($countries && !is_wp_error($countries) && $cities && !is_wp_error($cities)) { $country = $countries[0]->slug; $city = $cities[0]->slug; $permalink = str_replace('%country%', $country, $permalink); $permalink = str_replace('%city%', $city, $permalink); } } elseif ($post->post_type == 'subjects') { $schools = get_the_terms($post->ID, 'schools'); $disciplines = get_the_terms($post->ID, 'disciplines'); if ($schools && !is_wp_error($schools) && $disciplines && !is_wp_error($disciplines)) { $school = $schools[0]->slug; $discipline = $disciplines[0]->slug; $permalink = str_replace('%schools%', $school, $permalink); $permalink = str_replace('%disciplines%', $discipline, $permalink); } } elseif ($post->post_type == 'courses') { $countries = wp_get_post_terms($post->ID, 'country'); $cities = wp_get_post_terms($post->ID, 'city'); $university = wp_get_post_terms($post->ID, 'universities'); if (!empty($countries) && !empty($cities) && !empty($university)) { $country_slug = $countries[0]->slug; $city_slug = $cities[0]->slug; $university_slug = $university[0]->slug; $permalink = str_replace('%country%', $country_slug, $permalink); $permalink = str_replace('%city%', $city_slug, $permalink); $permalink = str_replace('%university%', $university_slug, $permalink); } } return $permalink; } add_filter('post_type_link', 'custom_post_type_permalink', 10, 3); // Фильтр для изменения ссылок на таксономии function custom_taxonomy_permalink($termlink, $term, $taxonomy) { if ($taxonomy == 'country' || $taxonomy == 'city') { $country = null; $city = null; if ($taxonomy == 'country') { $country = $term->slug; } elseif ($taxonomy == 'city') { $country_term = get_term($term->parent, 'country'); if ($country_term && !is_wp_error($country_term)) { $country = $country_term->slug; } $city = $term->slug; } if ($country) { $termlink = str_replace('%country%', $country, $termlink); } if ($city) { $termlink = str_replace('%city%', $city, $termlink); } } elseif ($taxonomy == 'schools' || $taxonomy == 'disciplines' || $taxonomy == 'universities') { $school = null; $discipline = null; if ($taxonomy == 'schools') { $school = $term->slug; } elseif ($taxonomy == 'disciplines') { $school_term = get_term($term->parent, 'schools'); if ($school_term && !is_wp_error($school_term)) { $school = $school_term->slug; } $discipline = $term->slug; } elseif ($taxonomy == 'universities') { // Для таксономии universities, необходимо сделать дополнительную замену $termlink = str_replace('%university%', $term->slug, $termlink); } if ($school) { $termlink = str_replace('%schools%', $school, $termlink); } if ($discipline) { $termlink = str_replace('%disciplines%', $discipline, $termlink); } } return $termlink; } add_filter('term_link', 'custom_taxonomy_permalink', 10, 3);
Что я ожидал: ccылка ввида universities/%country%/%city%/%university%/courses/курс будет открываться согласно иерархии шаблонов, то есть на странице single-courses.php.
Что я получил:ccылка ввида universities/%country%/%city%/%university%/courses/курс ссылка открывается с ошибкой 404.
Контекст: если изменить ссылку для кастомного типа записи на courses/курс, то будет открываться согласно иерархии шаблонов, то есть на странице single-courses.php, но задача стоит, чтобы страница открывалась по адресу universities/%country%/%city%/%university%/courses/курс.
Вопрос: как правильно присвоить шаблон страницы для кастомного типа записи чтобы он открывался по адресу universities/%country%/%city%/%university%/courses/курс?
Дополнительные вопросы
Попробуйте пересохранить ссылки. Вашу простыню кода тестить не буду, но дам совет — попробуйте сначала добиться, чтобы работал хотя бы один параметр ссылки universities/%country%/, а потом по аналогии добавляйте остальные
Ответы на вопрос 0
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
В WordPress нельзя «присвоить шаблон страницы» кастомному типу записи в том же смысле, как обычной странице. Для CPT используются template hierarchy:
single-{post_type}.php,archive-{post_type}.php, taxonomy templates и rewrite rules. Если вам нужен URL вида/страна/город/университет/каталог-курсов/курс, задача состоит не в выборе шаблона, а в маршрутизации и связях между CPT.Я бы разделил задачу на две части:
Шаблон для CPT
coursesделается файлом в теме:single-courses.php
Если нужно выбирать разные шаблоны внутри одного CPT, можно использовать фильтр:
add_filter('single_template', function ($template) { if (is_singular('courses')) { $custom = locate_template('single-courses-custom.php'); if ($custom) { return $custom; } } return $template; });
Но URL с таксономиями в середине — отдельная история. Нужно добавить rewrite rule и затем подставлять правильный permalink через
post_type_link. При этом WordPress должен знать, какой университет связан с курсом, какая страна и город у университета.Важно: если курс является дочерней сущностью университета, возможно, правильнее хранить связь через post meta или relationship field, а не пытаться сделать всё только таксономиями. Таксономии хорошо подходят для классификации, но не всегда подходят для иерархии объектов.
Минимальная логика маршрута будет примерно такая:
add_action('init', function () { add_rewrite_rule( '^([^/]+)/([^/]+)/([^/]+)/catalog-courses/([^/]+)/?$', 'index.php?courses=$matches[4]', 'top' ); });
После этого внутри шаблона курса нужно проверить, что страна, город и университет в URL действительно соответствуют текущему курсу. Иначе один и тот же курс может открываться по любым случайным URL, что плохо для SEO.
Вывод: шаблон — это
single-courses.phpили фильтрsingle_template. А желаемый адрес делается через rewrite + permalink filter + проверку связей. Без этой проверки будет много дублей.