WordPress und Ajax

Wie angekündigt, gibt es hier meinen kleinen Sammelbeitrag zu WordPress und Ajax. Im Beispiel werden immer die Standard-Beiträge von WordPress ausgegeben. Für die Ausgabe wird immer WP_Query verwendet, sodass man die Schnipsel für jeden Beitragstyp verwenden kann. Erklärungen dazu findest du als Kommentar in den Schnipseln.

Objektorientiert

Hier die objektorientiere Variante. Im Beispiel werden die scripte sowohl im wp-admin als auch im Front-End ausgegeben. Bitte darauf achten und die jeweilige Einbindung entfernen, die nicht benötigt wird.

Beide Beispiel sind möglichst objektorientiert, auch wenn das mit JS noch nicht ganz so gut geht. Finde es persönlich aber übersichtlicher. Kannst du machen, wie du magst. Die Funktionen funktionieren auch außerhalb der Klasse. Einfach kopieren, die Variablen anpassen und fertig.

Am besten du kopierst den Code und fügst ihn in deinen Code-Editor ein. Hier ist er ein wenig unübersichtlich auch das Highlighting ist etwas verwirrend (aber schick).

PHP

<?php
namespace Custom;
use \WP_Query as WP_Query;
new Posts;

class Posts
{
  // wird für übersetzungen benötigt
  public $text_domain = 'textdomain';
  
  public function __construct() 
  {
    // frontend enqueue
    add_action('wp_enqueue_scripts', [ $this, 'enqueue' ] );

    // admin enqueue
    add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] );

    // die aktion an sich, hier wird sie ausgelöst,
    // wenn der benutzer bzw. besucher nicht angemeldet ist
    add_action( 'wp_ajax_my_posts', [ $this, 'get_posts' ] );

    // die aktion "my_posts" an sich, hier wird sie ausgelöst,
    // wenn der besucher bzw. benutzer angemeldet ist
    add_action( 'wp_ajax_nopriv_my_posts', [ $this, 'get_posts' ] );
  }

  public function enqueue()
  {
    $general = [];
    $js = [];

    // mit dieser id wird der enqueue definiert
    // er lässt sich mit dieser id auch wieder deregistrieren
    $general['id'] = 'ajax-posts';
    
    // in diesem object werden die js vars gespeichert
    $js['object'] = 'ajax_posts';

    // die datei die eingebunden werden soll
    // hier für ein plugin
    $js['file'] = plugins_url( '/js/ajax-posts.js', __FILE__ );

    // hier für ein theme
    $js['file'] = get_stylesheet_directory_uri() . '/js/ajax-posts.js';

    // scripte die verwendet werden sollen
    $js['use'] = [ 'jquery' ];

    // gibt an, dass das script im footer geladen werden soll
    $js['footer'] = true;

    // variablen die via js abrufbar gemacht werden sollen
    $js['vars'] = [
      // hierhin werden die requests weitergeleitet
      // wird für den ajax request benötigt
      'ajax_url' => admin_url( 'admin-ajax.php' ),
      // andere dinge, hier ein test den wir später in die browser konsole packen
      'test' => 'Das ist für die Browser-Konsole',
    ];
    
    wp_enqueue_script($general['id'], $js['file'], $js['use'], $js['footer']);
    wp_localize_script( $general['id'], $js['object'], $js['vars']);
  }

  // hier wird die ausgabe der beiträge definiert
  // is_admin() gibt hier immer true zurück, auch im frontend!
  public function get_posts()
  { 
    $args = [];
    $text_domain = $this->text_domain;

    $posts_per_page = get_option('posts_per_page');

    // wenn ppp via request ankommen, dann sollen sie verwendet werden
    // sofern es ein integer ist
    if( isset($_REQUEST['ppp']) && is_int($_REQUEST['ppp']) ) {
      $posts_per_page = esc_html($_REQUEST['ppp']);
    }

    $args['post_type'] = 'post';
    $args['posts_per_page'] = $posts_per_page;

    // hier können beliebig viele argumente hinzugefügt werden
    
    $response = __x(
      'Keine Beiträge gefunden', 
      'Wird ausgegeben, wenn keine Beiträge gefunden wurden', 
      $text_domain
    );

    $query = new WP_Query($args);

    // die anzahl der gefundenen beiträge
    $posts_found = $query->found_posts;

    if( $query->have_posts() ) {

      // die überschrift, die vor den beiträgen ausgegeben wird
      $response = sprintf(
        '<h3>%s</h3>',
        __x( 'Beiträge:', 'Überschrift für die Beitragsausgabe', $text_domain )
      );
      
      while( $query->have_posts() ): $query->the_post();

      // kann auch inkludiert werden, oder sonst etwas... 
      // wie sonst eben auch
      $response .= sprintf( 
        '<a href="%1$s" title="%2$s" target="_blank">%2$s</a><br>',
        esc_html(get_the_permalink()),
        esc_html(get_the_title())
      );
      
      endwhile; wp_reset_postdata();

      // die anzahl der beiträge wird direkt unterhalb dargestellt
      $response .= sprintf(
        __('Es wurden insgesamt %s Beiträge gefunden', $text_domain),
        $posts_found
      );
    }

    // die ausgabe
    echo $response;

    wp_die();
  }
}Code-Sprache: HTML, XML (xml)

