Содержание статьи
Используйте кастомную логику представления без регистрации нового пост-типа. Нет нужды плодить CPT ради нескольких уникальных страниц. Достаточно определить класс с нужными параметрами – и всё. У вас будет доступ к мета-полям, шаблонам, хукам, без перегрузки ядра.
Пример простой конфигурации:
class About_Page_Type extends \\YourNamespace\\PageType {
public function register() {
$this->name = \'О компании\';
$this->template = \'templates/about.php\';
}
}
Не используйте глобальные мета-боксы – вместо этого определяйте поля внутри структуры типа. Они будут загружаться только тогда, когда это действительно нужно.
public function fields() {
return [
Text::make(\'Заголовок\'),
Textarea::make(\'Описание\'),
];
}
Важно помнить: поля можно логически группировать, добавлять условия показа, создавать вложенные секции без сторонних зависимостей.
Отдельное внимание: порядок загрузки файлов шаблонов. Подключение нестандартных шаблонов работает через фильтр template_include
. Это дает контроль над маршрутизацией без хака ядра.
Никаких switch-case в functions.php
. Всё логично организовано, классы разнесены по файлам, поддержка autoload из Composer работает без нареканий.
Внимание! Не пытайтесь использовать классы типов внутри хуков до инициализации. Структура должна быть зарегистрирована после
init
, иначе система просто проигнорирует её.
Как итог: никаких лишних CPT, всё на уровне обычных страниц, но с возможностями конструкторов данных. Это решение – не про маркетинг, а про архитектуру. Сухую, логичную, функциональную.
Как использовать Page Type API для создания уникальных шаблонов страниц
Определите новый тип шаблона через PHP-файл внутри каталога lib/page-types
. Название файла должно соответствовать имени будущего шаблона, например: custom-landing.php
.
Внутри этого файла регистрируйте структуру, используя массив с ключами name
, template
, post_type
, options
. Пример:
class CustomLandingType extends \\Papi\\Page\\Type {
public function __construct() {
$this->box( \'Основные настройки\', [
papi_property( [
\'slug\' => \'hero_title\',
\'title\' => \'Заголовок\',
\'type\' => \'string\',
] ),
papi_property( [
\'slug\' => \'hero_image\',
\'title\' => \'Изображение\',
\'type\' => \'image\',
] )
] );
}
public function get_template() {
return \'templates/custom-landing.php\';
}
public function get_post_type() {
return \'page\';
}
}
Важно соблюдать строгую связь между файлом шаблона, указанным в get_template()
, и реально существующим PHP-шаблоном в каталоге templates
. Отсутствие шаблона вызовет ошибку отображения.
В интерфейсе админки после регистрации появляется выбор нужного шаблона при создании новой записи. Название определяется через метод get_label()
.
Настройка свойств осуществляется через papi_property
. Типы данных ограничены: строка, изображение, чекбокс, редактор, список. Используйте только поддерживаемые типы. Никакой самодеятельности.
Внимание! Если вы не определите
get_post_type()
, шаблон не будет доступен ни в одном типе записей.
Используйте метод show_on_page()
, если требуется ограничить шаблон для конкретных ID страниц. Это полезно при создании лендингов под кампании или уникальных посадочных страниц:
public function show_on_page( $post_id ) {
return $post_id === 42;
}
Важно помнить: каждый шаблон должен быть изолирован. Не дублируйте поля между типами. Наследование здесь не работает.
Все данные, введенные в этих полях, доступны через papi_get_field( $post_id, \'field_slug\' )
. Не используйте get_post_meta()
– значения сериализованы особым образом.
Хотите шаблон с кастомным набором блоков, редактором и условиями видимости? Тогда этот подход – молоток. Но помните: один удар – один результат. Упростите структуру до предела. Без магии.
Настройка кастомных полей через Page Type API в Papi
Создавайте поля напрямую в классе типа страницы. Не через интерфейс. Не через хуки. Только через код. Это единственный способ добиться предсказуемого поведения и полной управляемости.
Добавление полей происходит в методе register_fields
. Пример:
public function register_fields() {
$this->box( \'Основные настройки\', [
papi_property( [
\'slug\' => \'subtitle\',
\'title\' => \'Подзаголовок\',
\'type\' => \'string\'
] )
] );
}
Поля группируются в боксы. Это обязательная структура. Без бокса – не работает. Поле может быть любого типа: string, bool, file, image, repeater, flex. Некоторые из них требуют дополнительных настроек, особенно repeater и flex – там вложенность, и нужно описывать каждое подполе отдельно.
Пример вложенного repeater:
papi_property( [
\'slug\' => \'faq\',
\'title\' => \'Часто задаваемые вопросы\',
\'type\' => \'repeater\',
\'settings\' => [
\'items\' => [
papi_property( [
\'slug\' => \'question\',
\'title\' => \'Вопрос\',
\'type\' => \'string\'
] ),
papi_property( [
\'slug\' => \'answer\',
\'title\' => \'Ответ\',
\'type\' => \'text\'
] )
]
]
] )
Важно! Не используйте одинаковые
slug
в разных типах страниц. Это приводит к коллизиям данных и потере значений в интерфейсе.
Сортировка, отображение, скрытие – всё контролируется опциями внутри массива papi_property
. Можно задать default, description, placeholder, required. Но не переусердствуйте: чем больше ограничений, тем выше шанс на конфликт с кастомной логикой темы.
Есть подводные камни. Поля типа file
и image
могут не работать, если отключены соответствующие MIME-типы в настройках загрузки. Проверьте functions.php
, прежде чем искать ошибку в коде поля.
Помните: поле не отобразится, если не указано в возвращаемом массиве в методе
register_fields
. Даже если вы его описали, оно не появится без этого шага.
Добавлять кастомные валидаторы – боль. Делается через papi/validate/property
, но требует глубокого контроля над данными. Ошибки не отображаются явно. Отладка только через консоль и error_log
.
Настройка кастомных полей – не декорация. Это жесткая структура хранения данных. Точность, минимализм и строгая типизация – три кита. Ошибка в одном параметре – сломана вся страница. Без предупреждений.
Хотите стабильности? Используйте только проверенные типы и минимальное количество уровней вложенности. Чем проще – тем живучее.
Интеграция Page Type API с существующими темами WordPress
Подключение механизма к активной теме – не рутинная задача. Первое: отключи автоматическое подключение типов через фильтр papi/settings/show_editor
, если в теме используются кастомные шаблоны. Конфликт будет незаметен до первого сохранения страницы.
Шаблоны должны включать явный вызов the_content()
. Без этого контент просто не отрендерится. Простейшая ловушка, в которую попадают даже опытные разработчики. Тема живет, а контент – мертв.
Названия классов типов должны соответствовать файловой структуре. Например, файл page-types/SingleProductPage.php
требует класс SingleProductPage
. Пропустишь – редактор не увидит тип, даже если он существует.
Важно: не размещай определения классов в
functions.php
. Используй отдельную папку и автозагрузку через composer илиspl_autoload_register
.
Если тема использует кастомные поля ACF, инициализация происходит раньше загрузки типа. Результат – сброшенные значения, пустые блоки, полная анархия. Используй хук acf/init
внутри конструктора типа, а не в глобальном контексте.
Переопределение шаблона происходит через фильтр template_include
. Укажи свой путь, например:
add_filter(\'template_include\', function($template) {
if (is_singular(\'product\')) {
return get_template_directory() . \'/templates/single-product.php\';
}
return $template;
});
Избегай использования get_page_template()
. Этот вызов игнорирует механизм выбора типа и подсовывает дефолт. И да, фильтр papi/settings/show_only_page_type_ui
может скрыть редактор полностью – если ты случайно вернешь true
глобально.
Интеграция невозможна без учета хука init
. Подключай типы строго после этого события. Лучше – внутри after_setup_theme
. Гарантия, что всё, что нужно, уже доступно. Убери типы раньше – столкнешься с пустым UI.
Помните: если используешь кастомную иерархию шаблонов, настрой
papi/settings/page_type_directory
вручную. Автопоиск не охватывает вложенные папки.
Таблица отображения соответствий для интеграции:
Тип страницы | Путь до файла | Класс | Шаблон |
---|---|---|---|
Продукт | /page-types/SingleProductPage.php | SingleProductPage | single-product.php |
Событие | /page-types/EventType.php | EventType | event.php |
Главная | /page-types/HomeType.php | HomeType | front-page.php |
Проверь структуру темы. Использует ли она get_template_part()
? Тогда внедрение – через частичные шаблоны с передачей данных из типа. Но не через глобальные переменные – используем фильтры, массивы и явные include.
Хочешь, чтобы редактор появился только на нужных страницах? Используй papi/settings/show_page_type
. Верни false
там, где вмешательство недопустимо: архивы, поиск, 404.
И помни: интеграция – не добавление кода, это хирургия. Режь точно, подключай аккуратно. Иначе всё рухнет.
Управление отображением контента на основе типов страниц в Papi
Сразу: логика показа контента должна основываться на проверке текущего шаблона или конкретного свойства. Игнорировать это – гарантировать хаос в админке и на фронте.
Если нужен разный контент на разных типах – проверяйте уникальные идентификаторы шаблонов через get_post_meta()
или используйте фильтрацию по условию papi_get_page_type()
. Пример:
if ( papi_get_page_type( get_the_ID() ) === \'custom-article\' ) {
echo \'Отображается только на типе custom-article\';
}
Динамика начинается, когда условия становятся сложнее. Используйте is_singular()
в паре с papi_get_page_type()
для построения гибкой архитектуры шаблонов. Код работает как швейцарские часы только при условии, что вы не доверяете интерфейсу и вручную контролируете значения ключей мета-полей.
Рассмотрим фильтрацию меню:
if ( papi_get_page_type() === \'landing\' ) {
wp_nav_menu( [ \'theme_location\' => \'landing_menu\' ] );
} else {
wp_nav_menu( [ \'theme_location\' => \'default_menu\' ] );
}
Меню – лишь один пример. Блоки, шорткоды, вызовы API, фильтрация REST – всё это должно учитывать тип текущего объекта. Ошибка – делать общую обвязку, не проверяя контекст.
Важно помнить: проверка типа должна идти первой в цепочке условий. Никаких get_post_type() – используйте нативные методы контекстного доступа.
Игра начинается, когда нужно менять поля админки. Используйте papi_property
с параметром show_if
:
public function show() {
return [
papi_property( [
\'title\' => \'Скрытое поле\',
\'slug\' => \'hidden_field\',
\'type\' => \'string\',
\'show_if\' => [
\'field\' => \'toggle_visibility\',
\'operator\' => \'===\',
\'value\' => true
]
] )
];
}
Сложные структуры? Вынесите логику в отдельные классы. Старайтесь минимизировать условия в шаблонах – от этого зависит читаемость и дебаг. Чем больше условий на фронте – тем хуже ваша архитектура.
Внимание! Никогда не полагайтесь на визуальные признаки в админке. Настройка должна проверяться только через данные, а не через внешний вид.
- Используйте уникальные слуги при регистрации
- Не дублируйте поля между типами
- Храните зависимости в конфигурации, не в логике шаблонов
- Тестируйте условия в разных языках и мультисайтах
Не стройте логику отображения на post_type. Это ловушка. Единственный надёжный источник истины – ID шаблона, возвращённый ядром. Не используйте wp_query для фильтрации – только конкретная привязка к типу и значение поля. Это не опция. Это необходимость.