WordPress: Beiträge via AJAX nachladen (inklusive Fallback)

Um auf einer Übersichtsseite weitere Beiträge zu erreichen, ist die Verwendung eines »Load More«-Buttons eine beliebte Methode. Hierbei werden via JavaScript (AJAX) weitere Beiträge unter den zuvor angezeigten Beiträgen geladen, ohne dass die gesamte Unterseite neu geladen werden muss. Wenn JavaScript deaktiviert ist oder nicht geladen werden kann, ist es sinnvoll, als Fallback die klassische Pagination zu verwenden.

AJAX in WordPress

WordPress ist bereits von Hause aus mit einer AJAX-Funktionalität ausgestattet, die sich in der WP-Core-Datei admin-ajax.php befindet und durch Action-Hooks auch für besucherseitige AJAX-Anfragen benutzt werden kann. Auf diese Funktionalität greifen wir zurück, um einen »Load more«-Button unter unseren Loop zu integrieren. Hierbei spielt es keine Rolle, ob es sich um den Standard-Loop von WordPress oder um einen Custom-Loop (wp_query) handelt. Für beide Varianten haben wir ein Code-Beispiel erstellt.

Standard-Loop für AJAX-»Load more« vorbereiten

Als Basis für die Nachladen-Funktion verwenden wir die Funktion paginate_links() von WordPress. Dadurch berücksichtigen wir direkt das spätere Fallback, sollte die AJAX-Funktion aufgrund von JavaScript-Problemen nicht greifen. Somit verfolgen wir hier das Prinzip von »Progressive Enhancement«.
An die Pagination übergeben wir nun drei data-Attribute, die wir später mithilfe von JavaScript auslesen:

<?php
// Standard-Loop
if ( have_posts() ) {
  while ( have_posts() ) { the_post();
    get_template_part('template-parts','teaser');
  }

  // Pagination
  if($wp_query->max_num_pages > 1) {
    if($wp_query->query_vars["paged"] == 0) {
      $current_page = 1;
    } else {
      $current_page = $wp_query->query_vars["paged"];
    }
    echo '<div class="pagination" data-query="'.htmlspecialchars(json_encode($wp_query->query_vars)).'" data-maxpages="'.htmlspecialchars(json_encode($wp_query->max_num_pages)).'" data-current="'.$current_page.'">'.paginate_links(array('total' => $wp_query->max_num_pages)).'</div>';
  }
}
?>

WP Query für AJAX-»Load more« vorbereiten

Der grundsätzliche Aufbau bei einem Custom-Loop bleibt identisch mit dem oben beschrieben Aufbau, jedoch müssen wir hier noch drei weitere Variablen erzeugen, um die Pagination mit den richtigen Informationen zu versorgen. Weitere Informationen dazu auch in unserem Artikel: WordPress: WP_Query mit Pagination.

<?php
// Custom Loop
$count = get_option('posts_per_page', 10);
$paged = get_query_var('paged') ? get_query_var('paged') : 1;
$offset = ($paged - 1) * $count;

$args = array(
  'post_type' => 'post',
  'posts_per_page' => $count,
  'paged' => $paged,
  'offset' => $offset,
);
$wp_query = new WP_Query( $args );
if ( $wp_query->have_posts() ) {
  while ( $wp_query->have_posts() ) { $wp_query->the_post();
    get_template_part('template-parts','teaser');
  }

  // Pagination
  if($wp_query->max_num_pages > 1) {
    if($wp_query->query_vars["paged"] == 0) {
      $current_page = 1;
    } else {
      $current_page = $wp_query->query_vars["paged"];
    }
    echo '<div class="pagination" data-query="'.htmlspecialchars(json_encode($wp_query->query_vars)).'" data-maxpages="'.htmlspecialchars(json_encode($wp_query->max_num_pages)).'" data-current="'.$current_page.'">'.paginate_links(array('total' => $wp_query->max_num_pages)).'</div>';
  }
}
wp_reset_postdata();

AJAX-Script integrieren und Variablen übergeben

