Maintenir un statut de publication lors de la mise à jour d’une publication WordPress
Je viens de terminer une fonctionnalité pour un projet qui utilise une combinaison de types de publication personnalisés, d’importations de données et de mise à jour des publications existantes lors de la suppression d’un utilisateur (ou d’un ensemble d’utilisateurs).
Il y a cependant un problème :
Disons que vous avez un message qui est actuellement publié (c’est-à-dire que ‘post_status’ est défini sur ‘publish’) mais, lorsque vous mettez à jour le message via wp_update_post, son attribut post_status est défini sur ‘future’.
En d’autres termes, chaque fois que vous mettez à jour une publication par programme, le statut de la publication est défini sur "Planifié" (selon l’interface utilisateur) et "futur" (selon la colonne de la base de données).
Alors qu’est-ce qui donne ?
Statut de publication lors de la mise à jour
D’une manière générale, je ne suis pas fan de faire fonctionner quelque chose, de découvrir que c’est le cas et de passer à la tâche suivante à moins que je ne comprenne exactement pourquoi cela n’a pas fonctionné [comme prévu] en premier lieu.
Cela ne veut pas dire qu’il n’y a pas de moments où des contraintes ont provoqué cela (au moins pendant les heures de travail). Mais s’il est minuit, je corrige un bug, et je ne suis pas tout à fait sûr de comprendre pourquoi il a apparemment été cassé en premier lieu, autant rester éveillé et comprendre, n’est-ce pas ?
C’est comme la version du programmeur du biais de coût irrécupérable.
Quoi qu’il en soit, comme indiqué ci-dessus, voici l’essentiel du problème:
- Un article donné existe dans WordPress.
- Lorsqu’un utilisateur est supprimé, le système vérifie si un certain contenu existe dans une publication donnée et, si c’est le cas, le supprime.
- La publication est ensuite mise à jour à l’aide d’une fonction API WordPress.
Tout fonctionne très bien sauf qu’il y a un problème : chaque fois que la publication est mise à jour par programme, elle marque le statut de la publication comme "futur" dans la base de données, définissant finalement l’élément de campagne de la publication dans la vue Toutes les publications comme "Planifié".
Deux solutions
Il existe deux façons de résoudre ce problème :
- Exécutez une requête rapide directement sur la base de données pour résoudre le problème.
- Mettez à jour les arguments de la publication pour utiliser l’heure appropriée en GMT (je couvrirai cela plus en détail dans un instant).
Si vous optez pour la première solution, assurez-vous d’utiliser la fonction prepare et assurez-vous d’exécuter la requête après le retour de la fonction update.
<?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) );
}
Si vous optez pour la seconde solution, mettez alors explicitement à jour les propriétés de l’objet post avant de le passer à la fonction update.
<?php
$event_post->post_date_gmt = gmdate( 'Y-m-d H:i:s', $event_post->post_date_gmt );
wp_update_post( $event_post );
Je ne suis pas du genre à dire qu’il n’y a pas de place pour l’une ou l’autre de ces solutions lorsque vous travaillez sur un projet, mais la question demeure :
Pourquoi WordPress marque-t-il une publication prévue pour le futur alors que la publication, avant de passer par la procédure de mise à jour, était configurée pour être publiée ?
Et si vous n’êtes pas familier avec le reste des arguments qui sont transmis à WordPress lors de la mise à jour d’un article, il faudra un certain temps pour le retrouver.
Comprendre le problème
Afin d’éviter d’écrire une requête directe à la base de données, j’opte pour la deuxième solution car elle est plus propre (bien que cela ne la rende pas moins déroutante).
Pour comprendre pourquoi ce comportement se produit, vous pouvez demander à un autre développeur ou déboguer le code. Étant donné que je travaillais dessus tard dans la nuit, j’ai opté pour ce dernier.
Exécution du débogueur et du code de traçage via post.php.
Je ne vais pas parler de tous les points d’arrêt et de toutes les montres que j’ai définis, je vais donc essayer de le rendre aussi concis que possible.
Tout d’abord, lorsque le code passe par la fonction wp_update_post, il rencontre ce bloc de code :
<?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';
}
}
}
Notez que dans le conditionnel, nous ne travaillons pas avec une pièce jointe et nous travaillons avec un statut de publication de "publier". Nous allons donc frapper le premier conditionnel dans le conditionnel externe (un peu déroutant, n’est-ce pas ?).
Maintenant, il y a une variable, $ post_status, conservant une valeur de publication mais elle n’est affectée à aucune propriété particulière du message actuel. Si vous continuez à tracer le code, vous tomberez sur la ligne suivante :
<?php
$post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, compact( array_keys( $postarr) ), $postarr );
Ici, vous verrez qu’il fonctionne avec un ensemble de clés de tableau contenues dans la variable $postarr. Cette variable est utilisée plus tôt dans le code (voir ici sur Trac). Et si vous regardez attentivement, vous verrez qu’il vérifie d’abord si la propriété post_date_gmt est vide ou si tout est mis à zéro.
Et puisque ce n’est pas le cas, il utilisera la valeur que nous avons spécifiée sur la propriété lorsque nous avons initialement appelé la fonction :
<?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'];
}
Attendre.
Pourquoi remonter dans la fonction alors que le code a déjà dépassé cela? C’est la nature du débogage. Parfois, vous voyez des variables et ne pensez à rien d’elles uniquement pour voir qu’elles sont utilisées, définies, manipulées, combinées ou quoi que ce soit d’autre plus tard dans le code.
C’est la réalité.
Mais de toute façon, à cause de cela, la propriété conservera la valeur que nous avons fournie avant d’appeler la fonction de mise à jour. Habituellement, ce sera la même valeur que lorsque la fonction a démarré, mais il peut arriver que vous souhaitiez, par exemple, supprimer un message.
Et c’est une raison pour utiliser wp_delete_post. Mais il a ses mises en garde, en particulier autour des types de publication personnalisés.
Cela entre dans un autre poste, cependant.