Skip to content

Все для WordPress, веб-розробки — і не тільки

⚙️ WordPress: як встановити шаблон за замовчуванням для кастомного типу записів

⚙️ WordPress: як встановити шаблон за замовчуванням для кастомного типу записів

Здали клієнту сайт на WordPress з портфоліо, а він телефонує через день: «Я тут запис додаю, а шаблон щоразу злітає на стандартний із сайдбаром. Як його закріпити?» Ситуація до болю знайома: клік по «Додати новий» у кастомному типі, і замість зверстаної сторінки на всю ширину виїжджає блогова колонка з сайдбаром. Обирати шаблон вручну під час кожної публікації, безглузда рутина, яка дратує і вас, і замовника. Особливо коли практично завжди потрібен «Full Width» без бічної панелі.

WordPress за замовчуванням для кастомних типів записів (CPT) бере single.php із теми. А single.php зазвичай заточений під блог: заголовок, контент, сайдбар із віджетами. Для портфоліо, кейсів, відгуків чи товарів таке верстання не підходить. Хороша новина: WordPress пропонує чотири способи закріпити шаблон за CPT, від найпростішого (файл у темі, жодного коду) до повністю програмного через хуки та блок-теми. Кожен метод розв'язує задачу надійно, різниця лише в рівні контролю та зручності підтримки.

💡 Швидкий огляд:

  • Створіть файл single-{post_type}.php у корені теми, WordPress підхопить його автоматично за ієрархією шаблонів
  • Підключіть фільтр template_include у functions.php, задайте шаблон програмно без створення фізичного файлу в темі
  • Для блок-тем створіть single-{post_type}.html у папці templates/, редагується через Site Editor без коду
  • Після будь-якої зміни скиньте пермалінки: «Налаштування → Постійні посилання → Зберегти», інакше WordPress не побачить новий шаблон

Спосіб 1: Файл шаблону за ієрархією WordPress

Найнадійніший і найпростіший метод. WordPress з версії 3.0 підтримує кастомні шаблони для CPT через стандартну ієрархію шаблонів. Працює це так: коли відвідувач відкриває запис типу portfolio, WordPress шукає шаблон у строго визначеному порядку, зверху вниз, і використовує перший знайдений файл:

single-portfolio.phpsingle.phpsingular.phpindex.php

Вам потрібно створити файл з іменем single-{post_type}.php, де {post_type}, слаг вашого кастомного типу. Покладіть його в корінь активної теми:

1/* Файл: /wp-content/themes/your-theme/single-portfolio.php */
2
3<?php get_header(); ?>
4
5<div class="full-width-content">
6 <?php while ( have_posts() ) : the_post(); ?>
7 <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
8 <h1><?php the_title(); ?></h1>
9 <div class="entry-content">
10 <?php the_content(); ?>
11 </div>
12 </article>
13 <?php endwhile; ?>
14</div>
15
16<?php get_footer(); ?>
17

Найшвидший старт: скопіюйте вміст page.php або template-fullwidth.php із вашої теми та адаптуйте верстку під конкретний CPT. Якщо файлу single-{post_type}.php немає, WordPress мовчки відкочується на single.php, і клієнт отримує сайдбар.

Плюс методу: жодного коду в functions.php, файл просто лежить у темі та працює. Мінус: шаблон жорстко прив'язаний до теми, при зміні теми файл залишається в старій папці та перестає працювати.

Спосіб 2: Програмно через фільтр template_include

Файловий метод працює, поки ви контролюєте тему. Але якщо ви розробляєте плагін або дочірню тему, яка не повинна залежати від наявності файлу в корені, потрібен хук template_include.

Фільтр спрацьовує перед завантаженням шаблону та дозволяє вказати PHP-файл із будь-якого місця:

1/* Файл: functions.php (темы) или основной файл плагина */
2
3add_filter( 'template_include', 'sd_cpt_default_template', 99 );
4
5function sd_cpt_default_template( $template ) {
6 if ( is_singular( 'portfolio' ) ) {
7 $custom_template = plugin_dir_path( __FILE__ ) . 'templates/single-portfolio.php';
8 if ( file_exists( $custom_template ) ) {
9 return $custom_template;
10 }
11 }
12 return $template;
13}

Що тут відбувається:

  • is_singular('portfolio') перевіряє, що ми на сторінці одиничного запису типу portfolio
  • Якщо умова істинна, WordPress завантажує шаблон із папки плагіна, ігноруючи ієрархію теми
  • Пріоритет 99 гарантує, що фільтр спрацює останнім і не буде перебитий темою

Цей підхід зручний, коли шаблон має жити всередині плагіна та переживати зміни теми. Файл templates/single-portfolio.php всередині плагіна може використовувати get_header() і get_footer() з активної теми, візуально все залишиться в дизайні сайту.

Спосіб 3: Фільтр {$type}_template

WordPress надає динамічний хук {$type}_template, у якому $type — це single, archive або page. Для CPT він набуває вигляду single-portfolio_template і дозволяє перевизначити шаблон точково, без зайвих перевірок усередині колбеку:

1add_filter( 'single_template', 'sd_cpt_template_by_type' );
2
3function sd_cpt_template_by_type( $single_template ) {
4 global $post;
5
6 if ( 'portfolio' === $post->post_type ) {
7 $custom_template = get_stylesheet_directory() . '/single-portfolio.php';
8 if ( file_exists( $custom_template ) ) {
9 return $custom_template;
10 }
11 }
12 return $single_template;
13}

