
🔧 Jak utworzyć szablon dla niestandardowego typu wpisów w WordPress
Dodał/a Pan/Pani na stronę niestandardowy typ wpisów, powiedzmy „Promocje", „Portfolio" lub „Opinie". Wszystko działa: wpisy się tworzą, pola meta są wypełniane. Ale kiedy otwiera Pan/Pani stronę takiego wpisu na froncie, wygląda ona jak zwykły wpis na blogu. Ten sam układ, te same sidebary, żadnej różnicy. A przecież zakładał/a Pan/Pani niestandardowy typ właśnie po to, żeby treść prezentowała się inaczej.
Problem polega na tym, że WordPress domyślnie renderuje każdy niestandardowy wpis przez single.php, uniwersalny szablon dla wszystkich pojedynczych wpisów. Aby uzyskać indywidualny układ dla konkretnego typu, potrzebny jest własny plik szablonu. A robi się go zaskakująco prosto.
Poniżej analiza krok po kroku: od hierarchii szablonów do dwóch sposobów tworzenia (przez plik motywu oraz przez filtr template_include), z praktycznymi przykładami kodu.
💡 Szybki przegląd:
- Wyjaśniamy, jak WordPress szuka szablonu dla niestandardowego typu, priorytet
single-{post_type}.php - Kopiujemy
single.phpmotywu, zmieniamy nazwę pod swój CPT i dostosowujemy - Omawiamy alternatywną metodę, przez filtr
template_include(wygodna, jeśli nie chce Pan/Pani ruszać motywu) - Tworzymy sam niestandardowy typ przez wtyczkę Custom Post Type UI, szybko i bez kodu
1. Jak WordPress wybiera szablon dla niestandardowego typu
Hierarchia szablonów WordPress to łańcuch plików, według którego rdzeń szuka odpowiedniego szablonu do wyświetlenia strony. Dla standardowych wpisów łańcuch jest długi: single-post.php → single.php → singular.php → index.php. Dla typów niestandardowych jest krótszy, ale logika jest taka sama.
Kiedy odwiedzający otwiera stronę niestandardowego wpisu typu aktsii, WordPress sprawdza pliki w następującej kolejności:
single-aktsii.php, szablon konkretnie dla tego niestandardowego typusingle.php, ogólny szablon pojedynczego wpisusingular.php, szablon dla dowolnej pojedynczej treści (wpis, strona, CPT)index.php, ostateczny fallback
Pierwszy znaleziony plik z łańcucha jest używany do renderowania. Jeśli single-aktsii.php istnieje, WordPress weźmie go i zatrzyma się. Jeśli nie znajdzie, idzie dalej do single.php. Właśnie dlatego Pana/Pani niestandardowy typ wygląda jak zwykły wpis: pliku single-aktsii.php nie ma i rdzeń schodzi do ogólnego single.php.
Stąd rozwiązanie: tworzymy single-{post_type}.php, a WordPress automatycznie go przechwytuje.
2. Tworzymy plik szablonu: kopiujemy single.php i zmieniamy nazwę
Najprostszy i najbardziej niezawodny sposób. Działa z każdym klasycznym motywem, nie wymaga wtyczek ani filtrów.
Krok 1: proszę znaleźć single.php motywu. Leży on w katalogu głównym folderu motywu: /wp-content/themes/ваша-тема/single.php. Jeśli motyw używa FSE (Full Site Editing) i jest zbudowany na blokach, tego pliku może nie być i sposób z filtrem (template_include) będzie wygodniejszy (rozdział 4).
Krok 2: proszę skopiować i zmienić nazwę. Kopiuje Pan/Pani single.php i nazywa według reguły single-{slug}.php: zamiast {slug} proszę wstawić alias niestandardowego typu (ten podany przy rejestracji, po łacinie). Na przykład dla typu z aliasem aktsii:
1 single-aktsii.php
Dla typu z aliasem portfolio plik będzie się nazywał single-portfolio.php. Dla testimonials powstanie single-testimonials.php. Ważne: slug musi być zgodny z tym, co podano w parametrze 'rewrite' => array('slug' => '...') przy rejestracji.
Krok 3: proszę umieścić plik z powrotem w folderze motywu. WordPress sam przechwyci go dla wszystkich wpisów tego typu. Żadnych dodatkowych ustawień, hierarchia szablonów robi to automatycznie.
Krok 4: proszę sprawdzić. Proszę otworzyć dowolny wpis niestandardowego typu na froncie. Jeśli widzi Pan/Pani tę samą stronę co wcześniej, proszę sprawdzić nazwę pliku (wielkość liter, myślniki zamiast podkreślników) i wyczyścić cache. Jeśli plik został utworzony w motywie potomnym, a motyw nadrzędny również zawiera single-{post_type}.php, motyw potomny ma priorytet.
3. Dostosowujemy zawartość szablonu
Skopiowany single.php na razie niczym nie różni się od oryginału, po prostu renderuje ten sam uniwersalny układ. Teraz wypełniamy go treścią specyficzną dla niestandardowego typu.
3.1. Podstawowa struktura: wyświetlamy pola niestandardowe
Załóżmy, że niestandardowy typ aktsii ma pola: aktsiya_data_start, aktsiya_data_end i aktsiya_skidka (utworzone przez ACF, Meta Box lub ręcznie). Oto minimalny szablon, który je wyświetla:
1 <?php 2 /** 3 * Шаблон для кастомного типа «Акции» (single-aktsii.php) 4 */ 5 6 get_header(); 7 ?> 8 9 <main id="main" class="site-main" role="main"> 10 11 <?php while ( have_posts() ) : the_post(); ?> 12 13 <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> 14 15 <header class="entry-header"> 16 <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?> 17 </header> 18 19 <?php if ( has_post_thumbnail() ) : ?> 20 <div class="post-thumbnail"> 21 <?php the_post_thumbnail( 'large' ); ?> 22 </div> 23 <?php endif; ?> 24 25 <div class="entry-content"> 26 <?php the_content(); ?> 27 28 <div class="custom-fields"> 29 <?php 30 $data_start = get_post_meta( get_the_ID(), 'aktsiya_data_start', true ); 31 $data_end = get_post_meta( get_the_ID(), 'aktsiya_data_end', true ); 32 $skidka = get_post_meta( get_the_ID(), 'aktsiya_skidka', true ); 33 34 if ( $data_start ) { 35 echo '<p><strong>Дата начала:</strong> ' . esc_html( $data_start ) . '</p>'; 36 } 37 if ( $data_end ) { 38 echo '<p><strong>Дата окончания:</strong> ' . esc_html( $data_end ) . '</p>'; 39 } 40 if ( $skidka ) { 41 echo '<p><strong>Скидка:</strong> ' . esc_html( $skidka ) . '%</p>'; 42 } 43 ?> 44 </div> 45 </div> 46 47 </article> 48 49 <?php 50 if ( comments_open() || get_comments_number() ) : 51 comments_template(); 52 endif; 53 ?> 54 55 <?php endwhile; ?> 56 57 </main> 58 59 <?php 60 get_sidebar(); 61 get_footer();
To w pełni funkcjonalny szablon, który można umieścić w motywie w takiej postaci. Wyświetla tytuł, miniaturę, treść i trzy dowolne pola w osobnym bloku.
3.2. Co jeszcze można zrobić z szablonem
Dalej to nieograniczone pole do dostosowania pod konkretne zadanie:
- Usunąć sidebar, wystarczy usunąć wywołanie
get_sidebar(). - Zmienić opakowanie HTML, zastąpić
<article>przez<div>z potrzebną klasą, dodać własną siatkę. - Wywołać konkretny template-part, na przykład
get_template_part( 'template-parts/content', 'aktsii' )i przechowywać logikę w osobnym pliku. - Podłączyć niestandardowe style, przez
wp_enqueue_style()wewnątrzfunctions.phpze sprawdzeniemis_singular( 'aktsii' ).
Ważna kwestia: jeśli motyw jest aktualizowany, plik w motywie nadrzędnym może zostać nadpisany. Dlatego proszę albo pracować w motywie potomnym, albo użyć metody z filtrem z następnego rozdziału.
4. Alternatywne podejście: filtr template_include
Jeśli nie chce Pan/Pani zmieniać plików motywu (lub motyw jest blokowy, bez klasycznego single.php), szablon można przypisać przez hook template_include. Uruchamia się on zanim WordPress podłączy plik szablonu i pozwala nadpisać ścieżkę.
Minus: plik szablonu trzeba będzie przechowywać albo we wtyczce, albo w motywie potomnym, kod musi wskazać poprawną ścieżkę. Plus: logika nie ginie przy aktualizacji motywu nadrzędnego.
4.1. Przykład: jeden CPT, jeden szablon
Proszę dodać w functions.php motywu potomnego (lub w MU-plugin):
1 add_filter( 'template_include', 'techblog_cpt_template', 99 ); 2 3 function techblog_cpt_template( $template ) { 4 if ( is_singular( 'aktsii' ) ) { 5 $custom_template = get_stylesheet_directory() . '/single-aktsii.php'; 6 if ( file_exists( $custom_template ) ) { 7 return $custom_template; 8 } 9 } 10 return $template; 11 }
Kod sprawdza: czy otwarta jest strona niestandardowego typu aktsii? Jeśli tak, szuka pliku single-aktsii.php w folderze motywu potomnego (get_stylesheet_directory()) i zwraca go. Jeśli nie znajdzie, zwraca standardowy $template bez zmian.
4.2. Przykład: kilka CPT z jednym handlerem
Jeśli niestandardowych typów jest kilka, wygodnie zebrać logikę w jednym filtrze:
1 add_filter( 'template_include', 'techblog_cpt_templates', 99 ); 2 3 function techblog_cpt_templates( $template ) { 4 $cpt_templates = array( 5 'aktsii' => 'single-aktsii.php', 6 'portfolio' => 'single-portfolio.php', 7 'testimonials' => 'single-testimonials.php', 8 ); 9 10 foreach ( $cpt_templates as $cpt => $template_file ) { 11 if ( is_singular( $cpt ) ) { 12 $custom_template = get_stylesheet_directory() . '/' . $template_file; 13 if ( file_exists( $custom_template ) ) { 14 return $custom_template; 15 } 16 } 17 } 18 19 return $template; 20 }
Teraz każdy CPT otrzymuje swój szablon, a cała logika jest w jednej funkcji.
4.3. Przechowywanie szablonów we wtyczce
Jeśli rozpowszechnia Pan/Pani niestandardowy typ jako wtyczkę (a nie jako część motywu), logiczne jest przechowywanie szablonu w folderze wtyczki. Wtedy ścieżkę wskazuje się przez plugin_dir_path( __FILE__ ):
1 add_filter( 'template_include', 'myplugin_cpt_template', 99 ); 2 3 function myplugin_cpt_template( $template ) { 4 if ( is_singular( 'aktsii' ) ) { 5 $custom_template = plugin_dir_path( __FILE__ ) . 'templates/single-aktsii.php'; 6 if ( file_exists( $custom_template ) ) { 7 return $custom_template; 8 } 9 } 10 return $template; 11 }
Ten wzorzec stosuje wiele popularnych wtyczek (WooCommerce, Easy Digital Downloads, The Events Calendar), niosą one szablony wewnątrz siebie i podłączają je przez filtr.
5. Tworzenie niestandardowego typu wpisów
Sam szablon zrobiliśmy, ale dla kompletności obrazu, kilka słów o tym, skąd bierze się niestandardowy typ.
5.1. Rejestracja przez kod
Minimalna rejestracja CPT w functions.php lub MU-plugin:
1 add_action( 'init', 'techblog_register_cpt_aktsii' ); 2 3 function techblog_register_cpt_aktsii() { 4 $labels = array( 5 'name' => 'Акции', 6 'singular_name' => 'Акция', 7 'menu_name' => 'Акции', 8 ); 9 10 $args = array( 11 'labels' => $labels, 12 'public' => true, 13 'has_archive' => true, 14 'supports' => array( 'title', 'editor', 'thumbnail' ), 15 'rewrite' => array( 'slug' => 'aktsii' ), 16 'show_in_rest' => true, 17 ); 18 19 register_post_type( 'aktsii', $args ); 20 }
Tutaj ważne jest: parametr 'rewrite' => array( 'slug' => 'aktsii' ) ustawia alias, który jest używany w URL i w nazwie pliku szablonu. Jeśli slug ustawiono jako aktsii, plik szablonu musi nazywać się single-aktsii.php.
5.2. Przez wtyczkę Custom Post Type UI
Jeśli nie chce Pan/Pani edytować functions.php, CPT tworzy się wizualnie przez bezpłatną wtyczkę Custom Post Type UI na WordPress.org. Po instalacji:
- Proszę przejść w panelu administracyjnym: CPT UI → Add/Edit Post Types
- Proszę wypełnić pola: Post Type Slug (po łacinie), Plural Label, Singular Label
- Na karcie Settings proszę zaznaczyć, które elementy edytora są potrzebne (title, editor, thumbnail)
- Proszę kliknąć Add Post Type
Wtyczka generuje kod PHP rejestracji, który można wyeksportować i wstawić do functions.php, wygodne, jeśli później zechce Pan/Pani usunąć zależność od wtyczki. Ten sam slug, który podał/a Pan/Pani w CPT UI, trafi do nazwy pliku szablonu.
⁉️🤔 Częste pytania
Co robić, jeśli szablon nie jest przechwytywany po utworzeniu pliku?
Proszę zresetować bezpośrednie odnośniki: proszę wejść w Ustawienia → Bezpośrednie odnośniki i kliknąć „Zapisz zmiany" (nic nie trzeba zmieniać). WordPress przebuduje reguły routingu. Jeśli to nie pomogło, proszę sprawdzić nazwę pliku: slug niestandardowego typu i nazwa pliku muszą być zgodne (wielkość liter, myślniki i podkreślniki). Trzeci krok, proszę wyczyścić cache wtyczki cachingowej, jeśli jest zainstalowana. Bezpośrednie odnośniki należy resetować po każdej rejestracji nowego niestandardowego typu, nie tylko przy problemach z szablonem. To standardowa praktyka: wchodzi Pan/Pani w Ustawienia → Bezpośrednie odnośniki → Zapisz, i nowe URL od razu działają.
Czy można używać jednego szablonu dla kilku niestandardowych typów?
Tak, na dwa sposoby. Pierwszy, utworzyć fizyczny plik
single-aktsii.php, a dla drugiego typu (na przykładportfolio) skopiować go jakosingle-portfolio.php. Drugi, przez filtrtemplate_include(rozdział 4): w tablicy$cpt_templateswskazać różnym typom ten sam plik szablonu. Ale w praktyce różne CPT prawie zawsze mają różny układ, kopiowanie i poprawianie jest prostsze niż budowanie logiki warunkowej wewnątrz szablonu. Jeśli typów jest naprawdę dużo i logika jest taka sama, proszę utworzyć ogólnysingle-cpt.php, wewnątrz sprawdzaćget_post_type()i podłączać odpowiedni template-part przezget_template_part( 'template-parts/content', get_post_type() ). To czyste i skalowalne podejście.
Czy trzeba tworzyć archive-{post_type}.php** dla strony archiwum?**
Wskazane, ale nie obowiązkowe. Bez niego WordPress używa
archive.phplubindex.php. Jeśli dla CPT włączono parametr'has_archive' => truei archiwum otwiera się pod adresem/aktsii/, a plikuarchive-aktsii.phpnie ma, zostanie użyty ogólnyarchive.php. Tworzenie osobnego szablonu archiwum warto rozważyć wtedy, gdy siatka wpisów, układ kolumn lub sidebar mają różnić się od archiwum blogowego.
Czy to działa z motywami blokowymi (FSE)?
W motywach blokowych klasyczne szablony PHP przez pliki motywu nie są główną ścieżką. Jednak filtr
template_include(rozdział 4) działa również w FSE: może Pan/Pani umieścić pliksingle-aktsii.phpw motywie potomnym lub wtyczce i podłączyć przez filtr. Alternatywnie, w edytorze witryny (Site Editor) można utworzyć szablon dla konkretnego niestandardowego typu przez interfejs: Appearance → Editor → Templates → Add New Template → Single Item: Aktsii. WordPress zapisze go jako szablon HTML w bazie danych i będzie działał bez plików w motywie.
Co stosować w 2026: plik czy filtr?
Krótka matryca wyboru podejścia:
Sytuacja | Co stosować |
|---|---|
Klasyczny motyw, jeden-dwa CPT | Plik |
Motyw potomny, CPT dodaje Pan/Pani | Plik w motywie potomnym - przetrwa aktualizacje motywu nadrzędnego |
Motyw blokowy (FSE), CPT przez wtyczkę | Filtr |
CPT rozpowszechniany jako wtyczka | Filtr + szablon wewnątrz folderu wtyczki |
Wiele CPT o podobnej strukturze | Filtr + ogólny |
W praktyce my na techblog.sdstudio.top najczęściej używamy kombinacji: CPT rejestrujemy przez kod w MU-plugin, a szablony umieszczamy jako pliki w motywie potomnym. Daje to automatyczne przechwytywanie bez zbędnych filtrów, a aktualizacje motywu nadrzędnego niczego nie psują.
Jeśli dopiero zaczyna się Pan/Pani zapoznawać z niestandardowymi typami, proszę zacząć od pliku single-{post_type}.php. To pięć minut pracy i natychmiastowy rezultat. A kiedy poczuje Pan/Pani, że możliwości podejścia plikowego nie wystarczają (trzeba ładować szablony z wtyczki lub zmieniać je w locie), proszę przejść na template_include. Obie metody są całkowicie legalne i wspierane przez rdzeń WordPress.



