Подключение шаблонов для Типов записей и Таксономий при их регистрации

Идея: при регистрации Типа записи и Таксономии сразу указывать, какой шаблон будет использоваться для Архива, а какой для Записи, а также сколько выводить в этом шаблоне записей.

Реализация:

<?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 ещё удобнее, но появляется минус - магия, о которой в будущем можно забыть и долго чесать затылок, как же это работает.