Добавить действие только при публикации записи - не при обновлении
У меня есть действие, которое добавляет произвольное поле со значением при публикации записи. Проблема в том, что когда я обновляю запись, произвольное поле сбрасывается до значения по умолчанию.
Я уже пробовал использовать 'new_to_publish' вместо 'publish_post', но это не работает.
add_action('publish_post', 'add_custom_field_automatically');
function add_custom_field_automatically($post_ID) {
global $wpdb;
if(!wp_is_post_revision($post_ID)) {
update_post_meta($post_ID, 'votes_count', '0');
}
}
Всё еще не работает
add_action( 'transition_post_status', 'wpse120996_post_status_publish', 10, 3 );
function wpse120996_post_status_publish( $new_status, $old_status, $post_ID ) {
if ( $new_status == 'publish' && $old_status == 'pending' ) {
global $wpdb;
if(!wp_is_post_revision($post_ID)) {
update_post_meta($post_ID, 'votes_count', '0');
}
}}
Как я понимаю - каждый раз, когда статус меняется с "ожидающего" на "опубликовано", должно выполняться то, что находится внутри условия if. Но это не работает.
На моем сайте есть система рейтинга записей с произвольным полем 'votes_count', где хранятся голоса. Когда я делаю запрос votes_count от большего к меньшему, он не показывает записи без голосов, поэтому мне нужно заполнить их значением по умолчанию 0, чтобы включить их в запрос. Всё работает нормально, но когда я обновляю запись, голоса сбрасываются до 0... Записи публикуются пользователями со статусом "ожидающие", которые я проверяю и публикую.

Как отметил @milo в комментарии, проверка существования мета-поля записи — это самый простой способ достичь желаемого. Вот пример:
add_action('publish_post', 'wpse120996_add_custom_field_automatically');
function wpse120996_add_custom_field_automatically($post_id) {
global $wpdb;
$votes_count = get_post_meta($post_id, 'votes_count', true);
if( empty( $votes_count ) && ! wp_is_post_revision( $post_id ) ) {
update_post_meta($post_id, 'votes_count', '0');
}
}
→ При создании/публикации, но не при обновлениях
Я оставляю это, потому что это соответствует теме выполнения действий при публикации, а не при обновлении. Но переход auto-draft
→ publish
работает только при первой публикации записи и только если запись публикуется напрямую. Возможно, потребуется охватить больше случаев, например, draft
→ publish
или pending
→ publish
.
Можно попробовать так:
//специфично, потому что хук указывается в формате {$old_status}_to_{$new_status}
add_action( 'auto-draft_to_publish', 'wpse120996_specific_post_status_transition' );
function wpse120996_specific_post_status_transition() {
//ваш код
}
вместо использования new_to_publish
.
→ Подробнее смотрите в Post Status Transitions.
Или можно работать с общим хуком transition_post_status
следующим образом:
//универсально, потому что статусы указываются внутри функции, а не через хук
add_action( 'transition_post_status', 'wpse120996_generic_post_status_transition', 10, 3 );
function wpse120996_generic_post_status_transition( $new_status, $old_status, $post ) {
if ( $new_status == 'publish' && $old_status == 'auto-draft' ) {
//ваш код
}
}
Ещё один аккуратный способ выполнения действий при публикации или, точнее, при первом создании, а не при обновлениях — использовать подход, показанный ниже. Я выбрал хук save_post
, но это можно сделать и с помощью хука publish_post
.
add_action('save_post', 'wpse120996_on_creation_not_update');
function wpse120996_on_creation_not_update($post_id) {
//get_post( $post_id ) == null проверяет, есть ли запись в базе данных
if( get_post( $post_id ) == null ) {
//ваш код
}
}

Удивительно, но это работает. Возможно, я не настолько глуп, как думал. Спасибо вам обоим за помощь.
add_action('publish_post', 'add_custom_field_automatically');
function add_custom_field_automatically($post_ID) {
global $wpdb;
$meta_count = get_post_meta($post_ID, "votes_count", true);
if($meta_count == '') {
if(!wp_is_post_revision($post_ID)) {
update_post_meta($post_ID, 'votes_count', '0');
}
}
}
