Pobieranie postów z kategorii w WordPress, przewodnik dewelopera
PL

Pobieranie postów z kategorii w WordPress, przewodnik dewelopera

Ostatnio zweryfikowano: 1 lipca 2026
9 min czytania
Poradnik
500+ projektów WP
Full-stack developer

#Wprowadzenie do pobierania postów według kategorii

Dowiedz się więcej o profesjonalnym tworzeniu stron WordPress w WPPoland. Jednym z najczęstszych zadań w tworzeniu WordPress jest pobieranie postów z konkretnych kategorii. Niezależnie od tego, czy budujesz niestandardówy układ strony głównej, tworzysz szablon archiwum kategorii, czy wyświetlasz powiązane treści, zrozumienie jak sprawnie odpytywać posty według kategorii jest niezbędne dla każdego dewelopera WordPress.

Ten kompleksowy przewodnik obejmuje wiele podejść do pobierania list postów z kategorii, od prostych implementacji po zaawansowane techniki optymalizacji. Po jego lekturze będziesz dysponować kompletnym zestawem narzędzi do obsługi zapytań opartych na kategoriach w każdym projekcie WordPress.

#Zrozumienie kategorii WordPress

Zanim przejdziemy do kodu, warto zrozumieć, jak WordPress obsługuje kategorie:

  • Kategorie to wbudowana taksonomia w WordPress
  • Każdy post może należeć do wielu kategorii
  • Kategorie mogą być hierarchiczne (relacje rodzic-dziecko)
  • Dane kategorii są przechowywane w tabelach wp_terms i wp_term_taxonomy
  • Relacje post-kategoria są przechowywane w wp_term_relationships

Zrozumienie tej struktury pomaga pisać bardziej wydajne zapytania i rozwiązywać problemy, gdy się pojawią.

#Ustalanie ID kategorii na podstawie sluga lub nazwy

Większość argumentów zapytania przyjmuje slug albo numeryczne ID, ale argumenty oparte na ID (cat, category__in) są najszybsze, bo pomijają wyszukiwanie termu. Gdy znasz tylko slug, rozwiąż go raz i używaj gotowego ID:

// Ze sluga
$term = get_category_by_slug('news');
$news_id = $term ? $term->term_id : 0;

// Z nazwy wyświetlanej
$news_id = get_cat_ID('News'); // zwraca 0, gdy nie znaleziono

// Z dowolnej taksonomii (w tym kategorii)
$term = get_term_by('slug', 'news', 'category');

W polskich instalacjach slug często bywa spolszczony (aktualnosci, poradniki), więc nie zakładaj z góry, że odpowiada nazwie wyświetlanej. Jeśli ID wpisujesz w szablonie na sztywno, zapisz je w stałej lub opcji, bo wywoływanie get_cat_ID() przy każdym żądaniu dokłada zbędne zapytanie do bazy.

#Metoda 1: WP_Query (podejście elastyczne)

WP_Query to podstawowa klasa WordPress do odpytywania postów. Oferuje maksymalną elastyczność i jest zalecanym podejściem w większości przypadków.

#Podstawowe zapytanie kategorii

$args = array(
    'category_name' => 'news',
    'posts_per_page' => 10,
    'orderby' => 'date',
    'order' => 'DESC'
);

$query = new WP_Query($args);

if ($query->have_posts()) {
    while ($query->have_posts()) {
        $query->the_post();
        // Wyświetl treść posta
        ?>
        <article>
            <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
            <div class="entry-content">
                <?php the_excerpt(); ?>
            </div>
        </article>
        <?php
    }
    wp_reset_postdata();
}

#Zapytanie według ID kategorii

$args = array(
    'cat' => 5, // ID kategorii
    'posts_per_page' => 5
);

$query = new WP_Query($args);

#Wiele kategorii

// Posty w KTÓREJKOLWIEK z tych kategorii (relacja LUB)
$args = array(
    'category__in' => array(5, 10, 15),
    'posts_per_page' => 10
);