Nachdem wir den Loop vorbereiten haben, erstellen wir eine JavaScript-Datei, die wir in unserem Beispiel loadmore.js nennen und in die anschließend unsere Nachladen-Funktion geschrieben wird.

Mit Hilfe von wp_localize_script() übergeben wir drei Variablen an unser Script, die wir später benötigen:

Wir verwenden diese Methode unter anderem dafür, um später die Button-Beschriftung mit Hilfe von Sprachdateien übersetzbar zu machen.

Folgenden Code schreiben wir nun in unsere functions.php oder in ein seitenspezifisches Plugin.

function kb_load_scripts() {
  wp_enqueue_script('jquery');

  wp_register_script( 'kb_load_more', get_stylesheet_directory_uri() . '/loadmore.js', array('jquery') );

  wp_localize_script('kb_load_more', 'kb_string', array(
    'ajaxurl' => admin_url('admin-ajax.php'),
    'buttontxt' => __('Load more','kb-theme'),
    'buttonload' => __('Loading ...','kb-theme'),
  ));

  wp_enqueue_script( 'kb_load_more' );
}
add_action( 'wp_enqueue_scripts', 'kb_load_scripts' );

Bitte beachtet, dass wir für unser Beispiel zusätzlich jQuery benötigen, welches aber in WordPress von Hause aus an Bord ist.
AJAX funktioniert grundsätzlich natürlich auch mit »purem« JS.

AJAX-Funktion in JavaScript schreiben

Als Erstes werden alle HTML-Elemente mit der Klasse .page-numbers mit Ausnahme von .next aus dem DOM entfernt und der Text des Links mit der CSS-Klasse .next mit der zuvor übergebenen Variabel buttontxt ersetzt. Dies wird der »Load more«-Button.

Via Klick auf den »Load more«-Button lesen wir nun die data-Attribute aus der Pagination aus, speichern sie in Variablen und übergeben sie an data. Zusätzlich vergeben wir den action-Name kb_load_more, mit dem wir später die AJAX-Handler aufrufen.

Bevor der AJAX-Call beginnt, ändern wir den Button-Text mit der zuvor übergeben Variable zum »Loading«-Text. Nach erfolgreicher Ausführung des Calls wird die Seitenzahl »hochgezählt«, die Inhalte oberhalb der Pagination ausgespielt und der Button-Text wieder zurückgeändert.

Dem DOM werden also alle Inhalte hinzugefügt, die sich eigentlich auf der nachkommenden Seite innerhalb der Pagination befinden würden.

Wenn die aktuelle Seitenzahl gleich der maximalen Seitenzahl ist, wird der Button gänzlich entfernt, da es keine Inhalte mehr zum Nachladen gibt und der Button somit überflüssig ist.

jQuery(function ($) {
  $('.pagination .page-numbers').not('.next').remove();
  $('.pagination .next').html(kb_string.buttontxt);

  $(document).on('click','.pagination .next',function(e) {
    e.preventDefault();
    var query = JSON.stringify($(this).closest('.pagination').data('query'));
    var maxpages = $(this).closest('.pagination').data('maxpages');
    var current = parseInt($(this).closest('.pagination').data('current'));

    var button = $(this),
      data = {
        'action': 'kb_load_more',
        'query': query,
        'page' : current,
      };

    $.ajax({
      type: 'POST',
      url: kb_string.ajaxurl,
      data: data,
      beforeSend: function(xhr) {
        button.text(kb_string.buttonload);
      },
      success: function(data) {
        current++;
        button.closest('.pagination').before(data);
        button.closest('.pagination').data('current',current);
        button.text(kb_string.buttontxt);
        if ( current == maxpages ) {
          button.remove();
        }
      },
    });
  });
});

Richtige Inhalte ausgeben mit dem AJAX-Handler

Zu guter Letzt müssen wir dem AJAX-Call noch mitteilen, welche Inhalte er aus der Datenbank laden soll und wie er sie ausspielen soll. Hierfür benötigen wir den AJAX-Handler, den wir in unsere functions.php oder in ein seitenspezifisches Plugin schreiben. Dieser enthält einen einfachen Loop. Die Argumente für den Loop kommen aus dem AJAX-Call. Da Handler und Funktion miteinander »verknüpft« sind, müssen die WordPress-Actions mit der im Call angegebenen Actions übereinstimmen:

function kb_load_more_handler(){
  $args = json_decode( stripslashes( $_POST['query'] ), true );
  $args['paged'] = $_POST['page'] + 1;
  $args['post_status'] = 'publish';

  query_posts( $args );

  if( have_posts() ) {
    while( have_posts() ) { the_post();
      get_template_part('template-parts','teaser');
    }
  }
  die;
}
add_action('wp_ajax_kb_load_more', 'kb_load_more_handler');
add_action('wp_ajax_nopriv_kb_load_more', 'kb_load_more_handler');

Geschrieben von Robert Menzel

Benutzerbild

Robert arbeitet als Frontend-Developer und Web-Designer bei kulturbanause. Zu seinen Aufgaben gehören die visuelle Gestaltung und die technische Umsetzung von Websites, eCommerce-Shops oder dessen Kombination. Besonders gerne übernimmt er die Entwicklung individueller und anspruchsvoller Websites mit umfangreichen ineinandergreifenden Funktionen, getreu dem Motto: »Der beste Lack bringt nichts, wenn die Maschine darunter nicht läuft.«

Feedback & Ergänzungen – 5 Kommentare

  1. Hans Hansen
    schrieb am 11.05.2022 um 16:36 Uhr:

    Moin, der lädt bei mir die gleichen Posts immer wieder, any idea?

    Antworten
    • Hans Hansen
      schrieb am 16.05.2022 um 08:31 Uhr:

      Habe die Funktion mit dem Offset entfernt dann gings.

      Antworten
  2. Steffen
    schrieb am 07.03.2022 um 20:13 Uhr:

    Moin, danke für das Tutorial! Eine Frage: Kann ich mit der Methode auch Posts per Klick auf einen Button in ein bestimmtes Div per Ajax reinladen? Also sodass das Div erst leer ist und dann per Ajax dynamisch gefüllt wird. Oder geht das nur wie in deinem Tutorial wenn man bereits einen Loop inkl. Paginierung hat?
    Danke im Voraus! :)

    Antworten
  3. Ferdal
    schrieb am 31.03.2021 um 10:01 Uhr:

    Vielen Dank für den inspirierenden Artikel. Ich habe auf meiner Website mehrere custom querries. Muss ich den Ajax-Handler für jeden querry seperat anpassen, da ihr im Artikel schreibt: „Da Handler und Funktion miteinander »verknüpft« sind, müssen die WordPress-Actions mit der im Call angegebenen Actions übereinstimmen“. Wenn ja, frage ich mich, wie der Ajax-Handler die unterschiedlichen custom-querries unterscheidet. Im Ajax-Handler-Code steht nur: query_posts( $args );
    Würde mich über eine Antwort und eure Rückmeldung hierzu sehr freuen.
    Liebe Grüße

    Antworten
    • Robert Menzel
      schrieb am 01.04.2021 um 17:14 Uhr:

      Hallo Ferdal,
      du musst den Ajax-Handler nicht für jeden Query anpassen.
      Durch die Angabe von data-query, data-maxpages, data-current übergibst du alle relevanten Daten an das Script, die benötigt werden um die richten Inhalte nachzuladen.

      Viele Grüße
      Robert

      Antworten

Kommentar zu dieser Seite

Wir freuen uns über Anregungen, Ergänzungen oder Hinweise zu Fehlern. Wir lesen jeden Eintrag, veröffentlichen aber nur, was den Inhalt sinnvoll ergänzt.

WordPress-Projekte mit kulturbanause

Wir wissen wovon wir reden. Wir setzen WordPress seit über 10 Jahren erfolgreich ein und realisieren maßgeschneiderte Websites auf Basis dieses großartigen CMS.

WordPress-Leistungsangebot →

Schulungen von kulturbanause

Wir bieten Seminare und Workshops zu den Themen Konzept, Design und Development. Immer up-to-date, praxisnah, kurzweilig und mit dem notwendigen Blick über den Tellerrand.

Übersicht Schulungsthemen →