Zilele trecute am avut următoarea situație:
- În backend: o taxonomie custom cu câteva zeci de terms
- În frontend: afișez ultimele zece articole dintr-un term + buton de încărcare a următorului term.
Prima idee a fost: încarc toate articolele dintr-un foc și fac toggle la vizibilitate cu JS. Dar se ajunge lejer la câteva sute de articole, lucru ce afectează performanța din toate punctele de vedere.
Concret, aveam o taxonomie pentru țări – fiecare term reprezenta o țară – și trebuia să afișez ultimele articole pentru prima țară. Apăsai buton, mai încărca o țară. Apăsai iar, încă o țară șamd.
Ca să facem asta cât mai eficient, trebuie să extragem logica necesară afișării articolelor dintr-o țară ori într-o funcție ori într-o clasă separată. Folosim o funcție:
function showCountry($countryID)
{
$term = get_term($countryID);
$countryQuery = new WP_Query([
'post_type' => 'myPostType',
'tax_query' => [
[
'taxonomy' => $term->taxonomy,
'terms' => $term->term_id,
],
],
'posts_per_page' => 10,
]);
while ($countryQuery->have_posts()) {
$countryQuery->the_post();
require get_template_directory() . '/templates/loop-more-countries.php';
}
wp_reset_postdata();
}
Tot codul responsabil de markup se află în loop-more-countries.php
dar acolo nu se întâmplă nimic interesant ce ar merita menționat.
Afișarea primei țări
Provocarea cea mai mare a fost să găsesc o modalitate eficientă de a afișa primul term la încărcarea paginii și restul la cerere, dinamic. Afișarea primului post e simplă, ne folosim de funcția de mai sus:
<?php
$countries = get_terms([
'taxonomy' => 'country',
'fields' => 'ids'
]);
?>
<div class="js-countries">
<?php showCountry($countries[0]); ?>
<div>
Problema era: cum notific JS-ul despre ultimul term încărcat?
<button class="js-loadMoreCountries"
data-countries='<?php echo json_encode( array_slice($countries, 1) ) ?>'>Load more countries</button>
Păi… simplu: setez atributul data-countries
ca un JSON ce conține ID-urilor tuturor terms mai puțin primul, cel deja afișat. Observă te rog că folosesc ghilimele simple, nu duble; asta pentru că jQuery știe să parseze JSON dintr-un atribut! Ce convenabil!
Vrei să afișezi mai multe terms inițial? Ori apelezi funcția showCountry
de mai multe ori, ori, mai elegant, folosești array_walk
:
array_walk(array_slice($countries, 0, 3), 'showCountry');
Evident, nu uităm să actualizăm și butonul:
json_encode( array_slice($countries, 3)
AJAX
Înainte de JS, hai să-i spunem WP-ului că așteptăm request-uri AJAX:
function loadMoreCountries()
{
$termID = absint($_REQUEST['termID']);
if ($termID>0) {
showCountry($termID);
}
die();
}
add_action('wp_ajax_load_more_countries', 'loadMoreCountries');
add_action('wp_ajax_nopriv_load_more_countries', 'loadMoreCountries');
Javascript
Pentru javascript logica e simplă: facem un request AJAX la fiecare apăsare de buton și ținem minte index-ul ultimului term încărcat. Când încărcăm ultimul term, ascundem butonul:
jQuery(document).ready(function($) {
var loadMoreButton = $('.js-loadMoreCountries');
var container = $('.js-countries');
var countriesIDs = loadMoreButton.data('countries'); // atributul data-countries al butonului de mai sus
var index = 0; // index-ul ultimului term încărcat
var loadingClass = 'is-loading';
var callbacks = {
beforeLoading: function() {
button.addClass(loadingClass)
container.addClass(loadingClass)
},
completeLoading: function() {
button.removeClass(loadingClass);
container.removeClass(loadingClass);
},
success: function(data) {
container.append(data);
},
}
loadMoreButton.on('click', function() {
if (loadMoreButton.hasClass(loadingClass)) {
return false;
}
var data = {
action: 'load_more_countries',
termID: countriesIDs[index]
};
index++; // următorul term
if (index >= countriesIDs.length) {
loadMoreButton.hide();
}
$.ajax({
url: loadMoreCountries.ajaxUrl,
data: data,
type: 'GET',
beforeSend: callbacks.beforeLoading,
complete: callbacks.completeLoading,
success: callbacks.success
});
return false;
})
});
Cam atât. Atenție însă, nu vrei să folosești această metodă dacă ai foarte multe terms! Cred că se pretează bine la maximum 50-100 items, dar peste s-ar putea să ai nevoie de o altă abordare. Oricum ar fi, nu uita să faci și cache la terms, altfel s-ar putea să aibă un impact asupra performanței (dar despre asta într-un alt articol).
Lasă un răspuns