niestandardowe typy wpisów wordpress

Custom Post Types w WordPress – kiedy i jak używać

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:

  1. Dashboard → Wtyczki → Dodaj nową
  2. Wyszukaj „Custom Post Type UI”
  3. 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 projekt

Krok 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: 5

Co 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: zaznaczone

BONUS: 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 projekcie

Krok 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: Tak

3: 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: Pionowy

4: 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: Thumbnail

Krok 3: Lokalizacja

Wyświetl tę grupę pól jeśli:
├─ Typ wpisu → jest równy → Portfolio

To 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 → klient

Warunkowa 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 == Branding

Teraz 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 (prefix wp_ 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: Opcjonalne

4. 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=789

Ustawienia 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-commerce
Taksonomia 2: Branża klienta
├─ Slug: branza
├─ Hierarchiczna: NIE
└─ Wartości: Medycyna, Finanse, Edukacja, Technologia

W 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_finansowy

Rozwią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!

Bądź na bieżąco...

otrzymuj najnowsze wiadomości, aktualizacje i wiele innych rzeczy co 2 tygodnie.

Zostaw komentarz

Przewijanie do góry