Skip to content

Wszystko o WordPressie, tworzeniu stron — i nie tylko

⚙️ WordPress: jak ustawić domyślny szablon dla niestandardowego typu wpisów

⚙️ WordPress: jak ustawić domyślny szablon dla niestandardowego typu wpisów

Oddaliśmy klientowi stronę na WordPress z portfolio, a on dzwoni następnego dnia: „Dodaję wpis, a szablon za każdym razem przeskakuje na domyślny z paskiem bocznym. Jak go przypisać na stałe?" Sytuacja boleśnie znajoma: kliknięcie „Dodaj nowy" w niestandardowym typie treści i zamiast zakodowanej strony na całą szerokość wyjeżdża kolumna blogowa z sidebar. Ręczne wybieranie szablonu przy każdej publikacji to bezsensowna rutyna, która irytuje zarówno Pana/Panią, jak i zleceniodawcę. Zwłaszcza gdy praktycznie zawsze potrzebny jest „Full Width" bez panelu bocznego.

WordPress domyślnie dla niestandardowych typów wpisów (CPT) pobiera single.php z motywu. A single.php jest zwykle dostosowany do bloga: nagłówek, treść, sidebar z widżetami. Dla portfolio, case studies, referencji czy produktów taki układ nie pasuje. Dobra wiadomość: WordPress oferuje cztery sposoby na przypisanie szablonu do CPT na stałe, od najprostszego (plik w motywie, zero kodu) po w pełni programowy przez hooki i motywy blokowe. Każda metoda rozwiązuje zadanie niezawodnie, różnica polega jedynie na poziomie kontroli i wygodzie utrzymania.

💡 Szybki przegląd:

  • Proszę utworzyć plik single-{post_type}.php w katalogu głównym motywu, WordPress przechwyci go automatycznie zgodnie z hierarchią szablonów
  • Proszę podpiąć filtr template_include w functions.php, ustawić szablon programowo bez tworzenia fizycznego pliku w motywie
  • Dla motywów blokowych proszę utworzyć single-{post_type}.html w folderze templates/, edytuje się przez Site Editor bez kodu
  • Po każdej zmianie proszę zresetować bezpośrednie odnośniki: „Ustawienia → Bezpośrednie odnośniki → Zapisz", w przeciwnym razie WordPress nie zobaczy nowego szablonu

Sposób 1: Plik szablonu według hierarchii WordPress

Najbardziej niezawodna i najprostsza metoda. WordPress od wersji 3.0 obsługuje niestandardowe szablony dla CPT poprzez standardową hierarchię szablonów. Działa to tak: gdy odwiedzający otwiera wpis typu portfolio, WordPress szuka szablonu w ściśle określonej kolejności, od góry do dołu, i używa pierwszego znalezionego pliku:

single-portfolio.phpsingle.phpsingular.phpindex.php

Należy utworzyć plik o nazwie single-{post_type}.php, gdzie {post_type} to slug Pana/Pani niestandardowego typu. Proszę umieścić go w katalogu głównym aktywnego motywu:

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

Najszybszy start: proszę skopiować zawartość page.php lub template-fullwidth.php z Pana/Pani motywu i dostosować układ do konkretnego CPT. Jeśli plik single-{post_type}.php nie istnieje, WordPress po cichu przełącza się na single.php i klient otrzymuje sidebar.

Zaleta metody: zero kodu w functions.php, plik po prostu leży w motywie i działa. Wada: szablon jest sztywno powiązany z motywem, przy zmianie motywu plik pozostaje w starym folderze i przestaje działać.

Sposób 2: Programowo przez filtr template_include

Metoda plikowa działa, dopóki kontroluje Pan/Pani motyw. Jeśli jednak tworzy Pan/Pani wtyczkę lub motyw potomny, który nie powinien zależeć od obecności pliku w katalogu głównym, potrzebny jest hook template_include.

Filtr uruchamia się przed załadowaniem szablonu i pozwala wskazać plik PHP z dowolnego miejsca:

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}

Co tu się dzieje:

  • is_singular('portfolio') sprawdza, czy jesteśmy na stronie pojedynczego wpisu typu portfolio
  • Jeśli warunek jest prawdziwy, WordPress ładuje szablon z folderu wtyczki, ignorując hierarchię motywu
  • Priorytet 99 gwarantuje, że filtr zadziała jako ostatni i nie zostanie nadpisany przez motyw

To podejście jest wygodne, gdy szablon ma żyć wewnątrz wtyczki i przetrwać zmiany motywu. Plik templates/single-portfolio.php wewnątrz wtyczki może używać get_header() i get_footer() z aktywnego motywu, wizualnie wszystko pozostanie w designie strony.

Sposób 3: Filtr {$type}_template

WordPress udostępnia dynamiczny hook {$type}_template, w którym $type to single, archive lub page. Dla CPT przyjmuje on postać single-portfolio_template i pozwala nadpisać szablon punktowo, bez zbędnych sprawdzeń wewnątrz callbacka:

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}

