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
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 Repeater s Advanced 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í 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;
}
fetch načteme celou stránku s novým filtremToto ř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.
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.