WordPress: Artikel mit Ablaufdatum

WordPress kann viel (außer am richtigen Datum in der neuen Version zu erscheinen), einige Dinge sind aber noch nicht ganz so ausgereift, wie man es gerne hätte. Eines dieser Problemchen ist, dass Artikel kein Verfall- oder Ablaufdatum haben können, was für den Gebrauch als Blogger vielleicht uninteressant ist, für solche, die WordPress allerdings als CMS einsetzen, wichtig sein kann. Man muss da schon die Spezialfelder bemühen, um Artikel mit Ablaufdatum zu erhalten. Damit geht es dann aber ganz gut. Und hier steht, wie!

Der Code

Das hier angeführte Codebeispiel ist mehr als ineffizient und sollte wenn überhaupt nur dann verwendet werden, wenn die Filterung erst nach der Datenbankabfrage erfolgen soll (ich wüsste nicht, wann das jemals der Fall sein könnte). Ich habe unten eine Aktualisierung geschrieben!

  • Erstelle ein neues Spezialfeld mit einer passenden Bezeichnung, zB: „Ablaufdatum“ oder – in meinem Fall – ablaufdatum (jjjj-mm-tt). Ich habe mich für diese Namensgebung entscheiden, weil ich damit gleich auch die Eingabeform angebe.
  • Als Wert gibt man in dieses Spezialfeld nun das Ablaufdatum im genannten Format an, also jjjj-mm-tt: 2008-03-10 für den 10. März 2008.
  • Das war’s von Nutzerseite.

Im Theme muss natürlich nun eine Abfrage her, die den Artikel ausblendet, wenn das angegebene Datum überschritten ist, daher:

Codebeispiel für Artikel mit Ablaufdatum

<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
  <?php $heute = strtotime(date("Y-m-d"));

  /* Heutiges Datum im Format Y-m-d abfragen */
  $ablaufdatum = strtotime(get_post_meta($post->ID, 'SPEZIALFELD', true));

  /* Ablaufdatum aus dem Spezialfeld "SPEZIALFELD"
     abfragen. Die Daten im Spezialfeld müssen unbedingt
     im Format Y-m-d gespeichert werden! */
  if (empty($ablaufdatum)) { $ablaufdatum = $heute + 1; };
  if ($ablaufdatum >= $heute) { ?>

    <a href="<?php the_permalink() ?>"><?php the_title(); ?></a>
  <?php }; ?>
<?php endwhile; endif; ?>

Anmerkungen

Dieser Code und diese Lösung entstanden aus der Not heraus, Artikel zeitlich begrenzt darzustellen, zB Ankündigungen, die am Tag des Ereignisses nicht mehr aktuell sind. Für Blogger wird diese Funktionalität nicht von Bedeutung sein, für solche, die WordPress allerdings als CMS einsetzen, kann das wichtig werden.

Zur Klärung: Der Code lässt den Artikel nicht verschwinden, sondern blendet ihn bei einer bestimmten Abfrage einfach nur aus. In Kategorie-, Stichwort- und datumsbasierten Auflistungen wird der „abgelaufene“ Artikel trotzdem noch auftauchen. (Ich habe das Problem insofern gelöst, als dass ich mit dem gleichen Code dem Artikel eine Zeile hinzufüge, die aussagt, dass die Informationen dieses Artikels bereits veraltet sind.)

Verbesserungen, Optimierungen, etc. sind immer in den Kommentaren willkommen.

Aktualisierter Code: pre_get_posts-Hook

Anstatt die Datenbank mit potentiell hunderten Abrufen bezüglich des Datums zu bombardieren und potentiell keinen einzigen Artikel mehr angezeigt zu bekommen, ist es deutlich eleganter, den Loop überhaupt nicht aufzurufen, sondern das Filtern der Beiträge bereits vor dem eigentlichen Datenbankabruf durchzuführen. Das geht mit dem pre_get_posts-Hook, in die functions.php oder ein Plugin kopiert, am besten. Hier der Code, angepasst an die oben genannten Bedingungen:

/**
 * Beiträge nach Ablaufdatum (Feld: ablaufdatum (jjjj-mm-tt)) filtern.
 */
function filter_old_entries( $query ) {
    $heute = date( 'Y-m-d');
    if( !is_admin() && $query->is_main_query() ) {
        $meta_query = $query->get('meta_query');
        $meta_query[] = array(
            'key' => 'ablaufdatum (jjjj-mm-tt)',
            'value' => $heute,
            'compare' => '>',
            'type' => 'DATE'
        );
        $query->set('meta_query', $meta_query);
    }
}
add_action( 'pre_get_posts', 'filter_old_entries' ); 

Was passiert hier?

Zuerst holen wir das aktuelle Datum im Format Y-m-d, also zB „2018-07-19“. In der nächsten Zeile schließen wir aus, dass wir uns im Backend befinden, vor allem aber wird sichergestellt, dass es sich bei der aktuellen Query um die Haupt-Query handelt.

Mittels $query->get('meta_query') holen wir uns die womöglich vorhandene Meta-Abfrage, um sie nicht zu überschreiben, und ergänzen sie mit dem nun folgenden Array um einen Datums-Vergleich: Das Feld „ablaufdatum (jjjj-mm-tt)“ muss, damit die Query Resultate liefert, größer sein als das heutige Datum ($heute). Um sicherzugehen, dass ein Datumsvergleich stattfindet, habe ich den Typ mit „DATE“ festgesetzt.

Damit ist sichergestellt, dass die zurückgelieferten Einträge auf jeden Fall nur heute oder in der Zukunft liegen und ich muss im Ausgabeteil (zB im Template) nicht auf Fehlerbehandlungsroutinen udgl. verzichten.