Я только что закончил функцию для проекта, в котором используется комбинация настраиваемых типов сообщений, импорта данных и обновления существующих сообщений при удалении пользователя (или группы пользователей).
Однако есть одна проблема:
Скажем, у вас есть сообщение, которое в настоящее время опубликовано (то есть его «post_status» установлено на «опубликовать»), но когда вы обновляете сообщение через wp_update_post, его атрибут post_status устанавливается на «будущее».
Другими словами, всякий раз, когда вы программно обновляете публикацию, статус публикации устанавливается на «Запланировано» (в соответствии с пользовательским интерфейсом) и «Будущее» (в соответствии со столбцом базы данных).
Так что дает?
Статус публикации при обновлении
Вообще говоря, я не сторонник того, чтобы заставить что-то работать, выяснить, что это работает, и перейти к следующей задаче, если я точно не понимаю, почему это не сработало [как ожидалось] в первую очередь.
Это не означает, что нет случаев, когда ограничения вызывали это (по крайней мере, в рабочее время). Но если сейчас полночь, я исправляю ошибку, а потом я не совсем уверен, что понимаю, почему она, по-видимому, была сломана в первую очередь, я мог бы также остаться и выяснить это, верно?
Это похоже на предвзятость невозвратных издержек в версии программиста .
В любом случае, как указано выше, вот суть проблемы:
- Данная запись существует в WordPress.
- Когда пользователь удаляется, система проверяет, существует ли определенный контент в данном сообщении, и если да, то удаляет его.
- Затем сообщение обновляется с помощью функции WordPress API.
Все работает отлично, но есть проблема: всякий раз, когда сообщение программно обновляется, оно помечает статус сообщения как «будущий» в базе данных, в конечном итоге устанавливая элемент строки сообщения в представлении «Все сообщения» как «Запланировано».
Два решения
Есть два способа решить эту проблему:
- Запустите быстрый запрос непосредственно к базе данных, чтобы устранить проблему.
- Обновите аргументы сообщения, чтобы использовать правильное время по Гринвичу (я расскажу об этом подробнее чуть позже).
Если вы выберете первое решение, убедитесь, что вы используете функцию подготовки и убедитесь, что вы выполняете запрос после возврата функции обновления.
<?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) );
}
Если вы выберете второе решение, то явно обновите свойства объекта записи, прежде чем передавать его в функцию обновления.
<?php
$event_post->post_date_gmt = gmdate( 'Y-m-d H:i:s', $event_post->post_date_gmt );
wp_update_post( $event_post );
Я не говорю, что при работе над проектом нет места для любого из этих решений, но вопрос остается:
Почему WordPress помечает публикацию, запланированную на будущее, если запись перед прохождением процедуры обновления была настроена на публикацию?
И если вы не знакомы с остальными аргументами, которые передаются в WordPress при обновлении поста, потребуется некоторое время, чтобы отследить их.
Понимание проблемы
Чтобы избежать написания прямого запроса к базе данных, я предпочитаю второе решение, потому что оно чище (хотя и не делает его менее запутанным).
Чтобы выяснить, почему происходит такое поведение, вы можете обратиться к другому разработчику или отладить код. Учитывая, что я работал над этим поздно ночью, я выбрал последнее.
Запуск отладчика и трассировка кода через post.php.
Я не буду описывать все точки останова и контрольные точки, которые я установил, поэтому я постараюсь сделать это максимально кратким.
Во-первых, когда код проходит через функцию wp_update_post, он столкнется с этим блоком кода :
<?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';
}
}
}
Обратите внимание, что в условном выражении мы не работаем с вложением, а работаем со статусом публикации «опубликовать». Итак, мы найдем первое условное предложение внутри внешнего условного предложения (немного запутанно, не правда ли?).
Теперь есть переменная $post_status, сохраняющая значение публикации, но не назначенная какому-либо конкретному свойству текущего сообщения. Если вы продолжите отслеживать код, вы наткнетесь на следующую строку :
<?php
$post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, compact( array_keys( $postarr) ), $postarr );
Здесь вы увидите, что он работает с набором ключей массива, которые содержатся в переменной $postarr. Эта переменная используется ранее в коде (см. здесь, на Trac). И если вы внимательно присмотритесь, вы увидите, что сначала он проверяет, пусто ли свойство post_date_gmt или оно полностью обнулено.
А поскольку это не так, будет использоваться значение, которое мы указали в свойстве при первом вызове функции :
<?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'];
}
Ждать.
Зачем возвращаться к функции, когда код уже прошел это? Такова природа отладки. Иногда вы видите переменные и ничего о них не думаете только для того, чтобы увидеть, как они используются, устанавливаются, манипулируются, комбинируются или что-то еще в коде.
Такова реальность.
Но в любом случае из-за этого свойство будет поддерживать значение, которое мы указали перед вызовом функции обновления. Обычно это будет то же значение, что и при запуске функции, но могут быть случаи, когда вы хотите, скажем, удалить сообщение.
И это основание для использования wp_delete_post. Но у него есть свои предостережения, особенно в отношении пользовательских типов сообщений.
Это попадает в другой пост, хотя.