zpět na technikálie

AJAX filtrace pro Oxygen Repeater/Easy Posts bez přenačtení stránky

Při práci s Oxygen Repeaterem/Easy Posts často potřebuju filtrovat obsah.

Standardně to znamená přenačtení celé stránky. Přiznejme si, že to uživatelsky není ono.

Pojďme si ukázat, jak implementovat AJAX filtraci, která zachová všechny výhody Oxygen renderingu, ale bez nutnosti obnovovat stránku.

Poznámka: nejedná se o JS filtraci, která neumí pagination, ale o plnohodnotné řešení. Srovnání různých přístupů k filtraci v předchozím článku.

Datum poslední změny: 6. 8. 2025

Výchozí situace

Máme Oxygen Repeater, který zobrazuje custom post type (vlastní typ příspěvku) s několika ACF, přes které chci filtrovat příspěvky. Pro výpis příspěvků používám RepeaterAdvanced Query. Filtruju podle url parametru přes meta query (přes ACF políčka).

Utm parametr získávám z parametru filter. Například:

<https://vase-stranka.cz/suppliers/?filter=furniture>

Řešení

Řešení využívá JavaScript k zachycení kliknutí na filtrační tlačítko, aktualizaci URL a výměnu obsahu Repeateru bez přenačtení stránky.

Poznámka: kódy níže jsou pro Repeater, ale pro Easy Posts se postup neliší. Drobné změny jsou jen v JS, kde se musí zohlednit jiné třídy a selektory (Repater a Easy Posts mají každý vlastní).

Takhle může vypadat adresářová struktura:

my-custom-plugin/
    ├── my-custom-plugin.php
    └── lib/
        └── js/
            └── filter-script.js

Příklad načtení JS (JS uveden dále):

function register_filter_script() {
    if (is_page('suppliers')) {
        wp_enqueue_script(
            'suppliers-filter',  
            plugin_dir_url(__FILE__) . 'lib/js/filter-script.js', 
            array(), 
            '1.0.0', 
            true
        );
    }
}
add_action('wp_enqueue_scripts', 'register_filter_script');

Takto může vypadat JS:

document.addEventListener('DOMContentLoaded', function() {
    const filterButtons = document.querySelectorAll('.filter-button');
    
    filterButtons.forEach(button => {
        button.addEventListener('click', function(e) {
            e.preventDefault();
            
            const filter = this.dataset.filter;
            const url = new URL(window.location);
            url.searchParams.set('filter', filter);
            
            window.history.pushState({}, '', url);
            
            const repeater = document.getElementById('dynamic_list');
            repeater.classList.add('loading');
            
            const tempContainer = document.createElement('div');
            tempContainer.style.display = 'none';
            document.body.appendChild(tempContainer);
            
            tempContainer.innerHTML = `<div class="oxy-dynamic-list" id="temp-list"></div>`;
            
            fetch(url.toString())
                .then(response => response.text())
                .then(html => {
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(html, 'text/html');
                    const newRepeater = doc.getElementById('dynamic_list');
                    
                    if (newRepeater) {
                        repeater.innerHTML = newRepeater.innerHTML;
                    }
                    
                    repeater.classList.remove('loading');  
                    tempContainer.remove();
                })
                .catch(error => {
                    console.error('Error:', error);
                    repeater.classList.remove('loading'); 
                    tempContainer.remove();
                });
        });
    });
});

Filtrační tlačítka

Samozřejmě nemusí jít o tlačítka. Můžou to být radio buttony (výběr jedné možnosti z vícera), check boxy (zaškrtávátka) nebo třeba selecty (rozbalovací nabídka). Pro tlačítka bude html například takovéto:

<button class="filter-button" data-filter="furniture">Nábytek</button>
<button class="filter-button" data-filter="inventory">Inventář</button>

A trocha "fancy" animace při načítání. 😊

.oxy-dynamic-list {
    transition: opacity 0.3s ease-in-out;
}

.oxy-dynamic-list.loading {
    opacity: 0.5;
}

Jak to funguje?

  1. Zachytíme klik na filtrační tlačítko
  2. Aktualizujeme URL s novým parametrem filtru
  3. Pomocí fetch načteme celou stránku s novým filtrem
  4. Z vrácené stránky "vykostíme" jen obsah repeateru
  5. Aktualizujeme kontejner Repeateru o nově načtený obsah

Výhody tohoto řešení

  1. Jednoduchá implementace - není potřeba vytvářet REST API endpoint
  2. Využití existující logiky - WP Query je definováno pouze v Oxygen Repeateru
  3. Funguje stránkování - server generuje správnou stránku s odpovídajícími daty
  4. Zachování Oxygen funkcionality - filtrační parametry a jiné nastavení v Oxygen Repeater/Easy Posts fungují normálně
  5. Robustní řešení - méně míst, kde se může něco pokazit
  6. Sdílitelné URL - odkazy s filtry vedou na stránku se volenou filtrací

Závěr

Toto řešení představuje elegantní kompromis mezi uživatelskou přívětivostí (žádné přenačítání stránky) a jednoduchostí implementace. Místo vytváření paralelní implementace WP Query v REST API využívám existující Oxygen funkcionalitu, což vede k robustnějšímu a udržitelnějšímu kódu.

WordPressito

Měsíční newsletter pro lidi, kteří chtějí, aby jejich WordPress spolehlivě fungoval.

Dozvíš se:

🔌 Tipy na užitečné pluginy a nástroje.
🆕 Novinky z WordPress světa.
💡 Praktické návody a rady.

srknu WordPressito
linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram