Budujesz stronę portfolio i próbujesz wtłoczyć projekty w standardowe wpisy blogowe? Tworzysz stronę dla restauracji i zapisujesz dania menu jako zwykłe strony? Czujesz, że WordPress ogranicza Cię do „wpisów” i „stron” i zastanawiasz się jak przechowywać inne typy treści?
Poznaj niestandardowe typy wpisów WordPress (ang. custom post types) – potężną funkcję, która zmienia WordPress z prostego bloga w elastyczny system zarządzania treścią (CMS). W tym przewodniku dowiesz się, kiedy warto stworzyć własny typ wpisu WordPress, jak to zrobić bez pisania kodu, i jak wykorzystać to do maksimum.
Czym są niestandardowe typy wpisów w WordPress?
Definicja i podstawy
Niestandardowy typ wpisu (ang. custom post type, w skrócie CPT) to sposób na tworzenie i przechowywanie różnych rodzajów treści poza standardowymi wpisami i stronami WordPress.
Domyślne typy wpisów w WordPress:
- Wpis (ang. post) – dla bloga, chronologicznie
- Strona (ang. page) – statyczne treści, hierarchiczne
- Załącznik (ang. attachment) – media (obrazy, pliki)
- Wersje (ang. revisions) – historia zmian
- Menu nawigacyjne (ang. nav_menu_item) – elementy menu
Problem: Nie wszystko jest wpisem blogowym ani statyczną stroną.
Przykłady gdzie standardowe typy nie wystarczają:
🎨 Portfolio – Projekty nie są wpisami blogowymi
- Mają inne pola (klient, data realizacji, technologie)
- Inna prezentacja (galeria, case study)
- Inna organizacja (po kategoriach projektów)
🏢 Baza firm – Firmy to nie artykuły
- Pola: adres, telefon, godziny otwarcia, współrzędne GPS
- Prezentacja: mapa, lista, pojedyncza wizytówka
- Filtrowanie: po branży, lokalizacji
🍕 Menu restauracyjne – Dania mają swoją strukturę
- Pola: cena, składniki, alergeny, kalorie
- Grupowanie: przystawki, dania główne, desery
- Prezentacja: karta menu, nie blog
🎓 Kursy online – Lekcje to nie wpisy
- Pola: czas trwania, poziom trudności, wymagania
- Organizacja: moduły, kolejność lekcji
- Funkcje: postęp użytkownika, ukryte dla niezalogowanych
Dlaczego używać niestandardowych typów wpisów?
1. Organizacja treści Zamiast mieć wszystko jako „wpisy”, masz wyraźne kategorie:
- Portfolio → Projekty
- Blog → Wpisy
- Produkty → Sklep
- Zespół → Pracownicy
2. Dedykowane pola Każdy typ może mieć własne pola niestandardowe (ang. custom fields):
- Projekt: klient, rok, technologie, link
- Produkt: cena, SKU, zapas, wymiary
- Osoba: stanowisko, email, telefon, social media
3. Indywidualne szablony Każdy typ może wyglądać inaczej:
- Wpis blogowy: pełna szerokość, komentarze, data
- Projekt portfolio: galeria, sidebar z informacjami
- Produkt: duże zdjęcia, przycisk „Kup teraz”
4. Lepsze SEO i użytkownik
- Czyste URLe:
/projekty/strona-firmowa/zamiast/projekt-strona-firmowa/ - Breadcrumbs („okruszki”): Strona główna → Projekty → Strona firmowa
- Logiczne menu administracyjne
5. Skalowalność
- Łatwo dodać nowe pola
- Można mieć tysiące elementów każdego typu
- Niezależne zarządzanie każdym typem
Analogia:
Standardowy WordPress = szuflada na wszystko
CPT = szafka z wieloma szufladami, każda na inny typ rzeczy
Kiedy używać niestandardowych typów wpisów?
Przypadki użycia – przykłady z życia
✅ UŻYWAJ CPT, gdy chcesz stworzyć:
1. Portfolio / Projekty
Typ: portfolio
Pola:
- Klient
- Rok realizacji
- Technologie (wielokrotny wybór)
- Link do strony
- Galeria zdjęć
- Opis projektu
Taksonomie (kategorie):
- Typ projektu (strona www, aplikacja, branding)
- Branża (medycyna, e-commerce, edukacja)
URL: /portfolio/nazwa-projektu/Dlaczego CPT? Projekty nie są chronologiczne jak blog, potrzebują specjalnych pól i prezentacji.
2. Nieruchomości
Typ: nieruchomosci
Pola:
- Cena
- Powierzchnia (m²)
- Liczba pokoi
- Piętro
- Garaż (tak/nie)
- Współrzędne GPS
- Galeria
Taksonomie:
- Typ (mieszkanie, dom, działka)
- Lokalizacja (dzielnica/miasto)
- Status (sprzedane, dostępne, rezerwacja)
URL: /nieruchomosci/apartament-centrum-krakowa/Dlaczego CPT? Nieruchomości mają unikalne parametry, potrzebują wyszukiwania zaawansowanego, map.
3. Wydarzenia / Events
Typ: wydarzenia
Pola:
- Data i godzina rozpoczęcia
- Data i godzina zakończenia
- Lokalizacja (adres)
- Cena biletu
- Link do rejestracji
- Organizator
- Mapa
Taksonomie:
- Kategoria (konferencja, warsztat, meetup)
- Miasto
URL: /wydarzenia/konferencja-wordpress-2025/Dlaczego CPT? Wydarzenia mają daty, lokalizacje, trzeba je sortować chronologicznie ale inaczej niż blog.
4. Członkowie zespołu
Typ: zespol
Pola:
- Zdjęcie
- Stanowisko
- Bio
- Email
- Telefon
- LinkedIn
- Twitter
Taksonomie:
- Dział (zarząd, marketing, IT)
URL: /zespol/jan-kowalski/Dlaczego CPT? Profile nie są artykułami, mają strukturę wizytówki.
5. Referencje / Testimoniale
Typ: referencje
Pola:
- Cytat
- Osoba (imię, nazwisko)
- Stanowisko
- Firma
- Logo firmy
- Ocena (gwiazdki)
- Zdjęcie osoby
URL: /referencje/jan-nowak-firma-abc/Dlaczego CPT? Testimoniale wyświetlane są inaczej, potrzeba specjalnych widgetów.
6. Menu restauracji
Typ: dania
Pola:
- Cena
- Składniki
- Alergeny
- Kalorie
- Waga/porcja
- Ostrość (dla potraw)
- Zdjęcie
Taksonomie:
- Kategoria (przystawki, zupy, dania główne, desery)
- Dieta (wegetariańskie, wegańskie, bezglutenowe)
URL: /menu/spaghetti-carbonara/❌ NIE UŻYWAJ CPT, gdy chcesz:
1. Chronologiczny blog Standardowy wpis wystarcza. CPT tylko komplikuje.
2. Pojedyncze strony informacyjne „O nas”, „Kontakt”, „Polityka prywatności” – standardowe strony są OK.
3. Tylko 2-3 elementy Nie warto tworzyć CPT dla 3 członków zespołu. Użyj strony z sekcjami.
4. Brak potrzeby specjalnych pól Jeśli nie potrzebujesz custom fields, CPT jest przesadą.
5. Treść będzie zmieniana rzadko Dla statycznych treści użyj page buildera i zwykłej strony.
Drzewo decyzyjne
Czy treść ma strukturę różną od wpisu/strony?
├─ NIE → Użyj standardowych wpisów/stron
└─ TAK → Czy będzie >5 elementów?
├─ NIE → Rozważ zwykłe strony lub sekcje
└─ TAK → Czy potrzebujesz specjalnych pól?
├─ NIE → Może wystarczą kategorie?
└─ TAK → UTWÓRZ CPT!Złota zasada: Jeśli coś „nie czuje się” jak wpis blogowy ani statyczna strona – prawdopodobnie potrzebuje CPT.
Implementacja bez kodu – wtyczki
Metoda 1: Custom Post Type UI (najprostsza)
Najpopularniejsza wtyczka – 1M+ aktywnych instalacji, darmowa.
Instalacja:
- Dashboard → Wtyczki → Dodaj nową
- Wyszukaj „Custom Post Type UI”
- Instaluj i aktywuj
Tworzenie CPT krok po kroku:
Podstawowe ustawienia:
CPT UI → Dodaj/edytuj typy wpisów
Podstawowe ustawienia:
├─ Slug (identyfikator): portfolio
│ (tylko małe litery, myślniki, bez spacji)
├─ Liczba mnoga: Projekty
├─ Liczba pojedyncza: Projekt
└─ Slug liczby mnogiej: projekty (do URL)Etykiety
Dodatkowe etykiety (opcjonalne):
├─ Dodaj nowy: Dodaj nowy projekt
├─ Edytuj: Edytuj projekt
├─ Wszystkie elementy: Wszystkie projekty
└─ itp. (CPT UI wypełnia automatycznie)Ustawienia
Ustawienia:
├─ Publiczny: TAK (widoczny na stronie)
├─ Ma archiwum: TAK (strona /projekty/)
├─ Hierarchiczny: NIE (chyba że chcesz podstrony)
├─ Wyświetlaj w menu: TAK
├─ Pozycja menu: 5 (pod "Wpisami")
├─ Ikona menu: dashicons-portfolio (wybierz z listy)
│
Obsługuje (features):
├─ Tytuł: TAK
├─ Edytor: TAK (treść)
├─ Wyróżniony obrazek: TAK
├─ Wycinek: TAK (excerpt)
├─ Komentarze: NIE (zwykle)
└─ Niestandardowe pola: TAK (jeśli planujesz ACF)Krok 4: Adresy URL (permalinki)
Przepisz:
├─ Slug: projekty
├─ Wsparcie: TAK (dla single: /projekty/nazwa/)
│
struktura URL:
/projekty/ → archiwum wszystkich
/projekty/nazwa-projektu/ → pojedynczy projektKrok 5: Zapisz Kliknij „Dodaj typ wpisu”
WAŻNE: Po utworzeniu CPT idź do: Ustawienia → Bezpośrednie odnośniki → Zapisz zmiany (resetuje permalinki)
Gotowe! W menu admin pojawi się nowa sekcja „Projekty”.
Metoda 2: Pods (zaawansowane funkcje)
Gdy potrzebujesz więcej: Pods to CPT + custom fields + relacje w jednym.
Instalacja:
Wtyczki → Dodaj nową → "Pods Framework"Tworzenie CPT w Pods:
Pods Admin → Dodaj nowy
1. Typ zawartości: Niestandardowy typ wpisu (Custom Post Type)
2. Utwórz nowy lub rozszerz istniejący: Utwórz nowy
3. Nazwa (singular): Projekt
4. Nazwa (plural): Projekty
5. Zaawansowane opcje (Advanced):
├─ Permalink Erase Slug: Tak (opcjonalnie)
├─ Hierarchiczny: Nie
├─ Supports: Tytuł, Edytor, Obrazek wyróżniony
└─ Menu pozycja: 5Co czyni Pods lepszym:
- Łatwiejsze tworzenie pól niestandardowych (built-in)
- Relacje między typami (np. Projekt → Klient)
- Zaawansowane szablony
- Lepsze API dla developerów
Wada: Bardziej złożony, może przytłoczyć początkujących.
Metoda 3: JetEngine (dla Elementora/Bricks)
Jeśli używasz page buildera: JetEngine integruje się idealnie.
Instalacja: Płatna wtyczka (~$26/rok), część ekosystemu Crocoblock.
Korzyści:
- Visual builder dla CPT
- Dynamic content w Elementorze (wyświetlanie pól CPT)
- Query builder (zaawansowane filtry)
- Gotowe widgety (listy, single templates)
Tworzenie CPT w JetEngine:
JetEngine → Post Types → Add New
1. Ogólne:
├─ Slug: portfolio
├─ Name (singular): Projekt
├─ Name (plural): Projekty
2. Labels: (auto-wypełniane)
3. Advanced settings:
├─ Public: True
├─ Has archive: True
├─ Menu icon: dashicons-portfolio
4. Supports:
├─ Title, Editor, Thumbnail: zaznaczoneBONUS: Od razu możesz dodać Meta Fields (pola niestandardowe) w tym samym interfejsie!
Porównanie metod
┌──────────────────┬─────────────┬──────────┬────────────┐
│ Funkcja │ CPT UI │ Pods │ JetEngine │
├──────────────────┼─────────────┼──────────┼────────────┤
│ Łatwość │ ⭐⭐⭐⭐⭐ │ ⭐⭐⭐ │ ⭐⭐⭐⭐ │
│ Custom Fields │ ❌ (osobno) │ ✅ │ ✅ │
│ Relacje │ ❌ │ ✅ │ ✅ │
│ Builder │ │ │ │
│ integration │ ❌ │ ~ │ ✅✅ │
│ Cena │ Darmowa │ Free │ $26/rok │
│ Dla kogo │ Początkujący│ Dev │ Elementor │
└──────────────────┴─────────────┴─────────┴─────────────┘Rekomendacja:
- Zaczynasz? → CPT UI
- Potrzebujesz relacji? → Pods
- Używasz Elementora/Bricks? → JetEngine
Advanced Custom Fields – pola niestandardowe
Czym są pola niestandardowe?
Pola niestandardowe (ang. custom fields) to dodatkowe informacje które możesz przypisać do CPT.
Przykład: Typ wpisu „Projekt”
- Standardowe pola WordPress: Tytuł, Treść, Obrazek wyróżniony
- Niestandardowe pola: Klient, Rok, Technologie, Link, Budżet
ACF – Advanced Custom Fields (najpopularniejsza wtyczka)
Instalacja:
Wtyczki → Dodaj nową → "Advanced Custom Fields"
Wersje:
├─ ACF Free (wystarczająca dla 80% projektów)
└─ ACF PRO ($249/rok - Unlimited websites , zaawansowane pola)Tworzenie grupy pól – przykład dla Portfolio:
Krok 1: Nowa grupa pól
ACF → Grupy pól → Dodaj nową
Tytuł: Informacje o projekcieKrok 2: Dodaj pola
1: Klient
├─ Typ pola: Tekst (Text)
├─ Etykieta pola: Klient
├─ Nazwa pola: klient (automatycznie)
├─ Instrukcje: Nazwa klienta dla którego zrealizowano projekt
├─ Wymagane: Tak
└─ Placeholder: np. "Firma ABC Sp. z o.o."2: Rok realizacji
├─ Typ pola: Data (Date Picker)
├─ Etykieta: Rok realizacji
├─ Nazwa: rok_realizacji
├─ Format wyświetlania: Y (tylko rok)
├─ Format zwracany: Y
└─ Wymagane: Tak3: Technologie
├─ Typ pola: Lista wyboru (Checkbox)
├─ Etykieta: Użyte technologie
├─ Nazwa: technologie
├─ Wybory (każdy w nowej linii):
WordPress
React
PHP
JavaScript
CSS/SASS
└─ Układ: Pionowy4: Link do strony
├─ Typ pola: URL
├─ Etykieta: Link do projektu
├─ Nazwa: link_projektu
├─ Placeholder: https://
└─ Wymagane: Nie (nie wszystkie projekty mają publiczny link)5: Galeria
├─ Typ pola: Galeria (Gallery) [wymaga ACF PRO]
│ (lub: Obraz (Image) z "Multiple values" w free)
├─ Etykieta: Galeria projektu
├─ Nazwa: galeria_projektu
├─ Min/Max: 3 obrazów minimum, 20 maksimum
└─ Rozmiar podglądu: ThumbnailKrok 3: Lokalizacja
Wyświetl tę grupę pól jeśli:
├─ Typ wpisu → jest równy → PortfolioTo sprawia że pola pojawią się TYLKO przy edycji projektów, nie wpisów blogowych!
Krok 4: Ustawienia
├─ Pozycja: Normal (po edytorze)
├─ Styl: Domyślny
└─ Ukryj na ekranie: Pola niestandardowe (żeby nie było konfliktu)Zapisz grupę pól.
Typy pól ACF – pełna lista
Podstawowe:
- Text – krótki tekst (imię, tytuł, slug)
- Text Area – dłuższy tekst (opis, notatka)
- Number – liczby (cena, waga, ilość)
- Email – walidowany email
- URL – walidowany link
- Password – ukryte znaki
Wybór:
- Select – rozwijana lista (1 wybór)
- Checkbox – wiele wyborów
- Radio Button – jeden wybór (widoczne opcje)
- Button Group – jak radio, ale przyciski
- True/False – przełącznik (tak/nie)
Treść:
- WYSIWYG Editor – edytor jak w wpisie
- oEmbed – embedy (YouTube, Vimeo)
- File – upload dowolnego pliku
- Image – upload obrazka z wyborem rozmiaru
- Gallery – wiele obrazków [PRO]
Relacyjne:
- Link – kreator linków (internal/external)
- Post Object – wybór wpisu/strony
- Page Link – link do strony
- Relationship – relacje wiele-do-wielu [PRO]
- Taxonomy – wybór terminu taksonomii
- User – wybór użytkownika
jQuery:
- Google Map – mapa z markerem [PRO]
- Date Picker – kalendarz wyboru daty
- Date Time Picker – data + godzina [PRO]
- Time Picker – tylko czas [PRO]
- Color Picker – wybór koloru
Layout:
- Message – informacja (nie zapisuje danych)
- Accordion – składane sekcje [PRO]
- Tab – zakładki [PRO]
- Group – grupowanie pól [PRO]
- Repeater – powtarzalne sekcje [PRO]
- Flexible Content – dynamiczne układy [PRO]
- Clone – klonowanie pól [PRO]
Wyświetlanie pól w szablonie
Metoda 1: Funkcje ACF (w PHP)
<?php
// W single-portfolio.php (szablon pojedynczego projektu)
// Pobierz wartość pola
$klient = get_field('klient');
$rok = get_field('rok_realizacji');
$technologie = get_field('technologie'); // array
$link = get_field('link_projektu');
$galeria = get_field('galeria_projektu'); // array obrazków
// Wyświetl
?>
<div class="project-info">
<h2><?php the_title(); ?></h2>
<?php if ($klient): ?>
<p><strong>Klient:</strong> <?php echo esc_html($klient); ?></p>
<?php endif; ?>
<?php if ($rok): ?>
<p><strong>Rok:</strong> <?php echo esc_html($rok); ?></p>
<?php endif; ?>
<?php if ($technologie): ?>
<p><strong>Technologie:</strong></p>
<ul class="tech-list">
<?php foreach ($technologie as $tech): ?>
<li><?php echo esc_html($tech); ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<?php if ($link): ?>
<a href="<?php echo esc_url($link); ?>" target="_blank" class="btn">
Zobacz projekt →
</a>
<?php endif; ?>
</div>
<?php
// Galeria
if ($galeria):
?>
<div class="project-gallery">
<?php foreach ($galeria as $image): ?>
<a href="<?php echo esc_url($image['url']); ?>" data-lightbox="gallery">
<img src="<?php echo esc_url($image['sizes']['medium']); ?>"
alt="<?php echo esc_attr($image['alt']); ?>">
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>Metoda 2: Dynamic content w page builderze
Dla Elementora (z JetEngine lub Dynamic Tags):
1. Przeciągnij widget "Heading"
2. Kliknij ikonę dynamiczną (tornedo)
3. Wybierz: ACF → Pole → klient
4. Gotowe! Automatycznie wyświetli wartośćDla Bricks:
1. Dodaj element Text
2. Zamiast tekstu kliknij {x} (dynamic data)
3. Wybierz: Post Custom Fields → klientWarunkowa logika ACF
Przykład: Pokaż pole „Link do projektu” tylko gdy checkbox „Projekt publiczny” jest zaznaczony
Pole: projekt_publiczny
├─ Typ: True/False
├─ Etykieta: Projekt jest publicznie dostępny
Pole: link_projektu
├─ Typ: URL
├─ Warunkowa logika:
└─ Pokaż to pole jeśli:
projekt_publiczny jest równy 1 (zaznaczony)Zaawansowany przykład: Różne pola dla różnych typów projektów
Pole: typ_projektu
├─ Typ: Radio Button
├─ Wybory: Strona WWW | Aplikacja mobilna | Branding
Pole: url_strony
├─ Typ: URL
├─ Warunkowa logika:
└─ typ_projektu == Strona WWW
Pole: system_operacyjny
├─ Typ: Checkbox
├─ Wybory: iOS | Android
├─ Warunkowa logika:
└─ typ_projektu == Aplikacja mobilna
Pole: logo_warianty
├─ Typ: Gallery [PRO]
├─ Warunkowa logika:
└─ typ_projektu == BrandingTeraz formularz dostosowuje się do typu projektu!
Best practices – dobre praktyki
1. Nazewnictwo
Slug CPT (identyfikator):
✅ Dobre:
portfolio(krótko, jasno)nieruchomosci(bez polskich znaków!)case_studies(podkreślnik OK)
❌ Złe:
Portfolio(wielkie litery)nasze projekty(spacje)nieruchomości(polskie znaki)wp_portfolio(prefixwp_zarezerwowany)
Nazwy pól ACF:
✅ Dobre:
klient(małe, bez znaków)rok_realizacji(podkreślnik dla czytelności)cena_netto
❌ Złe:
Klient(wielkie)rok realizacji(spacja)cena(netto)(znaki specjalne)
Złota zasada: slug i nazwy pól = małe litery, a-z, 0-9, podkreślenie/myślnik
2. Organizacja pól ACF
Grupuj logicznie:
Grupa: Podstawowe informacje
├─ Klient
├─ Rok realizacji
└─ Budżet
Grupa: Szczegóły techniczne
├─ Technologie (checkbox)
├─ Repozytorium GitHub (URL)
└─ Czas realizacji (number)
Grupa: Media
├─ Galeria (gallery)
└─ Video prezentacja (oEmbed)
Grupa: Linki
├─ Link do projektu (URL)
└─ Case study PDF (file)W ACF PRO użyj zakładek (Tabs) do separacji.
3. Walidacja i wymagane pola
Zawsze wymagane:
- Pola kluczowe dla typu (np. cena dla produktu)
- Pola użyte w szablonach (żeby nie było pustych miejsc)
Opcjonalne:
- Nice-to-have info
- Pola używane warunk owo
Przykład:
Portfolio:
├─ Tytuł projektu: WYMAGANE
├─ Klient: WYMAGANE
├─ Rok: WYMAGANE
├─ Opis (treść WP): WYMAGANE
├─ Obrazek wyróżniony: WYMAGANE
├─ Galeria: Opcjonalne (ale zalecane)
├─ Link: Opcjonalne (nie zawsze publiczny)
└─ Case study PDF: Opcjonalne4. Permalinki i slug
Struktura URL:
✅ Czytelne:
/portfolio/redesign-strony-firmowej/
/nieruchomosci/apartament-centrum-krakowa/
/zespol/jan-kowalski/❌ Niczytelne:
/post/123/
/?p=456
/type/portfolio/?id=789Ustawienia w CPT UI:
Przepisać:
├─ Slug: portfolio (pojawi się w URL)
├─ With Front: NIE (jeśli nie chcesz /blog/portfolio/)
└─ Hierarchiczny: TAK (dla podstron)Po zmianie permalink: Zawsze idź do Ustawienia → Bezpośrednie odnośniki → Zapisz
5. Archiwum i pojedyncze widoki
Zapewnij oba szablony:
Archiwum (archive-portfolio.php):
- Lista wszystkich projektów
- Filtrowanie (po kategoriach, tagach)
- Pagination (stronicowanie)
Single (single-portfolio.php):
- Pojedynczy projekt
- Wszystkie szczegóły
- Galeria, linki, pola ACF
Jeśli używasz page buildera:
- JetEngine/Elementor: ThemeBuilder → Archive/Single templates
- Oxygen: Templates → Archive/Single
6. Taksonomie (kategorie i tagi)
Dodaj własne taksonomie dla lepszej organizacji:
Przykład dla Portfolio:
Taksonomia 1: Kategoria projektu
├─ Slug: kategoria-projektu
├─ Hierarchiczna: TAK (może mieć podkategorie)
├─ Wartości:
├─ Strony internetowe
│ ├─ Landing pages
│ └─ Serwisy korporacyjne
├─ Aplikacje mobilne
│ ├─ iOS
│ └─ Android
└─ E-commerceTaksonomia 2: Branża klienta
├─ Slug: branza
├─ Hierarchiczna: NIE
└─ Wartości: Medycyna, Finanse, Edukacja, TechnologiaW CPT UI:
CPT UI → Dodaj/edytuj taksonomie
Podstawowe:
├─ Slug: kategoria-projektu
├─ Liczba mnoga: Kategorie projektów
├─ Liczba pojedyncza: Kategoria projektu
└─ Hierarchiczna: TAK
Przypisz do:
└─ Typy wpisów: Portfolio (zaznacz)7. Wydajność i optymalizacja
Niestandardowe typy wpisów WordPress mogą obciążać bazę danych, jeśli masz tysiące elementów z dziesiątkami pól:
Użyj cache’owania:
<?php
// Transient API - cache na 12 godzin
$projekty = get_transient('lista_projektow_portfolio');
if (false === $projekty) {
$projekty = new WP_Query(['post_type' => 'portfolio','posts_per_page' => -1]);
set_transient('lista_projektow_portfolio', $projekty, 12 * HOUR_IN_SECONDS);
}
?>
Ogranicz pola w zapytaniach:
<?php
// Tylko ID i tytuł (bez całej treści)
$query = new WP_Query(['post_type' => 'portfolio','fields' => 'ids' // Tylko ID]);
?>
Lazy loading dla obrazów:
W szablonach dodaj loading=”lazy” do tagów <img>:
<img src="<?php echo $url; ?>" loading="lazy" alt="...">Pagination (stronicowanie):
Nie ładuj 500 projektów na raz:
<?php
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$query = new WP_Query(['post_type' => 'portfolio','posts_per_page' => 12,'paged' => $paged]);
?>
8. Zabezpieczenia
Sanityzacja i walidacja danych:
<?php
// ZAWSZE używaj funkcji escapowania
// Dla tekstu:
echo esc_html($klient);
// Dla URL:
echo esc_url($link_projektu);
// Dla atrybutów:
echo esc_attr($alt_text);
// Dla JavaScript:
echo esc_js($zmienna);
?>
Uprawnienia użytkowników:
<?php
// Ogranicz dostęp do CPT
register_post_type('portfolio', ['capability_type' => 'portfolio_item','map_meta_cap' => true,'capabilities' => ['edit_post' => 'edit_portfolio_item','edit_posts' => 'edit_portfolio_items','edit_others_posts' => 'edit_others_portfolio_items','publish_posts' => 'publish_portfolio_items','read_post' => 'read_portfolio_item','delete_post' => 'delete_portfolio_item',]]);
?>
9. Backup i migracja
Eksport CPT i pól ACF:
- Wtyczka WP All Export/Import – eksport do XML/CSV
- ACF → Tools → Export Field Groups (kod PHP lub JSON)
- CPT UI → Tools → Get Code (kod rejestracji CPT)
Zapisz konfigurację jako kod:
Zamiast polegać na bazie danych, zapisz CPT i pola ACF jako kod w motywie potomnym lub wtyczce funkcjonalności. Dzięki temu łatwo przeniesiesz konfigurację między środowiskami.
// W functions.php motywu potomnego lub wtyczki:
require_once 'inc/custom-post-types.php';
require_once 'inc/acf-fields.php';10. Testowanie
Przed wdrożeniem na produkcję:
- ✅ Sprawdź wszystkie szablony (archive, single, taxonomy)
- ✅ Przetestuj responsywność (mobile, tablet, desktop)
- ✅ Zweryfikuj SEO (tytuły, opisy, schema.org)
- ✅ Sprawdź permalinki i 404 errors
- ✅ Przetestuj filtry i wyszukiwanie
- ✅ Dodaj przykładowe dane (lorem ipsum)
- ✅ Sprawdź wydajność (GTmetrix, PageSpeed Insights)
Zaawansowane zastosowania
Relacje między typami wpisów
Przykład: Portfolio + Klienci
Zamiast zapisywać nazwę klienta jako tekst, stwórz osobny CPT „Klienci” i powiąż projekty z klientami.
Typy wpisów:
- Portfolio (projekty)
- Klienci (klient)
W ACF PRO dodaj pole relacji:
Pole: powiazany_klient
├─ Typ: Post Object lub Relationship
├─ Typ wpisu: Klienci
└─ Wybór: Pojedynczy (lub wielokrotny)
Wyświetlanie:
<?php
$klient = get_field('powiazany_klient');
if ($klient) {echo '<h3>Klient: ' . get_the_title($klient->ID) . '</h3>'; // Pobierz pola klienta
$logo = get_field('logo', $klient->ID);
$website = get_field('strona_www', $klient->ID);}
?>
Korzyści:
- Unikasz duplikowania danych (logo, kontakt klienta)
- Łatwa aktualizacja (zmień raz w profilu klienta, zaktualizuje się wszędzie)
- Możesz wyświetlić wszystkie projekty danego klienta
Dynamiczne filtry i wyszukiwanie
Dla bardziej zaawansowanych stron z portfolio lub katalogów, dodaj filtry AJAX.
Wtyczki polecane:
- FacetWP (płatna) – najlepsze filtry dla CPT
- SearchWP (płatna) – wyszukiwanie w polach ACF
- JetSmartFilters (Crocoblock) – dla Elementora
Przykład funkcjonalności:
- Filtruj portfolio po technologiach (checkbox)
- Filtruj według roku realizacji (slider)
- Wyszukiwanie pełno-tekstowe w opisach projektów
- Sortowanie (najnowsze, według nazwy, według klienta)
Integracja z REST API
Niestandardowe typy wpisów WordPress są automatycznie dostępne przez WordPress REST API.
Aktywacja w rejestracji CPT:
<?php
register_post_type('portfolio', ['show_in_rest' => true, // Włącza REST API
'rest_base' => 'portfolio', // Endpoint: /wp-json/wp/v2/portfolio]);
?>
Dodaj pola ACF do REST API:
<?php
// W functions.php
add_action('rest_api_init', function() {
register_rest_field('portfolio', 'pola_acf', [
'get_callback' => function($object) {
return [
'klient' => get_field('klient', $object['id']),
'rok' => get_field('rok_realizacji', $object['id']),
'technologie' => get_field('technologie', $object['id']),];
}
]);
});
?>
Przykład użycia:
// Fetch z JavaScript
fetch('/wp-json/wp/v2/portfolio').then(res => res.json()).then(data => {
console.log(data); // Wszystkie projekty + pola ACF
});
Zastosowania:
- Aplikacje React/Vue pobierające dane z WordPressa
- Mobilne aplikacje (React Native, Flutter)
- Headless WordPress (frontend oddzielony od backendu)
- Integracje z zewnętrznymi systemami
Najczęstsze błędy i jak ich unikać
Błąd 1: Za dużo typów wpisów
Problem:
Tworzenie osobnego CPT dla każdej drobnej różnicy w treści.
Przykład złego podejścia:
├─ blog_techniczny
├─ blog_biznesowy
├─ blog_marketingowy
└─ blog_finansowyRozwiązanie:
Jeden CPT „Blog” z taksonomią „Kategoria”:
blog
└─ Kategorie:
├─ Technologia
├─ Biznes
├─ Marketing
└─ Finanse
Błąd 2: Zapomnienie o resetowaniu permalinków
Problem:
Po utworzeniu CPT strony pokazują błąd 404.
Rozwiązanie:
ZAWSZE po dodaniu/zmianie CPT:
Panel administracyjny → Ustawienia → Bezpośrednie odnośniki → Zapisz zmiany(Nie musisz nic zmieniać, tylko kliknąć „Zapisz”)
Błąd 3: Używanie polskich znaków w slug
Problem:
❌ Slug: „nieruchomości” → błędy w URL i bazie danych
Rozwiązanie:
✅ Slug: „nieruchomosci” (bez polskich znaków)
Nazwy wyświetlane mogą mieć polskie znaki, ale slug zawsze ASCII.
Błąd 4: Brak szablonów
Problem:
Tworzysz CPT, ale używa domyślnych szablonów wpisów, co wygląda źle.
Rozwiązanie:
Stwórz dedykowane szablony w motywie:
- single-portfolio.php (pojedynczy projekt)
- archive-portfolio.php (lista projektów)
- taxonomy-kategoria-projektu.php (archiwum kategorii)
Lub użyj page buildera (Elementor ThemeBuilder, Oxygen Templates).
Błąd 5: Brak walidacji pól ACF
Problem:
Użytkownik może zapisać projekt bez kluczowych informacji (np. bez roku realizacji).
Rozwiązanie:
W ustawieniach każdego pola ACF zaznacz „Wymagane: Tak” dla kluczowych pól.
Dodatkowo możesz dodać niestandardową walidację:
<?php
add_filter('acf/validate_value/name=rok_realizacji', function($valid, $value) {
if ($valid !== true) return $valid;
if ($value < 2000 || $value > date('Y')) {
return 'Rok musi być między 2000 a ' . date('Y');
}
return $valid;
}, 10, 2);
?>
Podsumowanie i checklisty
Niestandardowe typy wpisów WordPress to fundament profesjonalnych stron internetowych. Pozwalają odejść od ograniczeń standardowych wpisów i stron, tworząc struktury idealnie dopasowane do potrzeb projektu.
Checklista przed wdrożeniem CPT
Planowanie:
- ✅ Czy naprawdę potrzebuję CPT? (może wystarczą kategorie?)
- ✅ Jakie pola będą potrzebne?
- ✅ Jak będzie wyglądać struktura URL?
- ✅ Czy potrzeba taksonomii (kategorii własnych)?
Implementacja:
- ✅ Zainstalowano CPT UI lub inną wtyczkę
- ✅ Utworzono typ wpisu z poprawnym slug (bez polskich znaków)
- ✅ Zresetowano permalinki (Ustawienia → Bezpośrednie odnośniki → Zapisz)
- ✅ Zainstalowano ACF i utworzono grupy pól
- ✅ Ustawiono pola jako wymagane gdzie potrzeba
Szablony:
- ✅ Stworzono single-{type}.php
- ✅ Stworzono archive-{type}.php
- ✅ Dodano wyświetlanie pól ACF w szablonach
- ✅ Użyto funkcji escapowania (esc_html, esc_url, esc_attr)
Testowanie:
- ✅ Przetestowano wszystkie szablony
- ✅ Sprawdzono responsywność
- ✅ Zweryfikowano SEO (Yoast/RankMath)
- ✅ Sprawdzono wydajność
- ✅ Dodano przykładowe dane testowe
SEO:
- ✅ Włączono 'show_in_rest’ => true (dla Gutenberga i REST API)
- ✅ Ustawiono 'has_archive’ => true
- ✅ Skonfigurowano breadcrumbs
- ✅ Dodano schema.org markup (opcjonalnie)
Kluczowe wnioski
- Niestandardowe typy wpisów WordPress to must-have dla niemal każdej strony poza prostym blogiem
- Nie komplikuj – użyj CPT UI na start, przejdź na kod gdy potrzebujesz więcej kontroli
- ACF to nieodłączny partner CPT – razem tworzą potężne narzędzie
- Zawsze resetuj permalinki po zmianach w CPT
- Planuj strukturę przed implementacją – późniejsze zmiany są kosztowne
Co dalej?
Jeśli dopiero zaczynasz:
- Zacznij od prostego CPT (np. Portfolio z 3-5 polami)
- Użyj CPT UI + ACF Free
- Eksperymentuj z różnymi typami pól
- Naucz się tworzyć podstawowe szablony PHP
Jeśli masz doświadczenie:
- Przejdź na ACF PRO (Repeater, Flexible Content, Gallery)
- Eksploruj Pods lub JetEngine dla zaawansowanych relacji
- Naucz się REST API i headless WordPress
- Automatyzuj z WP-CLI
Powodzenia w tworzeniu zaawansowanych stron WordPress!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
💬 Potrzebujesz pomocy z wdrożeniem niestandardowych typów wpisów WordPress na swojej stronie?
Zostaw komentarz poniżej – chętnie pomogę!
🔖 Zapisz ten artykuł jako zakładkę – przyda się podczas każdego projektu!
![{"type":"elementor","siteurl":"https://danutacybulska.pl/wp-json/","elements":[{"id":"e6dd003","elType":"widget","isInner":false,"isLocked":false,"settings":{"editor":"Napisz krótko jaki masz problem z WordPress - przygotuje dla Ciebie bezpłatną wycenę!","_margin":{"unit":"px","top":"0","right":"0","bottom":"40","left":"0","isLinked":false},"_animation":"fadeIn","_animation_delay":250,"align":"left","__globals__":{"typography_typography":"globals/typography?id=text","text_color":"globals/colors?id=primary"},"drop_cap":"","text_columns":"","text_columns_tablet":"","text_columns_mobile":"","column_gap":{"unit":"px","size":"","sizes":[]},"column_gap_tablet":{"unit":"px","size":"","sizes":[]},"column_gap_mobile":{"unit":"px","size":"","sizes":[]},"align_tablet":"","align_mobile":"","typography_typography":"","typography_font_family":"","typography_font_size":{"unit":"px","size":"","sizes":[]},"typography_font_size_tablet":{"unit":"px","size":"","sizes":[]},"typography_font_size_mobile":{"unit":"px","size":"","sizes":[]},"typography_font_weight":"","typography_text_transform":"","typography_font_style":"","typography_text_decoration":"","typography_line_height":{"unit":"px","size":"","sizes":[]},"typography_line_height_tablet":{"unit":"em","size":"","sizes":[]},"typography_line_height_mobile":{"unit":"em","size":"","sizes":[]},"typography_letter_spacing":{"unit":"px","size":"","sizes":[]},"typography_letter_spacing_tablet":](https://danutacybulska.pl/wp-content/uploads/2022/04/cropped-MOJE-NOWE-LOGO_bez-tla-1-1-100x106.png)