JS bzw. jQuery

(function($) {

  $(function() {
    new MyPosts;
  });

  class MyPosts {
    constructor() {
      var self = this;
      
      // hier die entsprechende css class oder id eingeben
      // dient nur als beispiel für die js class
      self.container = '#posts';

      // hier die ausgabe der testvariable in der konsole
      console.log(ajax_posts.test);

      self.get_posts();
    }

    get_posts() {
      var self = this;

      // für ein formular
      // var ajax_data = $('#formular').serialize();
      
      // alternative für ein formular (nützlich bei dateien)
      // var ajax_data = $('#formular').serializeArray();

      // für unser beispiel per hand, wird nicht benötigt, wenn
      // die dinge bspw. via inputs weitergegeben werden
      var ajax_data = {};

      // unsere aktion
      // kann via formular auch in einem hidden input gespeichert werden
      // bspw. <input type="hidden" name="action" value="my_posts">
      ajax_data['action'] = 'my_posts';

      // unsere anzahl der beiträge
      ajax_data['ppp'] = 10;

      // unser request
      self.ajax_request(ajax_data).done(function(response) {

        // hier wird die rückmeldung bei #posts ausgegeben
        // wird in unserem beispiel im constructor festgelegt
        $(self.container).html(response);
      });      
    } 

    // unser request, damit wir ihn nicht jedes mal neutippen müssen
    ajax_request(data) {
      return $.ajax({
        // unser object und die url für den request
        url : ajax_posts.ajax_url,
        data : data,
      });
    } 
  }

})(jQuery)Code-Sprache: JavaScript (javascript)

Prozedural

PHP

// frontend enqueue
add_action('wp_enqueue_scripts', 'my_enqueue' );

// admin enqueue
add_action( 'admin_enqueue_scripts', 'my_enqueue' );

function my_enqueue() {
  $general = [];
  $js = [];

  // mit dieser id wird der enqueue definiert
  // er lässt sich mit dieser id auch wieder deregistrieren
  $general['id'] = 'ajax-posts';
  
  // in diesem object werden die js vars gespeichert
  $js['object'] = 'ajax_posts';

  // die datei die eingebunden werden soll
  // hier für ein plugin
  $js['file'] = plugins_url( '/js/ajax-posts.js', __FILE__ );

  // hier für ein theme
  $js['file'] = get_stylesheet_directory_uri() . '/js/ajax-posts.js';

  // scripte die verwendet werden sollen
  $js['use'] = [ 'jquery' ];

  // gibt an, dass das script im footer geladen werden soll
  $js['footer'] = true;

  // variablen die via js abrufbar gemacht werden sollen
  $js['vars'] = [
    // hierhin werden die requests weitergeleitet
    // wird für den ajax request benötigt
    'ajax_url' => admin_url( 'admin-ajax.php' ),
    // andere dinge, hier ein test den wir später in die browser konsole packen
    'test' => 'Das ist für die Browser-Konsole',
  ];
  
  wp_enqueue_script($general['id'], $js['file'], $js['use'], $js['footer']);
  wp_localize_script( $general['id'], $js['object'], $js['vars']);
}

