Per realizzare un infinte scroll o un bottone che carichi il contenuto successivo è necessario utilizzare AJAX.
Proprio per questo credo sia molto importante dare una breve introduzione a questo argomento.
Cos’è AJAX?
Ajax, acronimo di Asynchronous JavaScript and XML si basa su uno scambio di dati in background fra web browser e server.
Esso consente quindi l’aggiornamento dinamico di una pagina web senza un ricaricamento da parte dell’utente.
Perché utilizzarlo?
Facciamo subito un esempio pratico e immaginiamo di essere nella pagina blog del nostro sito.
Esso, con molta probabilità e se configurato correttamente avrà più pagine, solitamente nominate in questo modo: https://example.com/blog/page/1.
Passare alla seconda pagina del nostro blog comporterà un nuovo caricamento degli stili, degli script e dell’HTML stesso.
Invece, eseguendo una richiesta AJAX, non verranno ricaricati nuovamente tutti questi file ma solamente gli articoli successivi.
In quest’ultimo caso l’utente non sarà costretto ad aspettare il caricamento completo di una nuova pagina e tutto ciò si tradurrà in una miglior esperienza utente.
Infinite scroll e bottone load more
Ora che ti ho illustrato una breve introduzione sull’argomento AJAX sei pronto per costruire il tuo scroll infinito o alternativamente un bottone per caricare il contenuto successivo.
Creare uno shortcode WordPress
La prima cosa da fare è creare uno shortcode WordPress da utilizzare nella pagina in questione, nel mio caso la pagina del blog.
Per fare ciò dobbiamo creare una funzione di callback che verrà eseguita ogni volta che viene utilizzato il codice.
Aggiungiamo quindi il seguente codice nel file functions.php
.
Puoi trovare questo file al seguente percorso: /wp-content/themes/temaattivo/functions.php
.
function script_load_more($args = array()) {
echo '<div id="ajax-primary" class="content-area">';
echo '<div id="ajax-content" class="content-area">';
ajax_script_load_more($args);
echo '</div>';
echo '<a href="#" id="loadMore" data-page="1" data-url="'.admin_url("admin-ajax.php").'" >Load More</a>';
echo '</div>';
}
Ora creiamo il nostro shortcode il quale richiamerà la funzione script_load_more
.
Inseriscilo sempre nel file functions.php
.
add_shortcode('ajax_posts', 'script_load_more');
Crea la richiesta AJAX
Adesso dobbiamo creare la funzione che richiamerà gli articoli successivi, cioè ajax_script_load_more
chiamato all’interno della funzione script_load_more
.
Aggiungiamo perciò la seguente funzione nel file functions.php
.
function ajax_script_load_more($args) {
//Init ajax
$ajax = false;
//Controlla la chiamata AJAX
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$ajax = true;
}
//Numero degli articoli da caricare
$num =3;
//Numero della pagina
$paged = $_POST['page'] + 1;
//Args
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' =>$num,
'paged'=>$paged
);
//Query
$query = new WP_Query($args);
//Controllo
if ($query->have_posts()):
//loop articales
while ($query->have_posts()): $query->the_post();
//include articles template
include 'contenuto-ajax.php';
endwhile;
else:
echo 0;
endif;
//Ripristina post
wp_reset_postdata();
//Controlla la chiamata AJAX
if($ajax) die();
}
Con questa funzione verranno caricati 3 articoli alla volta.
Se vuoi caricarne di più o di meno modifica il valore $num
.
Crea il template dell’articolo
Ora crea il file contenuto-ajax.php
che verrà utilizzato nella funzione ajax_script_load_more
.
Questo è il file che conterrà il template dell’articolo.
Inserisci questo file al seguente percorso /wp-content/themes/temaattivo/contenuto-ajax.php
.
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<div class="box-articolo">
<div class="img-articolo">
<a class="img-thumbnail" href="<?php the_permalink() ?>"><?php the_post_thumbnail(); ?></a>
</div>
<div class="container-articolo">
<h3 class="titolo-articolo"><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></h3>
<div class="meta-articolo">
<p class="data">Pubblicato il <time><?php the_time('j F, Y'); ?></time></p>
<span class="divisore">/</span>
<a class="autore" href="<?php the_author_link(); ?>"><?php the_author(); ?> </a>
<span class="divisore">/</span>
<?php $parentscategory ="";
foreach((get_the_category()) as $category) {
if ($category->category_parent == 0) {
$parentscategory .= ' <a class="categoria" href="' . get_category_link($category->cat_ID) . '" title="' . $category->name . '">' . $category->name . '</a>, ';
}
}
echo substr($parentscategory,0,-2); ?>
</div>
<div class="excerpt">
<?php the_excerpt(); ?>
</div>
<div class="btn-altro">
<a class="leggi-altro" href="<?php the_permalink() ?>">Leggi altro</a>
</div>
</div>
</div>
</article>
Crea un action hook AJAX
Ora dobbiamo creare un action hook AJAX per richiamare la funzione ajax_script_load_more
.
Per farlo aggiungi il seguente codice nel file functions.php
.
add_action('wp_ajax_nopriv_ajax_script_load_more', 'ajax_script_load_more');
add_action('wp_ajax_ajax_script_load_more', 'ajax_script_load_more');
Crea il file script per lo scroll infinito o per il bottone load more
Ora creiamo il file scripts_ajax.js
all’interno della directory js del tema attivo.
Dovresti trovarla al seguente percorso: /wp-content/themes/temaattivo/js/scripts_ajax.js
.
Dopodiché creiamo una funzione nel file functions.php
che richiami questo script nel footer del nostro sito.
add_action( 'wp_enqueue_scripts', 'ajax_enqueue_script' );
function ajax_enqueue_script() {
wp_enqueue_script( 'scripts_ajax', get_theme_file_uri( '/js/scripts_ajax.js' ), array( 'jquery' ), '1.0', true );
}
Ora hai due possibilità, scegli una delle due e inserisci il codice apposito.
1) Caricare gli articoli successivi quando l’utente seleziona il bottone carica altro.
jQuery.noConflict($);
/* Funzioni AJAX */
jQuery(document).ready(function($) {
//Esegue la funzione quando avviene il click
$("#loadMore").on('click', function(e) {
e.preventDefault();
//Init
var that = $(this);
var page = $(this).data('page');
var newPage = page + 1;
var ajaxurl = that.data('url');
//Chiamata AJAX
$.ajax({
url: ajaxurl,
type: 'post',
data: {
page: page,
action: 'ajax_script_load_more'
},
error: function(response) {
console.log(response);
},
success: function(response) {
//Controllo
if (response == 0) {
$('#ajax-content').append('<div class="text-center"><h3>Non sono presenti altri articoli!</h3></div>');
$('#loadMore').hide();
} else {
that.data('page', newPage);
$('#ajax-content').append(response);
}
}
});
});
});
2) Caricare gli articoli quando l’utente scrolla la pagina.
jQuery.noConflict($);
/* Funzioni AJAX */
jQuery(document).ready(function($) {
//Trova la posizione dello scroll
$(window).scroll(function() {
//Init
var that = $('#loadMore');
var page = $('#loadMore').data('page');
var newPage = page + 1;
var ajaxurl = $('#loadMore').data('url');
//Controllo
if ($(window).scrollTop() == $(document).height() - $(window).height()) {
//Chiamata AJAX
$.ajax({
url: ajaxurl,
type: 'post',
data: {
page: page,
action: 'ajax_script_load_more'
},
error: function(response) {
console.log(response);
},
success: function(response) {
//Controllo
if (response == 0) {
//Controllo
if ($("#no-more").length == 0) {
$('#ajax-content').append('<div id="no-more" class="text-center"><h3>Non sono presenti altri articoli!</h3></div>');
}
$('#loadMore').hide();
} else {
$('#loadMore').data('page', newPage);
$('#ajax-content').append(response);
}
}
});
}
});
});
Utilizzando questo codice verranno caricati altri articoli solamente quando arriverai a toccare la fine della pagina.
Se vuoi che gli articoli successivi vengano caricati prima di toccare la fine della pagina utilizza questo codice:
jQuery.noConflict($);
/* Funzioni AJAX */
jQuery(document).ready(function($) {
var eseguito = false;
//Trova la posizione dello scroll
$(window).scroll(function() {
//Init
var that = $('#loadMore');
var page = $('#loadMore').data('page');
var newPage = page + 1;
var ajaxurl = $('#loadMore').data('url');
if (eseguito) {
//if ($(window).scrollTop() <= ($(document).height() - $(window).height())*0.8){
if ($(window).scrollTop() <= (($(document).height() - $(window).height())- $("footer").height())-200) {
eseguito = false;
} else {
return false;
}
}
if (!eseguito) {
//Controllo
//if ($(window).scrollTop() >= ($(document).height() - $(window).height())*0.8){
if ($(window).scrollTop() >= (($(document).height() - $(window).height())- $("footer").height())-200) {
eseguito = true;
//Chiamata AJAX
$.ajax({
url: ajaxurl,
type: 'post',
data: {
page: page,
action: 'ajax_script_load_more'
},
error: function(response) {
console.log(response);
},
success: function(response) {
//Controllo
if (response == 0) {
//Controllo
if ($("#no-more").length == 0) {
$('#ajax-content').append('<div id="no-more" class="text-center"><h3>You reached the end of the line!</h3><p>No more posts to load.</p></div>');
}
$('#loadMore').hide();
} else {
$('#loadMore').data('page', newPage);
$('#ajax-content').append(response);
}
}
});
}
}
});
});
Come puoi vedere viene dichiarata una variabile eseguito
che indica se la chiamata AJAX è già stata eseguita.
Questo perché utilizzando esclusivamente il valore >
nella selezione verrebbero eseguite più chiamate del singolo oggetto restituendo così gli stessi 3 articoli più volte.
Inoltre è presente un’altra possibile selezione sotto commento che ti permette di caricare altri post quando si arriva all’80% della pagina.
Aggiungere shortcode per visualizzare gli articoli
Ora non ti resta altro che aggiungere il seguente shortcode nella pagina del blog per ottenere il risultato sperato.
<?php echo do_shortcode('[[ajax_posts]]'); ?>
Come utilizzare AJAX “infinite scroll” o “load more” nelle pagine categorie e tag
Mi sono accorto che mano a mano che aumentava la popolarità di questo post, aumentavano anche le richieste di come poter applicare questa tipologia di codice alle pagine categoria e tag.
Molti per cercare di far funzionare il codice da me riportato hanno provato ad utilizzare il seguente filtro:
$categoria_corrente = get_queried_object();
$ID_categoria_corrente = $categoria_corrente->term_id;
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'cat' => $ID_categoria_corrente,
'posts_per_page' =>$num,
'paged'=>$paged
);
Purtroppo però questo codice funziona solo nel primo richiamo, dopodiché non riuscirà più a trovare la pagina da cui viene effettuata la richiesta, perché il codice partirà dal file JavaScript.
Così ho subito deciso di creare una versione funzionante con solo qualche piccola modifica. Di seguito il codice JavaScript:
jQuery.noConflict($);
jQuery(document).ready(function($) {
var eseguito = false;
//find scroll position
$(window).scroll(function() {
//init
var that = $('#loadMore');
// L'aggiornamento parte da qui
var classBody = document.getElementsByTagName("body")[0].className;
var cat = classBody.replace( /^\D+/g, '');
// L'aggiornamento finisce qui
var page = $('#loadMore').data('page');
var newPage = page + 1;
var ajaxurl = $('#loadMore').data('url');
if (eseguito) {
if ($(window).scrollTop() <= (($(document).height() - $(window).height())- $("footer").height())-200) {
eseguito = false;
} else {
return false;
}
}
if (!eseguito) {
//check
if ($(window).scrollTop() >= (($(document).height() - $(window).height())- $("footer").height())-200) {
eseguito = true;
/*ajax call*/
$.ajax({
url: ajaxurl,
type: 'post',
data: {
cat : cat, // Qui viene passata l'intera classe con l'ID categoria
page: page,
action: 'ajax_script_load_more_category'
},
error: function(response) {
console.log(response);
},
success: function(response) {
//check
if (response == 0) {
//check
if ($("#no-more").length == 0) {
$('#ajax-content').append('<div id="no-more" class="text-center"><h3>Non sono presenti altri articoli!</h3></div>');
}
$('#loadMore').hide();
} else {
$('#loadMore').data('page', newPage);
$('#ajax-content').append(response);
}
}
});
}
}
});
});
Mentre il codice da inserire sul functions.php è il seguente:
//INFINITY SCROLL
function script_load_more_category($args = array()) {
echo '<div id="ajax-primary" class="content-area">';
echo '<div id="ajax-content" class="content-area">';
ajax_script_load_more_category($args);
echo '</div>';
echo '<a href="#" id="loadMore" data-page="1" data-url="'.admin_url("admin-ajax.php").'" >Load More</a>';
echo '</div>';
}
add_shortcode('ajax_posts_category', 'script_load_more_category');
function ajax_script_load_more_category($args) {
//Init ajax
$ajax = false;
//Controlla la chiamata AJAX
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$ajax = true;
}
//Numero degli articoli da caricare
$num =3;
//Numero della pagina
$paged = $_POST['page'] + 1;
// L'aggiornamento parte qui
$cat = $_POST['cat'];
if(!$cat){
$categoria_corrente = get_queried_object();
$cat = $categoria_corrente->term_id;
}
// L'aggiornamento finisce qui
//Args
//$categoria_corrente = get_queried_object();
//$ID_categoria_corrente = $categoria_corrente->term_id;
//error_log($ID_categoria_corrente);
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'cat' => $cat, // Qui viene inserito l'ID categoria che filtra i risultati
'posts_per_page' =>$num,
'paged'=>$paged
);
//Query
$query = new WP_Query($args);
//Controllo
if ($query->have_posts()):
//loop articales
while ($query->have_posts()): $query->the_post();
//include articles template
include 'ajax-content.php';
endwhile;
else:
echo 0;
endif;
//Ripristina post
wp_reset_postdata();
//Controlla la chiamata AJAX
if($ajax) die();
}
add_action('wp_ajax_nopriv_ajax_script_load_more_category', 'ajax_script_load_more_category');
add_action('wp_ajax_ajax_script_load_more_category', 'ajax_script_load_more_category');
Conclusioni
Oggi abbiamo visto come creare uno scroll infinito e un bottone carica altro tramite delle chiamate AJAX permettendoci di migliorare e di molto l’esperienza dell’utente nel nostro sito.
Hai avuto problemi nella riproduzione del codice? Fammelo sapere nei commenti!
Un abbraccio,
Matteo.
Lascia un commento
Salve. é possibile farlo in DIVI theme?
Ciao, dipende, dici scrivendo codice o come funzione nativa del tema? 😉
Ciao Matteo,
grazie mille per questa guida molto chiare e utile.
Se volessi aggiungere il Load More per un nuovo Custom Post Type con nome “xyz”, dovrei modificare solo il post_type della WP_Query o serve altro?
Grazie 😉
Ciao Gabriele, esatto, basterebbe aggiornare il valore post_type 😉
Ciao,
grazie per gli snippet! Ho una domanda, se volessi scriverli in file al di fuori del functions.php?
Ciao Carla,
perché vorresti scriverli al di fuori del file functions.php?
Un saluto,
Matteo.
Ciao Matteo, mi piacerebbe richiamare il codice da un plugin custom e non dal tema
Ciao Carla,
dipende molto dalla struttura custom che sta seguendo il tuo plugin. Utilizzi il boilerplate di questo sito wppb.me?
Un saluto,
Matteo.
Sì, l’idea è quella di usare un plugin starter da cui richiamare le funzioni, evitando di chiamarle dal tema
Capito, penso che esistano già plugin del genere. Ti consiglio di utilizzare quelli se la realizzazione è troppo complessa, se invece vuoi proprio crearne uno ti consiglio di leggere la documentazione riguardo lo sviluppo di plugin su WordPress.org.
Un saluto,
Matteo.
Grazie mille, seguirò la guida!
Ciao Matteo grazie per questo code molto molto chiaro.
Volendolo inserire in una categoria come faccio a filtrare i risultati per categoria?
Ciao Marco,
basta inserire nell’$args del loop la categoria in questione che può essere ripresa direttamente con il seguente codice:
$categoria_corrente = get_queried_object();
$ID_categoria_corrente = $categoria_corrente->term_id;
All’interno dell’array della variabile $args dovrai poi inserire:
'cat' => $ID_categoria_corrente,
Un saluto,
Matteo.
Ciao Matteo,
ho fatto come mi hai detto ed effettivamente la query filtra i risultati per Id categoria.
L’unica cosa che funziona solo per i primi 3 che è il mio $num.
Dopo che comincia a caricare gli altri post è come se saltasse l’ID categoria dalla query e ne carica anche altri di altre categorie.
Il mio codice:
//Args
$categoria_corrente = get_queried_object();
$ID_categoria_corrente = $categoria_corrente->term_id;
$args = array(
‘post_type’ => ‘post’,
‘post_status’ => ‘publish’,
‘cat’ => $ID_categoria_corrente,
‘posts_per_page’ =>$num,
‘paged’=>$paged
);
//Query
$query = new WP_Query($args);
Ciao Marco,
non mi sembra di vedere niente di anomalo.
Stai eseguendo questo codice sulle pagine archivio di categoria, giusto?
Un saluto,
Matteo.
Si certo pagine di categoria, ma è come se salta la query dopo i primi 3 e carica tutti i post
Prova a scrivermi in chat e mandami il codice che stai utilizzando nella pagina di categoria utilizzando un programma come il seguente: https://pastebin.com/
Grazie!