fbpx

Jak dodać filtr postów WordPress i wyświetlić je na stronie bez wtyczek

Nowoczesna nawigacja po wpisach na stronie WordPress

Dobrze zorganizowana lista artykułów to ogromna zaleta każdej witryny. Szczególnie wtedy, gdy prezentujemy dużą ilość treści. Dzięki prostemu kodowi możesz wyświetlić wszystkie wpisy blogowe na jednej stronie. Dodatkowo użytkownik może filtrować je według kategorii i przeszukiwać tytuły wpisów. Takie rozwiązanie zapewnia większy komfort dla czytelnika i jednocześnie podnosi jakość UX.

Zastosowanie funkcji AJAX pozwala na dynamiczne filtrowanie zawartości bez przeładowywania strony. To sprawia, że przeglądanie postów staje się szybsze i bardziej płynne. Co ważne, użytkownik widzi wyniki od razu, co zwiększa jego zaangażowanie.

Cały mechanizm działa w pełni responsywnie – wygląda dobrze zarówno na komputerach, jak i na urządzeniach mobilnych. W wersji mobilnej zastosowano akordeon, który ukrywa przyciski kategorii. Dzięki temu nie zajmują one zbyt dużo miejsca na ekranie.

Szybkie filtrowanie dzięki dynamicznemu kodowi

Zamiast sięgać po kolejne wtyczki, warto samodzielnie wdrożyć filtr postów WordPress. Kod, który prezentujemy, oparty jest o prosty shortcode. Dzięki niemu możesz dodać system przeszukiwania i filtrowania w dowolnym miejscu strony.

Shortcode ten wykorzystuje wewnętrzne mechanizmy WordPressa oraz AJAX. Działa płynnie i eliminuje konieczność ładowania kolejnych podstron. Całość została przygotowana tak, by była łatwa w dostosowaniu do indywidualnych potrzeb strony.

Co więcej, styl CSS również uwzględnia różne rozdzielczości ekranu. Dzięki temu nie musisz martwić się o mobilną wersję witryny. Wszystko wygląda spójnie i działa poprawnie.

Dlaczego warto zastosować tę funkcję

Z technicznego punktu widzenia, filtr postów WordPress poprawia dostępność treści. Z punktu widzenia użytkownika natomiast – daje możliwość szybkiego dotarcia do interesujących wpisów. To ważne, szczególnie na stronach z dużą ilością treści blogowych lub poradnikowych.

Nie musisz być programistą, by wdrożyć takie rozwiązanie. Wystarczy, że skopiujesz kod i wkleisz go do pliku functions.php lub do wtyczki Code Snippets. Następnie użyj shortcode’a [ostatnie_wpisy] w wybranym miejscu.

