Подключение шаблонов для Типов записей и Таксономий при их регистрации
При работе с WordPress часто приходится регистрировать собственные типы записей (Custom Post Types) и таксономии, а затем руками прописывать для них шаблоны и параметры вывода.
В этой заметке я покажу, как сразу при регистрации CPT или таксономии задавать путь к шаблону single и archive, количество записей на странице и даже плейсхолдер заголовка.
Основная идея: при регистрации Типа записи и Таксономии сразу указывать, какой шаблон будет использоваться для Архива, а какой для Записи, а также сколько выводить в этом шаблоне записей.
Такой подход ускоряет разработку, упрощает поддержку проекта и помогает избежать дублирования кода.
Метод основан на использовании хуков registered_post_type и registered_taxonomy: мы «ловим» объект CPT/таксономии в момент регистрации, обрабатываем наши кастомные поля через соответствующие фильтры:
template_item- template_includetemplate_archive- pre_get_postsposts_per_page- enter_title_here- и тд.
В итоге нужный шаблон подключается автоматически, а количество выводимых постов задаётся один раз в массиве настроек. Такой приём делает код чище.
Реализация:
<?php
/**
* При регистрации CTP "ловит" и применяет параметры:
* "Шаблон"
* "Количество выводимых постов"
* "Плейсхолдер"
*/
add_action( 'registered_post_type', function ( $post_type, $ctp_object ) {
add_filter( 'template_include', function ( $templates ) use ( $ctp_object ) {
// Задаём шаблон одиночной записи.
if ( ! empty( $ctp_object->template_item ) && is_singular( $ctp_object->name ) ) {
$templates = locate_template( $ctp_object->template_item );
}
// Задаём шаблон архиву записей.
if ( ! empty( $ctp_object->template_archive ) && is_post_type_archive( $ctp_object->name ) ) {
$templates = locate_template( $ctp_object->template_archive );
}
return $templates;
} );
// Устанавливаем количество выводимых записей в архивах.
// Поддерживается свойсва 'posts_per_page_front' (приоритет) и 'posts_per_page' (fallback).
add_action( 'pre_get_posts', function ( $query ) use ( $ctp_object ) {
$ppp_front = $ctp_object->posts_per_page_front ?? null;
$ppp_front = $ppp_front ?: ( $ctp_object->posts_per_page ?? null );
if (
! empty( $ppp_front )
&& ! is_admin()
&& $query->is_main_query()
&& $query->is_post_type_archive( $ctp_object->name )
) {
$query->set( 'posts_per_page', $ppp_front );
}
} );
// Скрываем выбор количества постов в админке для типа записи, если он указывается программно.
add_action( 'admin_head-edit.php', static function () use ( $ctp_object ) {
global $typenow;
if ( $typenow === $ctp_object->name && isset( $ctp_object->posts_per_page_admin ) ) {
?>
<style>
#screen-meta .screen-options {
display: none;
}
</style>
<?php
}
} );
// Устанавливаем количество постов в таблице в админке.
add_filter( "edit_{$ctp_object->name}_per_page", static function ( $posts_per_page ) use ( $ctp_object ) {
$ppp_admin = $ctp_object->posts_per_page_admin ?? $posts_per_page;
return $ppp_admin === - 1 ? 1000 : $ppp_admin;
} );
// Устанавливаем плейсхолдер в поле Заголовок на странице редактирования записи
add_filter( 'enter_title_here', function ( $text, $post ) use ( $ctp_object ) {
if ( isset( $ctp_object->labels->title_placeholder ) && $post->post_type === $ctp_object->name ) {
$text = $ctp_object->labels->title_placeholder;
}
return $text;
}, 11, 2 );
}, 10, 2 );
/**
* При регистрации Таксономии "ловит" и применяет параметры "Шаблон" и "Количество выводимых постов".
*/
add_action( 'registered_taxonomy', function ( $taxonomy, $object_type, $taxonomy_object ) {
add_filter( 'template_include', function ( $templates ) use ( $taxonomy, $taxonomy_object ) {
// Задаём шаблон термину.
if ( ! empty( $taxonomy_object['template_item'] ) && is_tax( $taxonomy ) ) {
$templates = locate_template( $taxonomy_object['template_item'] );
}
return $templates;
} );
// Устанавливаем количество выводимых записей в архивах.
add_action( 'pre_get_posts', function ( $query ) use ( $taxonomy, $taxonomy_object ) {
if (
! empty( $taxonomy_object['posts_per_page'] )
&& ! is_admin()
&& $query->is_main_query()
&& $query->is_tax( $taxonomy )
) {
$query->set( 'posts_per_page', $taxonomy_object['posts_per_page'] );
}
} );
}, 10, 3 );
Теперь можем указать шаблон и количество выводимых в нём записей сразу при регистрации сущностей:
// Для Типа записи register_post_type( 'events', [ 'labels' => [ 'name' => 'События', 'singular_name' => 'События', 'name_admin_bar' => 'События', 'menu_name' => 'События', 'add_new' => 'Добавить новое событие', 'add_new_item' => 'Добавить новое событие', 'edit_item' => 'Редактировать событие', 'new_item' => 'Новое событие', 'view_item' => 'Посмотреть событие', 'search_items' => 'Найти событие', 'not_found' => 'Событие не найдено', 'not_found_in_trash' => 'В корзине событие не найдено', 'featured_image' => 'Фото События', 'set_featured_image' => 'Установите Фотографию события', 'title_placeholder' => 'Введите название события', 'first_menu_name' => 'Список событий', ], 'public' => true, 'rewrite' => [ 'slug' => 'events' ], 'capability_type' => 'post', 'has_archive' => 'events', 'hierarchical' => false, 'menu_position' => 7, 'menu_icon' => 'dashicons-megaphone', 'supports' => [ 'title', 'thumbnail', 'editor' ], 'template_item' => '/templates/event/single/event-single.php', 'template_archive' => '/templates/event/archive/event-archive.php', 'posts_per_page' => 4, 'show_in_rest' => true, 'show_ui' => true, 'show_in_menu' => true, ] ); // Для Таксономии register_taxonomy( 'section', [ 'news' ], [ 'hierarchical' => false, 'labels' => [ 'name' => 'Секция', 'singular_name' => 'Секция', 'add_new' => 'Добавить новую', 'add_new_item' => 'Добавить новую секцию', 'edit_item' => 'Редактировать секцию', 'new_item' => 'Новая секция', 'view_item' => 'Посмотреть секцию', 'search_items' => 'Найти секцию', 'not_found' => 'Секция не найдены', 'not_found_in_trash' => 'В корзине секций не найдено', 'menu_name' => 'Секции', ], 'template_item' => '/templates/event/archive/event-archive.php', 'posts_per_page' => 4, 'show_admin_column' => true, 'show_in_rest' => false, ] );
Благодаря такому подходу, вы можете при регистрации указать любой свой параметр, а потом в фильтрах registered_post_type/registered_taxonomy его применить, что делает работу с WordPress ещё удобнее, но появляется минус - магия, о которой в будущем можно забыть и долго чесать затылок, как же это работает.