// die aktion an sich, hier wird sie ausgelöst,
// wenn der benutzer bzw. besucher nicht angemeldet ist
add_action( 'wp_ajax_my_posts', 'my_get_posts' );

// die aktion "my_posts" an sich, hier wird sie ausgelöst,
// wenn der besucher bzw. benutzer angemeldet ist
add_action( 'wp_ajax_nopriv_my_posts', 'my_get_posts' );

// hier wird die ausgabe der beiträge definiert
// is_admin() gibt hier immer true zurück, auch im frontend!
function my_get_posts() { 
  $args = [];
  $text_domain = 'textdomain';

  $posts_per_page = get_option('posts_per_page');

  // wenn ppp via request ankommen, dann sollen sie verwendet werden
  // sofern es ein integer ist
  if( isset($_REQUEST['ppp']) && is_int($_REQUEST['ppp']) ) {
    $posts_per_page = esc_html($_REQUEST['ppp']);
  }

  $args['post_type'] = 'post';
  $args['posts_per_page'] = $posts_per_page;

  // hier können beliebig viele argumente hinzugefügt werden
  
  $response = __x(
    'Keine Beiträge gefunden', 
    'Wird ausgegeben, wenn keine Beiträge gefunden wurden', 
    $text_domain
  );

  $query = new WP_Query($args);

  // die anzahl der gefundenen beiträge
  $posts_found = $query->found_posts;

  if( $query->have_posts() ) {

    // die überschrift, die vor den beiträgen ausgegeben wird
    $response = sprintf(
      '<h3>%s</h3>',
      __x( 'Beiträge:', 'Überschrift für die Beitragsausgabe', $text_domain )
    );
    
    while( $query->have_posts() ): $query->the_post();

    // kann auch inkludiert werden, oder sonst etwas... 
    // wie sonst eben auch
    $response .= sprintf( 
      '<a href="%1$s" title="%2$s" target="_blank">%2$s</a><br>',
      esc_html(get_the_permalink()),
      esc_html(get_the_title())
    );
    
    endwhile; wp_reset_postdata();

    // die anzahl der beiträge wird direkt unterhalb dargestellt
    $response .= sprintf(
      __('Es wurden insgesamt %s Beiträge gefunden', $text_domain),
      $posts_found
    );
  }

  // die ausgabe
  echo $response;

  wp_die();
}Code-Sprache: PHP (php)

JS

(function($) {

  $(my_get_posts);

  function my_get_posts() {  
    // hier die entsprechende css class oder id eingeben
    // dient nur als beispiel für die js class
    var container = '#posts';

    // für ein formular
    // var ajax_data = $('#formular').serialize();
    
    // alternative für ein formular (nützlich bei dateien)
    // var ajax_data = $('#formular').serializeArray();

    // für unser beispiel per hand, wird nicht benötigt, wenn
    // die dinge bspw. via inputs weitergegeben werden
    var ajax_data = {};

    // unsere aktion
    // kann via formular auch in einem hidden input gespeichert werden
    // bspw. <input type="hidden" name="action" value="my_posts">
    ajax_data['action'] = 'my_posts';

    // unsere anzahl der beiträge
    ajax_data['ppp'] = 10;

    // unser request
    my_ajax_request(ajax_data).done(function(response) {

      // hier wird die rückmeldung bei #posts ausgegeben
      // wird in unserem beispiel im constructor festgelegt
      $(container).html(response);
    });    
  }

  my_ajax_request(data) {
    return $.ajax({
      // unser object und die url für den request
      url : ajax_posts.ajax_url,
      data : data,
    });
  } 

})(jQuery)Code-Sprache: JavaScript (javascript)

Die prozedurale Variante, werde ich dann wahrscheinlich im Urlaub schreiben. Denke bitte daran, dass die Rückmeldung via html auch mit einem include() funktioniert. So sparst du dir die unübersichtlichen HTML-Zeilen in deinem PHP-Code. Falls du dich fragst, warum der WP_Query ohne Slash möglich war, liegt es am use ganz oben in der Datei. Wird das nicht gemacht, musst du natürlich \WP_Query schreiben. Falls etwas nicht funktioniert, bitte kommentieren.

Nützliche Links

  1. Ajax in Plugins (WordPress Codex)
  2. Beginning PHP