// 1. Shortcode – zachowujemy oryginalną nazwę: [ostatnie_wpisy]
function custom_recent_posts_shortcode() {
    ob_start(); ?>

    <!-- NOWE: Filtry kategorii z akordeonem mobilnym -->
    <?php
    $categories = get_categories(array(
        'hide_empty' => true,
        'exclude'    => array(103)
    ));
    ?>

    <style>
    @media (max-width: 768px) {
        #category-accordion-toggle {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px 15px;
            background: #f1f1f1;
            cursor: pointer;
            border: 1px solid #ddd;
            margin-bottom: 10px;
        }
        #category-accordion-toggle span {
            font-weight: bold;
        }
        #category-accordion-toggle .arrow {
            transition: transform 0.3s;
        }
        #category-accordion-toggle.active .arrow {
            transform: rotate(180deg);
        }
        #custom-category-buttons {
            display: none;
            flex-direction: column;
            gap: 10px;
            margin-bottom: 20px;
        }
        #custom-category-buttons.show {
            display: flex;
        }
        .category-filter-btn {
            width: 100%;
            text-align: left;
        }
    }
    @media (min-width: 769px) {
        #category-accordion-toggle {
            display: none;
        }
        #custom-category-buttons {
            display: flex !important;
            flex-wrap: wrap;
            gap: 10px;
            margin-bottom: 20px;
        }
    }
    </style>

    <div id="category-accordion-toggle">
        <span>Kategorie</span>
        <span class="arrow">▼</span>
    </div>

    <div id="custom-category-buttons">
        <button class="category-filter-btn active" data-category="all" style="padding: 8px 15px;">Wszystkie</button>
        <?php foreach ($categories as $category): ?>
            <button class="category-filter-btn" data-category="<?php echo esc_attr($category->term_id); ?>" style="padding: 8px 15px;"><?php echo esc_html($category->name); ?></button>
        <?php endforeach; ?>
    </div>

    <script>
    document.addEventListener('DOMContentLoaded', function () {
        const toggle = document.getElementById('category-accordion-toggle');
        const categoryList = document.getElementById('custom-category-buttons');
        if (toggle && categoryList) {
            toggle.addEventListener('click', function () {
                toggle.classList.toggle('active');
                categoryList.classList.toggle('show');
            });
        }
    });
    </script>

    <div id="custom-post-search" style="margin-bottom: 20px;">
        <input type="text" id="search-input" placeholder="Szukaj po tytule..." style="width: 100%; padding: 10px; font-size: 1em;" />
    </div>

    <div id="custom-post-list">
        <?php echo get_custom_all_posts_html(); ?>
    </div>

    <?php
    return ob_get_clean();
}
add_shortcode('ostatnie_wpisy', 'custom_recent_posts_shortcode');

// 2. Funkcja do pobierania WSZYSTKICH wpisów
function get_custom_all_posts_html() {
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'post_status'    => 'publish',
        'orderby'        => 'date',
        'order'          => 'DESC'
    );

    $query = new WP_Query($args);
    $total_posts = $query->found_posts;
    ob_start();

    if ($query->have_posts()) {
        $i = 0;
        while ($query->have_posts()) {
            $query->the_post();
            $i++;
            $post_number = $total_posts - $i + 1;
            ?>

            <div class="custom-post-item" style="display: flex; margin-bottom: 20px;">
                <div class="custom-post-image" style="width: 40%; margin-right: 20px;">
                    <?php the_post_thumbnail('full'); ?>
                </div>
                <div class="custom-post-content" style="width: 60%;">
                    <?php
                    $categories = get_the_category();
                    if (!empty($categories)) {
                        echo '<div class="kategoria-wpisu" style="font-size: 0.85em; color: #777; margin-bottom: 5px;">Kategoria:<b> ' . esc_html($categories[0]->name) . '</b></div>';
                    }
                    ?>
                    <div class="tytul-wpisu">
                        <h2 style="margin-top: 0;"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
                    </div>
                    <div class="streszczenie-wpisu">
                        <p><?php echo wp_trim_words(get_the_excerpt(), 25, ' [...]'); ?></p>
                    </div>
                    <div class="data-i-godzina-wpisu">
                        <p style="font-size: 0.9em; color: #555;">Autor: <?php the_author(); ?> | <?php the_time('d.m.Y H:i'); ?></p>
                    </div>
                    <div class="czytajwiecej" style="margin-top: 10px;">
                        <a class="czytaj-wiecej" href="<?php the_permalink(); ?>" style="display: inline-block;">Czytaj więcej</a>
                        <span style="margin-left: 10px; font-size: 0.9em; color: #999;">Post #<?php echo $post_number; ?></span>
                    </div>
                </div>
            </div>

        <?php }
    }

    wp_reset_postdata();
    return ob_get_clean();
}

