Beibehalten eines Beitragsstatus beim Aktualisieren eines WordPress-Beitrags
Ich habe gerade eine Funktion für ein Projekt fertiggestellt, das eine Kombination aus benutzerdefinierten Beitragstypen, Datenimporten und der Aktualisierung vorhandener Beiträge beim Löschen eines Benutzers (oder einer Gruppe von Benutzern) verwendet.
Es gibt jedoch ein Problem:
Angenommen, Sie haben einen Beitrag, der derzeit veröffentlicht ist (d. h. sein „post_status“ ist auf „veröffentlichen“ gesetzt), aber wenn Sie den Beitrag über wp_update_post aktualisieren, ist sein post_status-Attribut auf „future“ gesetzt.
Mit anderen Worten, immer wenn Sie einen Beitrag programmgesteuert aktualisieren, wird der Status des Beitrags auf „Geplant“ (gemäß der Benutzeroberfläche) und „Zukunft“ (gemäß der Datenbankspalte) gesetzt.
Also was gibt?
Post-Status beim Aktualisieren
Im Allgemeinen bin ich kein Fan davon, etwas zum Laufen zu bringen, herauszufinden, dass es funktioniert, und mit der nächsten Aufgabe fortzufahren, es sei denn, ich verstehe genau, warum es überhaupt nicht [wie erwartet] funktioniert hat.
Das soll nicht heißen, dass es keine Zeiten gibt, in denen Einschränkungen dazu geführt haben (zumindest während der Arbeitszeit). Aber wenn es Mitternacht ist, ich einen Fehler behebe, und dann bin ich mir nicht ganz sicher, warum ich überhaupt verstehe, warum es anscheinend überhaupt kaputt war, könnte ich genauso gut aufbleiben und es herausfinden, richtig?
Es ist wie die Programmierer-Version von Sunk-Cost-Bias.
Wie auch immer, wie oben beschrieben, hier ist der Kern des Problems:
- Ein bestimmter Beitrag existiert in WordPress.
- Wenn ein Benutzer gelöscht wird, prüft das System, ob bestimmte Inhalte in einem bestimmten Beitrag vorhanden sind, und entfernt sie gegebenenfalls.
- Der Beitrag wird dann mithilfe einer WordPress-API-Funktion aktualisiert.
Alles funktioniert hervorragend, außer es gibt ein Problem: Immer wenn der Beitrag programmgesteuert aktualisiert wird, wird der Status des Beitrags in der Datenbank als „zukünftig“ markiert, wodurch die Position des Beitrags in der Ansicht „ Alle Beiträge “ schließlich als „Geplant“ festgelegt wird.
Zwei Lösungen
Es gibt zwei Möglichkeiten, dieses Problem zu beheben:
- Führen Sie eine schnelle Abfrage direkt in der Datenbank aus, um das Problem zu beheben.
- Aktualisieren Sie die Argumente des Beitrags, um die richtige Zeit in GMT zu verwenden (ich werde gleich darauf näher eingehen).
Wenn Sie sich für die erste Lösung entscheiden, stellen Sie sicher, dass Sie die Vorbereitungsfunktion verwenden, und stellen Sie sicher, dass Sie die Abfrage ausführen, nachdem die Aktualisierungsfunktion zurückgegeben wurde.
<?php
// First, update the post using the available WordPress API.
wp_update_post( $post );
/**
* If the post status attribute of the post that was just updated
* maintains the 'publish' post setatus, then manually update the
* database column.
*/
if ('publish' === $post->post_status) {
global $wpdb;
$wpdb->query(
$wpdb->prepare(
"
UPDATE $wpdb->posts
SET post_status = '%s'
WHERE ID = %d
",
'publish',
$post->ID) );
}
Wenn Sie sich für die zweite Lösung entscheiden, aktualisieren Sie explizit die Eigenschaften des Post-Objekts, bevor Sie es an die Update-Funktion übergeben .
<?php
$event_post->post_date_gmt = gmdate( 'Y-m-d H:i:s', $event_post->post_date_gmt );
wp_update_post( $event_post );
Ich bin niemand, der sagt, dass es keinen Platz für eine dieser Lösungen gibt, wenn man an einem Projekt arbeitet, aber die Frage bleibt:
Warum markiert WordPress einen Beitrag für die Zukunft geplant, wenn der Beitrag vor dem Update-Vorgang veröffentlicht werden sollte?
Und wenn Sie mit den restlichen Argumenten, die beim Aktualisieren eines Beitrags an WordPress übergeben werden, nicht vertraut sind, wird es einige Zeit dauern, sie aufzuspüren.
Verständnis des Problems
Um das Schreiben einer direkten Datenbankabfrage zu vermeiden, entscheide ich mich für die zweite Lösung, weil sie sauberer ist (obwohl sie dadurch nicht weniger verwirrend wird).
Um herauszufinden, warum dieses Verhalten auftritt, können Sie einen anderen Entwickler fragen oder den Code debuggen. Da ich bis spät in die Nacht daran gearbeitet habe, habe ich mich für Letzteres entschieden.
Ausführen des Debuggers und Ablaufverfolgungscodes über post.php.
Ich werde nicht alle Breakpoints und Watches, die ich setze, durchsprechen, also werde ich versuchen, dies so kurz wie möglich zu machen.
Erstens, wenn der Code die Funktion wp_update_post durchläuft, wird er auf diesen Codeblock stoßen :
<?php
if ('attachment' !== $post_type) {
if ('publish' == $post_status) {
$now = gmdate('Y-m-d H:i:59');
if (mysql2date('U', $post_date_gmt, false) > mysql2date('U', $now, false)) {
$post_status = 'future';
}
} elseif ('future' == $post_status) {
$now = gmdate('Y-m-d H:i:59');
if (mysql2date('U', $post_date_gmt, false) <= mysql2date('U', $now, false)) {
$post_status = 'publish';
}
}
}
Beachten Sie, dass wir innerhalb der Bedingung nicht mit einem Anhang arbeiten und mit dem Post-Status „veröffentlichen“. Also treffen wir die erste Bedingung innerhalb der äußeren Bedingung (ein bisschen verwirrend, nicht wahr?).
Jetzt gibt es eine Variable, $post_status, die einen Wert von publish beibehält, aber keiner bestimmten Eigenschaft des aktuellen Beitrags zugewiesen ist. Wenn Sie den Code weiter verfolgen, werden Sie auf die nächste Zeile stoßen :
<?php
$post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, compact( array_keys( $postarr) ), $postarr );
Hier sehen Sie, dass es mit einer Reihe von Array-Schlüsseln arbeitet, die in der Variablen $postarr enthalten sind. Diese Variable wird früher im Code verwendet (siehe hier auf Trac). Und wenn Sie genau hinsehen, werden Sie feststellen, dass zuerst überprüft wird, ob die Eigenschaft post_date_gmt leer oder auf Null gesetzt ist.
Und da dies nicht der Fall ist, wird der Wert verwendet, den wir für die Eigenschaft angegeben haben, als wir die Funktion ursprünglich aufgerufen haben :
<?php
if (empty( $postarr['post_date_gmt']) || '0000-00-00 00:00:00' == $postarr['post_date_gmt']) {
if (! in_array( $post_status, array( 'draft', 'pending', 'auto-draft') )) {
$post_date_gmt = get_gmt_from_date( $post_date );
} else {
$post_date_gmt = '0000-00-00 00:00:00';
}
} else {
$post_date_gmt = $postarr['post_date_gmt'];
}
Warte ab.
Warum zurück in die Funktion gehen, wenn der Code bereits daran vorbei gelaufen ist? Das ist die Natur des Debuggens. Manchmal sehen Sie Variablen und denken sich nichts dabei, nur um später im Code zu sehen, dass sie verwendet, gesetzt, manipuliert, kombiniert oder was auch immer sonst noch wird.
Das ist die Realität.
Aus diesem Grund behält die Eigenschaft jedoch den Wert bei, den wir vor dem Aufruf der Update-Funktion angegeben haben. Normalerweise ist dies derselbe Wert wie beim Start der Funktion, aber es kann vorkommen, dass Sie beispielsweise einen Beitrag löschen möchten.
Und das ist ein Grund für die Verwendung von wp_delete_post. Aber es hat auch seine Vorbehalte, besonders bei benutzerdefinierten Beitragstypen.
Das kommt aber in einen anderen Beitrag.