Różnica w stosunku do Sposobu 2 jest semantyczna: jawnie mówi Pan/Pani „zmieniamy szablon dla pojedynczych wpisów" zamiast „przechwytujemy wszystkie szablony". Kod jest nieco czystszy, ale funkcjonalnie oba hooki rozwiązują zadanie tak samo.

Sposób 4: Szablon w motywie blokowym (Full Site Editing)

Od WordPress 5.9 i przejścia na motywy blokowe podejście się zmienia. W motywach FSE szablony to pliki HTML w folderze templates/, a nie PHP. Dla niestandardowego typu wpisów proszę utworzyć:

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

Wewnątrz znajduje się struktura oparta na blokach. Minimalny przykład:

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"} /-->

Taki szablon można edytować bezpośrednio w Site Editor (Wygląd → Edytor), bez dotykania kodu. Przy zmianie motywu blokowego plik pozostaje w starym folderze, tutaj występuje ta sama podatność co w Sposobie 1.

Który sposób wybrać

Krótka matryca dla Pana/Pani scenariusza:

Sytuacja

Sposób

Jeden motyw, jeden CPT, bez wtyczek

Sposób 1: single-{post_type}.php

Wtyczka z własnym szablonem

Sposób 2: template_include

Motyw potomny, potrzeba nadpisania szablonu rodzica

Sposób 1 lub 3

FSE / motyw blokowy (Twenty Twenty-Four i nowsze)

Sposób 4: templates/single-{post_type}.html

Po wdrożeniu dowolnej z metod koniecznie proszę wejść w „Ustawienia → Bezpośrednie odnośniki" i kliknąć „Zapisz zmiany", resetuje to cache reguł przepisywania (rewrite rules) i WordPress zaczyna widzieć nowy szablon.

⁉️🤔 Często zadawane pytania

Szablon nie jest przechwytywany, co robić?

Po pierwsze: proszę zresetować bezpośrednie odnośniki („Ustawienia → Bezpośrednie odnośniki → Zapisz"). Po drugie: proszę sprawdzić, czy slug CPT w nazwie pliku pokrywa się ze slugiem z register_post_type(). Po trzecie: jeśli używana jest wtyczka cache, proszę wyczyścić cache. Z doświadczenia, problem najczęściej leży właśnie w resecie rewrite rules po rejestracji CPT, a nie w kodzie szablonu.

Czy można ustawić jeden szablon dla kilku CPT jednocześnie?

Tak. W Sposobie 2 proszę użyć tablicy w is_singular(): is_singular( array( 'portfolio', 'testimonials', 'team' ) ). Albo proszę sprawdzić in_array( $post->post_type, array('portfolio', 'team') ) wewnątrz callbacka. Plik szablonu jest wtedy jeden, układ będzie wspólny dla wszystkich wymienionych typów.

Szablon działa, ale układ się psuje, brakuje stylów sidebara/headera.

Odziedziczył Pan/Pani szablon z page.php, a style motywu są powiązane z klasami CSS body. Proszę dodać filtr body_class w functions.php, aby WordPress dodawał klasę post-type-{slug} do <body> i style zostaną przechwycone:

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

Co robić przy zmianie motywu, szablon znika?

Tak, plik single-portfolio.php pozostaje w folderze starego motywu. Opcje: proszę przenieść plik do nowego motywu ręcznie, użyć motywu potomnego (plik przetrwa aktualizacje rodzica) lub wynieść szablon do wtyczki przez Sposób 2, nie zależy on od aktywnego motywu.

A co jeśli potrzebuję, aby WSZYSTKIE CPT domyślnie otwierały się bez sidebara?

Proszę użyć uniwersalnego filtra ze sprawdzeniem is_singular() bez podawania konkretnego post_type, ale z wykluczeniem standardowych post i 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 );

To rozwiązanie stosuje jeden szablon full-width dla wszystkich niestandardowych typów wpisów jednocześnie: portfolio, referencji, zespołu, case studies. Standardowe posty i strony nie są ruszane.

Czy warto zawracać sobie głowę template_include, skoro można po prostu utworzyć plik?

Jeśli ma Pan/Pani jedną stronę, jeden motyw i jeden CPT, proszę utworzyć single-{post_type}.php i zapomnieć. To rozwiązanie na lata: nie psuje się przy aktualizacji WordPress, nie zależy od wersji PHP i jest zrozumiałe dla każdego developera, który otworzy folder motywu. Utrzymanie sprowadza się do jednego pliku, który można poprawić w minutę.

Metody programowe przez hooki są uzasadnione w dwóch przypadkach. Pierwszy: szablon jest częścią dystrybuowanej wtyczki i nie chce Pan/Pani wymagać od użytkownika kopiowania plików do motywu. Drugi: CPT są rejestrowane dynamicznie przez ACF, Toolset lub podobną wtyczkę i tworzenie dziesiątek single-*.php w motywie jest niewygodne. Do wszystkiego innego hierarchia szablonów WordPress to najprostsza i najbardziej niezawodna ścieżka, sprawdzona latami.