// 3. JavaScript – live search + filtr kategorii
function custom_search_script() {
    ?>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        const searchInput = document.getElementById('search-input');

        const filterPosts = (categoryId, searchText) => {
            const data = new FormData();
            data.append('action', 'filter_posts');
            data.append('category_id', categoryId);
            data.append('search_text', searchText);

            fetch('<?php echo admin_url("admin-ajax.php"); ?>', {
                method: 'POST',
                body: data
            })
            .then(response => response.text())
            .then(html => {
                document.getElementById('custom-post-list').innerHTML = html;
            });
        };

        document.querySelectorAll('.category-filter-btn').forEach(button => {
            button.addEventListener('click', function() {
                document.querySelectorAll('.category-filter-btn').forEach(btn => btn.classList.remove('active'));
                this.classList.add('active');
                const catId = this.dataset.category;
                const searchText = searchInput?.value || '';
                filterPosts(catId, searchText);
            });
        });

        if (searchInput) {
            searchInput.addEventListener('input', function() {
                const activeBtn = document.querySelector('.category-filter-btn.active');
                const categoryId = activeBtn ? activeBtn.dataset.category : 'all';
                filterPosts(categoryId, this.value);
            });
        }
    });
    </script>
    <?php
}
add_action('wp_footer', 'custom_search_script');

// 4. AJAX backend handler (filtrowanie postów)
add_action('wp_ajax_filter_posts', 'ajax_filter_posts_callback');
add_action('wp_ajax_nopriv_filter_posts', 'ajax_filter_posts_callback');

function ajax_filter_posts_callback() {
    $cat_id = sanitize_text_field($_POST['category_id']);
    $search = sanitize_text_field($_POST['search_text']);

    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'post_status'    => 'publish',
        'orderby'        => 'date',
        'order'          => 'DESC',
    );

    if ($cat_id && $cat_id !== 'all') {
        $args['cat'] = intval($cat_id);
    }

    if (!empty($search)) {
        $args['s'] = $search;
    }

    $query = new WP_Query($args);
    $total = $query->found_posts;
    $i = 0;

    if ($query->have_posts()) {
        ob_start();
        while ($query->have_posts()) {
            $query->the_post();
            $i++;
            $post_number = $total - $i + 1;
            ?>
            <div class="custom-post-item" style="display: flex; margin-bottom: 20px;">
                <div class="custom-post-image" style="width: 40%; margin-right: 20px;">
                    <?php the_post_thumbnail('full'); ?>
                </div>
                <div class="custom-post-content" style="width: 60%;">
                    <?php
                    $categories = get_the_category();
                    if (!empty($categories)) {
                        echo '<div class="kategoria-wpisu" style="font-size: 0.85em; color: #777; margin-bottom: 5px;">Kategoria:<b> ' . esc_html($categories[0]->name) . '</b></div>';
                    }
                    ?>
                    <div class="tytul-wpisu">
                        <h2 style="margin-top: 0;"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
                    </div>
                    <div class="streszczenie-wpisu">
                        <p><?php echo wp_trim_words(get_the_excerpt(), 25, ' [...]'); ?></p>
                    </div>
                    <div class="data-i-godzina-wpisu">
                        <p style="font-size: 0.9em; color: #555;">Autor: <?php the_author(); ?> | <?php the_time('d.m.Y H:i'); ?></p>
                    </div>
                    <div class="czytajwiecej" style="margin-top: 10px;">
                        <a class="czytaj-wiecej" href="<?php the_permalink(); ?>" style="display: inline-block;">Czytaj więcej</a>
                        <span style="margin-left: 10px; font-size: 0.9em; color: #999;">Post #<?php echo $post_number; ?></span>
                    </div>
                </div>
            </div>
            <?php
        }
        wp_reset_postdata();
        echo ob_get_clean();
    } else {
        echo '<p>Brak wyników.</p>';
    }

    wp_die();
}

Zostaw komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Imię:


Nazwisko:


Adres email:


Nazwa Twojej firmy:


NIP Twojej firmy

REGON Twojej firmy



Adres Twojej firmy

Ulica

Kod pocztowy

Miasto

Wybierz bramkę płatniczą na Twojej stronie