// Posty we WSZYSTKICH tych kategoriach (relacja I)
$args = array(
    'category__and' => array(5, 10),
    'posts_per_page' => 10
);

// Wykluczenie konkretnych kategorii
$args = array(
    'category__not_in' => array(3, 7),
    'posts_per_page' => 10
);

#Uwzględnianie kategorii podrzędnych

// Pobierz posty z kategorii i wszystkich jej dzieci
$parent_category_id = 5;

$args = array(
    'cat' => $parent_category_id,
    'posts_per_page' => 20
);

// WP_Query automatycznie uwzględnia kategorie podrzędne przy użyciu 'cat'

#Metoda 2: get_posts() (podejście proste)

W prostszych przypadkach get_posts() oferuje bardziej przejrzyste API.

#Podstawowe użycie

$posts = get_posts(array(
    'category' => 5,
    'posts_per_page' => 10,
    'orderby' => 'date',
    'order' => 'DESC'
));

foreach ($posts as $post) {
    setup_postdata($post);
    ?>
    <article>
        <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
    </article>
    <?php
}
wp_reset_postdata();

#Z nazwą kategorii

$posts = get_posts(array(
    'category_name' => 'technology',
    'numberposts' => 5
));

#Metoda 3: Shortcody dla edytorów treści

Stworzenie shortcodu pozwala edytorom treści wstawiać listy postów z kategorii w dowolnym miejscu.

function category_posts_shortcode($atts) {
    $atts = shortcode_atts(array(
        'category' => '',
        'posts' => 5,
        'orderby' => 'date',
        'order' => 'DESC'
    ), $atts);
    
    $args = array(
        'category_name' => $atts['category'],
        'posts_per_page' => intval($atts['posts']),
        'orderby' => $atts['orderby'],
        'order' => $atts['order']
    );
    
    $query = new WP_Query($args);
    
    ob_start();
    
    if ($query->have_posts()) {
        echo '<div class="category-posts-list">';
        while ($query->have_posts()) {
            $query->the_post();
            ?>
            <article class="category-post">
                <h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
                <p><?php the_excerpt(); ?></p>
            </article>
            <?php
        }
        echo '</div>';
    } else {
        echo '<p>Nie znaleziono postów w tej kategorii.</p>';
    }
    
    wp_reset_postdata();
    
    return ob_get_clean();
}
add_shortcode('category_posts', 'category_posts_shortcode');

Użycie: [category_posts category="news" posts="5"]

#Metoda 4: Modyfikowanie głównego zapytania

Gdy chcesz zmienić, które posty pojawiają się na stronach archiwum kategorii, użyj akcji pre_get_posts.

function modify_category_queries($query) {
    // Modyfikuj tylko archiwa kategorii w głównym zapytaniu
    if ($query->is_category() && $query->is_main_query() && !is_admin()) {
        // Pokaż 20 postów na stronę zamiast domyślnej wartości
        $query->set('posts_per_page', 20);
        
        // Wykluczenie postów z konkretnej kategorii na określonych stronach kategorii
        $current_cat = get_queried_object();
        if ($current_cat->slug === 'featured') {
            $query->set('category__not_in', array(10)); // Wyklucz kategorię o ID 10
        }
    }
}
add_action('pre_get_posts', 'modify_category_queries');

#Metoda 5: tax_query dla precyzyjnego filtrowania po taksonomiach

Skróty cat i category_name są wygodne, ale gdy wymagania robią się bardziej złożone, sięgasz po tax_query: łączenie kategorii z tagami, wykluczanie termów podrzędnych albo odpytywanie własnej taksonomii. To jedyny argument, który jawnie wyraża logikę AND/OR, czego skróty nie potrafią.

$args = array(
    'posts_per_page' => 10,
    'tax_query' => array(
        'relation' => 'AND',
        array(
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => array('news'),
        ),
        array(
            'taxonomy' => 'post_tag',
            'field'    => 'slug',
            'terms'    => array('featured'),
        ),
    ),
);