Різниця зі Способом 2 семантична: ви явно кажете «змінюємо шаблон для сингл-записів» замість «перехоплюємо взагалі всі шаблони». Код трохи чистіший, але функціонально обидва хуки розв'язують задачу однаково.

Спосіб 4: Шаблон у блок-темі (Full Site Editing)

З WordPress 5.9 і переходом на блок-теми підхід змінюється. У FSE-темах шаблони — це HTML-файли в папці templates/, а не PHP. Для кастомного типу записів створіть:

1/wp-content/themes/your-fse-theme/templates/single-portfolio.html

Всередині, структура на блоках. Мінімальний приклад:

1<!-- wp:template-part {"slug":"header","theme":"your-fse-theme"} /-->
2
3<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
4<main class="wp-block-group">
5 <!-- wp:post-title {"level":1} /-->
6 <!-- wp:post-featured-image /-->
7 <!-- wp:post-content {"layout":{"type":"constrained"}} /-->
8</main>
9<!-- /wp:group -->
10
11<!-- wp:template-part {"slug":"footer","theme":"your-fse-theme"} /-->

Редагувати такий шаблон можна прямо в Site Editor (Зовнішній вигляд → Редактор), без торкання коду. При зміні блок-теми файл залишається в старій папці, тут та сама вразливість, що й у Способу 1.

Який спосіб обрати

Коротка матриця під ваш сценарій:

Ситуація

Спосіб

Одна тема, один CPT, без плагінів

Спосіб 1: single-{post_type}.php

Плагін зі своїм шаблоном

Спосіб 2: template_include

Дочірня тема, потрібно перевизначити батьківський шаблон

Спосіб 1 або 3

FSE / блок-тема (Twenty Twenty-Four і новіші)

Спосіб 4: templates/single-{post_type}.html

Після впровадження будь-якого з методів обов'язково зайдіть у «Налаштування → Постійні посилання» та натисніть «Зберегти зміни» — це скидає кеш правил перезапису (rewrite rules), і WordPress починає бачити новий шаблон.

⁉️🤔 Часті запитання

Шаблон не підхоплюється, що робити?

Перше: скиньте пермалінки («Налаштування → Постійні посилання → Зберегти»). Друге: перевірте, що слаг CPT в імені файлу збігається зі слагом із register_post_type(). Третє: якщо використовується плагін кешування, очистіть кеш. З досвіду, проблема найчастіше саме в скиданні rewrite rules після реєстрації CPT, а не в коді шаблону.

Чи можна задати один шаблон одразу для кількох CPT?

Так. У Способі 2 використовуйте масив у is_singular(): is_singular( array( 'portfolio', 'testimonials', 'team' ) ). Або перевіряйте in_array( $post->post_type, array('portfolio', 'team') ) усередині колбеку. Файл шаблону при цьому один, верстка буде спільною для всіх перелічених типів.

Шаблон працює, але верстка ламається, немає стилів сайдбару/хедера.

Ви успадкували шаблон від page.php, а стилі теми зав'язані на CSS-класи body. Додайте фільтр body_class у functions.php, щоб WordPress проставляв клас post-type-{slug} на <body>, і стилі підхопляться:

1add_filter( 'body_class', function( $classes ) {
2 if ( is_singular( 'portfolio' ) ) {
3 $classes[] = 'single-portfolio';
4 }
5 return $classes;
6} );

Що робити при зміні теми, шаблон зникає?

Так, файл single-portfolio.php залишається в папці старої теми. Варіанти: перенесіть файл у нову тему вручну, використовуйте дочірню тему (файл переживає оновлення батьківської) або винесіть шаблон у плагін через Спосіб 2, він не залежить від активної теми.

А якщо мені потрібно, щоб УСІ CPT за замовчуванням відкривалися без сайдбару?

Використовуйте універсальний фільтр із перевіркою is_singular() без зазначення конкретного post_type, але виключіть стандартні post і page:

1add_filter( 'template_include', function( $template ) {
2 if ( is_singular() && ! is_singular( array( 'post', 'page' ) ) ) {
3 $fullwidth = get_stylesheet_directory() . '/template-fullwidth.php';
4 if ( file_exists( $fullwidth ) ) {
5 return $fullwidth;
6 }
7 }
8 return $template;
9}, 99 );

Це рішення застосовує один full-width шаблон для всіх кастомних типів записів одразу: портфоліо, відгуків, команди, кейсів. Стандартні пости та сторінки не зачіпаються.

Чи варто морочитися з template_include, якщо можна просто створити файл?

Якщо у вас один сайт, одна тема й один CPT, створіть single-{post_type}.php і забудьте. Це рішення на роки: воно не ламається при оновленні WordPress, не залежить від версії PHP і зрозуміле будь-якому розробнику, який відкриє папку теми. Супровід зводиться до одного файлу, який можна поправити за хвилину.

Програмні методи через хуки виправдані у двох випадках. Перший: шаблон є частиною плагіна, що розповсюджується, і ви не хочете вимагати від користувача копіювати файли в тему. Другий: CPT реєструються динамічно через ACF, Toolset чи подібний плагін, і плодити десяток single-*.php у темі незручно. Для всього іншого ієрархія шаблонів WordPress, найпростіший і найнадійніший шлях, перевірений роками.