$query = new WP_Query($args);

Kluczem, który najczęściej się pomija, jest include_children. Domyślnie tax_query dla category wciąga wszystkie termy potomne, co zwykle pasuje do archiwum, ale rzadko do wyselekcjonowanego bloku na stronie głównej:

'tax_query' => array(
    array(
        'taxonomy'         => 'category',
        'field'            => 'term_id',
        'terms'            => array(5),
        'include_children' => false, // tylko posty przypisane bezpośrednio do termu 5
    ),
),

Ponieważ tax_query działa na dowolnej taksonomii, ten sam wzorzec pobiera posty z własnej product_cat, portfolio_type czy jakiejkolwiek taksonomii zarejestrowanej przez motyw, bez osobnej funkcji dla każdej z nich. W praktyce w sklepach WooCommerce to właśnie tax_query po product_cat zastępuje próby odpytywania kategorii produktów zwykłym cat.

#Optymalizacja wydajności

#1. Używaj transients dla kosztownych zapytań

function get_cached_category_posts($category_id, $count = 5) {
    $cache_key = 'cat_posts_' . $category_id . '_' . $count;
    $posts = get_transient($cache_key);
    
    if (false === $posts) {
        $args = array(
            'cat' => $category_id,
            'posts_per_page' => $count
        );
        
        $query = new WP_Query($args);
        $posts = $query->posts;
        
        // Cache na 1 godzinę
        set_transient($cache_key, $posts, HOUR_IN_SECONDS);
    }
    
    return $posts;
}

#2. Optymalizacja zapytań do bazy danych

// Pobieraj tylko pola, których potrzebujesz
$args = array(
    'category_name' => 'news',
    'posts_per_page' => 10,
    'fields' => 'ids' // Pobieraj tylko ID postów dla lepszej wydajności
);

$query = new WP_Query($args);

#3. Używaj object caching

Jeśli Twoja strona korzysta z object cache (Redis, Memcached), wyniki WP_Query są automatycznie cachowane, co poprawia wydajność przy powtarzających się zapytaniach.

#Zaawansowane techniki

#Niestandardowe szablony dla archiwów kategorii

Utwórz plik szablonu category-news.php dla konkretnego stylowania kategorii:

<?php
/* Template Name: Kategoria - Aktualności */
get_header(); ?>

<div class="category-archive">
    <h1><?php single_cat_title(); ?></h1>
    
    <?php if (have_posts()) : ?>
        <div class="posts-grid">
            <?php while (have_posts()) : the_post(); ?>
                <?php get_template_part('content', 'category'); ?>
            <?php endwhile; ?>
        </div>
        
        <?php the_posts_pagination(); ?>
    <?php else : ?>
        <p>Nie znaleziono postów w tej kategorii.</p>
    <?php endif; ?>
</div>

<?php get_footer(); ?>

#Ładowanie AJAX dla postów kategorii

Dla lepszego doświadczenia użytkownika zaimplementuj ładowanie AJAX. Dwa szczegóły najczęściej sprawiają problemy: ajaxurl jest zdefiniowane tylko w wp-admin, więc na frontendzie musisz przekazać je samodzielnie, a każde żądanie potrzebuje nonce, żeby przejść audyt bezpieczeństwa.

Zarejestruj skrypt i przekaż mu adres admin-ajax oraz nonce:

function enqueue_category_loader() {
    wp_enqueue_script(
        'category-loader',
        get_theme_file_uri('/js/category-loader.js'),
        array('jquery'),
        '1.0',
        true
    );
    wp_localize_script('category-loader', 'catLoader', array(
        'ajaxurl' => admin_url('admin-ajax.php'),
        'nonce'   => wp_create_nonce('load_category_posts'),
    ));
}
add_action('wp_enqueue_scripts', 'enqueue_category_loader');

Żądanie z frontendu odczytuje wtedy dane z zlokalizowanego obiektu:

jQuery(document).ready(function($) {
    $('.load-more').on('click', function() {
        var button = $(this);

        $.ajax({
            url: catLoader.ajaxurl,
            type: 'POST',
            data: {
                action: 'load_category_posts',
                nonce: catLoader.nonce,
                category: button.data('category'),
                page: button.data('page')
            },
            success: function(response) {
                $('.posts-container').append(response);
                button.data('page', button.data('page') + 1);
            }
        });
    });
});

Na koniec zarejestruj handler dla użytkowników zalogowanych i anonimowych (wp_ajax_ oraz wp_ajax_nopriv_), zweryfikuj nonce i zwróć wyrenderowany kod:

function load_category_posts_handler() {
    check_ajax_referer('load_category_posts', 'nonce');

    $category = sanitize_text_field($_POST['category'] ?? '');
    $page     = max(1, intval($_POST['page'] ?? 1));

    $query = new WP_Query(array(
        'category_name'  => $category,
        'posts_per_page' => 5,
        'paged'          => $page,
    ));

    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();
            printf(
                '<article><h3><a href="%s">%s</a></h3></article>',
                esc_url(get_permalink()),
                esc_html(get_the_title())
            );
        }
        wp_reset_postdata();
    }

    wp_die(); // wymagane, aby admin-ajax zakończył się czysto
}
add_action('wp_ajax_load_category_posts', 'load_category_posts_handler');
add_action('wp_ajax_nopriv_load_category_posts', 'load_category_posts_handler');

#Wyświetlanie postów kategorii w motywie blokowym

W motywach blokowych (domyślnych od WordPress 6.1) często w ogóle nie potrzebujesz PHP. Blok pętli zapytań (Query Loop) filtrowany po kategorii renderuje tę samą listę z poziomu edytora: wstaw pętlę zapytań, otwórz ustawienia bloku i w sekcji filtrów dodaj wybraną kategorię. Zapisz to jako wzorzec synchronizowany, a redaktorzy będą mogli wstawiać wyselekcjonowaną listę na dowolnej stronie bez dotykania szablonu.

Po podejścia z kodem powyżej sięgaj wtedy, gdy potrzebujesz logiki, której blok nie wyrazi: cachowania w transientach, warunkowych wykluczeń per archiwum albo danych zużywanych poza motywem (biuletyn e-mail, odpowiedź z REST API).

#Pobieranie postów kategorii przez REST API

Dla frontendów headless, wyspy Reacta lub zewnętrznej integracji WordPress udostępnia posty kategorii przez REST API, bez potrzeby tworzenia własnego endpointu:

GET /wp-json/wp/v2/posts?categories=5&per_page=10&_fields=id,title,link,excerpt

Użyj categories_exclude, aby odfiltrować term, _embed, aby jednym żądaniem pobrać obrazki wyróżniające i nazwy termów, oraz _fields, aby ograniczyć payload do tego, co klient faktycznie renderuje. Aby zamienić slug na ID, którego oczekuje endpoint, najpierw odpytaj /wp-json/wp/v2/categories?slug=news.

#Debugowanie zapytania kategorii zwracającego niewłaściwe posty

Gdy zapytanie zwraca za dużo, za mało albo nieoczekiwane posty, obejrzyj SQL, który faktycznie się wykonał, zamiast zgadywać po argumentach. Zainstaluj Query Monitor, a pokaże każde zapytanie na stronie, w tym to wygenerowane przez Twoją pętlę, z oznaczeniem wolnych. Do szybkiego sprawdzenia bez wtyczki wypisz sparsowane zapytanie:

$query = new WP_Query($args);
// Dokładny SQL, który WordPress zbudował z Twoich $args
error_log($query->request);

Za większością niespodzianek stoją dwie przyczyny: uwzględnianie termów podrzędnych (patrz include_children powyżej) oraz zabłąkany filtr pre_get_posts z wtyczki lub motywu zmieniający główne zapytanie. Jeśli SQL wygląda poprawnie, a wynik jest pusty, upewnij się, że do termu naprawdę są przypisane opublikowane posty w bieżącym języku lub kontekście, o czym łatwo zapomnieć przy WPML czy Polylang.

#Częste błędy do uniknięcia

  1. Brak resetowania danych posta: zawsze wywołuj wp_reset_postdata() po niestandardowych pętlach
  2. Odpytywanie przy każdym ładowaniu strony: używaj cachowania dla kosztownych zapytań
  3. Brak sprawdzenia istnienia postów: zawsze weryfikuj have_posts() przed pętlą
  4. Nieprawidłowa modyfikacja głównego zapytania: używaj pre_get_posts zamiast tworzenia nowych zapytań na stronach archiwum
  5. Ignorowanie paginacji: pamiętaj o obsłudze paginacji dla dużych archiwów kategorii

#Podsumowanie

WordPress oferuje wiele sposobów pobierania postów z kategorii, z których każdy jest odpowiedni w różnych sytuacjach:

  • WP_Query: najlepsza do złożonych, niestandardowych wyświetleń
  • get_posts(): idealna do prostych list postów
  • Shortcody: doskonałe dla elastyczności edytorów treści
  • pre_get_posts: niezbędne do modyfikowania stron archiwum

Zrozumienie tych metod i wiedza, kiedy korzystać z każdej z nich, sprawi, że staniesz się bardziej efektywnym deweloperem WordPress. Pamiętaj, aby zawsze brać pod uwagę wydajność, szczególnie na stronach z dużą ilością treści.

W przypadku stron produkcyjnych wdróż strategie cachowania i testuj zapytania narzędziami takimi jak Query Monitor, aby zapewnić optymalną wydajność.

Następny krok

Przekuj artykuł w realne wdrożenie

Pod tym wpisem dokładam linki, które domykają intencję użytkownika i prowadzą dalej w strukturze serwisu.

Chcesz wdrożyć ten temat na swojej stronie?

Jeśli chcesz przełożyć wiedzę z artykułu na działającą stronę, sklep albo przebudowę serwisu, przygotuję konkretny zakres prac.

Powiązany klaster

Sprawdź inne usługi WordPress i bazę wiedzy

Wzmocnij swój biznes dzięki profesjonalnemu wsparciu technicznemu w kluczowych obszarach ekosystemu WordPress.

Czy muszę być doświadczonym deweloperem, aby korzystać z tego przewodnika?#
Ten przewodnik jest przeznaczony dla deweloperów WordPress na poziomie średniozaawansowanym. Zakładana jest podstawowa wiedza o PHP i WordPress, ale każdy kod jest wyjaśniany krok po kroku.
Czy te techniki działają z każdym motywem WordPress?#
Większość technik jest niezależna od motywu i działa ze standardowymi motywami WordPress. Jednak mocno dostosowane motywy mogą wymagać dodatkowej adaptacji.
Czy wdrożenie tych zmian na działającej stronie jest bezpieczne?#
Zawsze testuj zmiany najpierw na środowisku staging. Chociaż techniki są gotowe do użycia produkcyjnego, testowanie zapobiega potencjalnym problemom na żywej stronie.
Czy te metody działają z page builderami takimi jak Elementor?#
Tak, większość metod współpracuje z page builderami. Niektóre mogą wymagać konkretnych kroków integracji, które są opisane w sekcji implementacji.
Czy na motywie blokowym nadal potrzebuję kodu?#
Do zwykłej listy nie. Blok pętli zapytań (Query Loop) filtrowany po kategorii renderuje posty z poziomu edytora. Po kod sięgasz wtedy, gdy potrzebujesz cachowania, warunkowych wykluczeń albo danych zużywanych poza motywem, na przykład odpowiedzi z REST API.

Potrzebujesz FAQ dopasowanego do branży i rynku? Przygotujemy wersję pod Twoje cele biznesowe.

Porozmawiajmy

Polecane artykuły