WordPress как на ладони
Мощный и не дорогой хостинг от Fornex.com Хостинг, VPS/VDS и отдельные сервера только на SSD дисках. 7 дней бесплатного тестирования.

save_post хук-событие . WP 1.5.2

Событие срабатывающее всякий раз, когда запись (пост, страница) создается или обновляется, в том числе при публикации через импорт, xmlrpc или по email.

Данные записи передаются во втором параметре $post, но их также, как правило, можно получить через $_POST, $_GET или глобальную переменную global $post_data. Когда и что используется, зависит от того, как запись редактируется. Например, "быстрое редактирование" (quick edits) использует $_POST.

Хук срабатывает в самом конце, после очистки кэша и прочих действий.

С версии 3.7 появился точно такой же хук save_post_(post_type). Где вместо post_type нужно указать название типа записи и событие будет срабатывать только при сохранении/добавлении записи этого типа. Выглядит хук так:

do_action( "save_post_{$post->post_type}", $post_ID, $post, $update );

save_post - это копия хука wp_insert_post.

Хук edit_post - такой же как и save_post, но срабатывает только при обновлении записи.

Хук срабатывает после того, как был сброшен объектный кэш поста. Поэтому если изменяются какие-то данные поста на этом хуке, то кэш поста нужно сбросить еще раз

// очистим кэш поста
clean_post_cache( $post_ID );

Или нужно использовать хук wp_insert_post_data или wp_insert_attachment_data. Только эти хуки срабатывают до сброса кэша, но они не будут работать при вызове функции wp_publish_post().

Внимание! Зацикливание

В хуке save_post нужно аккуратно использовать функцию wp_update_post(). Потому что она повторно взывает этот хук и так код попадет в бесконечный цикл... Как этого избежать смотрите ниже в примере #3. Также об этом написано в описании функции wp_update_post().

Использование

add_action( 'save_post', 'action_function_name_85245', 10, 3 );
function action_function_name_85245( $post_ID, $post, $update ) {
	// Действие...
}
$post_ID(строка)
ID записи, которая обновляется.
$post(объект)
Объект записи, которая обновляется. Объект такой же как обычно в глобальной переменной $post.
$update(логический)
true — это обновление записи.
false — это добавление новой записи.

Примеры

#1 Отправка email при обновлении записи

Этот демонстративный пример, показывает как, всякий раз когда запись обновляется отправлять письмо администратору сайта с сообщением об обновлении:

add_action( 'save_post', 'my_project_updated_send_email' );
function my_project_updated_send_email( $post_id ) {

	// Если это ревизия, то не отправляем письмо
	if ( wp_is_post_revision( $post_id ) || get_post($post_id)->post_status != 'publish' )
		return;

	$post_title = get_the_title( $post_id );
	$post_url = get_permalink( $post_id );
	$subject = 'Запись была обновлена';

	$message = "На вашем сайте следующая запись была обновлена:\n\n";
	$message .= $post_title . ": " . $post_url;

	// Отправляем письмо.
	wp_mail( get_option('admin_email'), $subject, $message );
}

#2 Произвольный тип записи "book"

Предположим у вас есть тип поста book и вам нужно добавить к нему информацию об авторе, издателе и о печатной копии. Этот код показывает как можно сохранить эти данные в метаданные записи:

/**
 * Сохраняем метаданные записи при сохранении поста.
 */
add_action( 'save_post', 'save_book_meta' );
function save_book_meta( $post_id ) {
	// слаг лучше указать единожды и использовать во всех кодах 
	// связанных с типом записи, как это принято в классах
	$slug = 'book';

	// Проверяем тип записи, если не boo то выходим.
	if ( $slug != $_POST['post_type'] )
		return;

	// Обновляем метаданные записи.

	if ( isset( $_REQUEST['book_author'] ) ) {
		update_post_meta( $post_id, 'book_author', sanitize_text_field( $_REQUEST['book_author'] ) );
	}

	if ( isset( $_REQUEST['publisher'] ) ) {
		update_post_meta( $post_id, 'publisher', sanitize_text_field( $_REQUEST['publisher'] ) );
	}

	// inprint - это чекбокс.
	if ( isset( $_REQUEST['inprint'] ) ) {
		update_post_meta( $post_id, 'inprint', TRUE );
	} else {
		update_post_meta( $post_id, 'inprint', FALSE );
	}
}

В этом примере, проверку if ( $slug != $_POST['post_type'] ), можно заменить: вместо события save_post, можно использовать save_post_book.

#3 Как избежать зацикливания

Если вы вызываете функцию wp_update_post() внутри события save_post, то вы наткнетесь на зацикливание, потому что wp_update_post() вызывает save_post. Чтобы этого избежать, удалите добавленный хук, перед тем как вызывать wp_update_post(), а затем добавьте его снова:

// Эта функция делает все записи в дефолтной категории частными
add_action( 'save_post', 'set_private_categories' );
function set_private_categories( $post_id ){
	// Получим реальный ID поста, если это ревизия
	if ( $parent_id = wp_is_post_revision( $post_id ) ) 
		$post_id = $parent_id;

	// Получим ID категории по умолчанию из опций
	$defaultcat = get_option( 'default_category' );

	// Проверим находится ли пост в категории по умолчанию
	if ( in_category( $defaultcat, $post_id ) ) {
		// Удаляем хук, чтобы не было зацикливания
		remove_action( 'save_post', 'set_private_categories' );

		// обновляем запись. В это время срабатывает событие save_post
		wp_update_post( array( 'ID' => $post_id, 'post_status' => 'private' ) );

		// Ставим хук обратно
		add_action( 'save_post', 'set_private_categories' );
	}
}

Эта часть кода, должна быть обязательно:

// Удаляем хук, чтобы не было зацикливания
remove_action( 'save_post', 'set_private_categories' );

// обновляем запись. В это время срабатывает событие save_post
wp_update_post( array( 'ID' => $post_id, 'post_status' => 'private' ) );

// Ставим хук обратно
add_action( 'save_post', 'set_private_categories' );

Где вызывается хук

wp_insert_post()
save_post
WP_Customize_Manager::trash_changeset_post()
save_post
wp_publish_post()
save_post
wp-includes/post.php 3747
do_action( 'save_post', $post_ID, $post, $update );
wp-includes/class-wp-customize-manager.php 2974
do_action( 'save_post', $post->ID, $post, true );
wp-includes/post.php 3856
do_action( 'save_post', $post->ID, $post, true );

Где используется хук (в ядре WP)

wp-includes/default-filters.php 451
add_action( 'save_post', 'delete_get_calendar_cache' );
15 комментов
Полезные 1 Вопросы 1 Все
  • @ campusboy3079 cайт: www.youtube.com/c/wpplus

    Интересная штука, если прописать вот так:

    function save_postratings_for_post( $post_id ) {
    	var_dump($post_id);
    	exit;
    }
    add_action( 'save_post', 'save_postratings_for_post' );

    То мы сможем наблюдать, что при заходе на форму создания поста, он уже имеет ID. Если честно, я удивлен. По идее, зачем это делать?

    Если использовать первый пример, то при заходе на /wp-admin/post-new.php будет сразу отослано письмо.

    P.S.: В базе также появляется auto-draft

    Ответить2 года назад #
    • Kama7099

      Там сложная система на самом деле! При создании записи, сразу создается черновик. А нужно это чтобы была запись в БД, и был ID к которому сразу можно прилепить метаполя и т.д. А иначе придется куда-то это все сохранять, а там система то гибкая. Получается для этого нужно очень многое учесть и по сути нужно написать огромный скрипт, который будет хранить все что может быть привязано к записи. А таким подходом решается сразу все! Потом при публикации остается только изменить статус с draft на publish и готово!

      П.С. Первый пример дополнил, спасибо!

      Ответить2 года назад #
      • @ campusboy3079 cайт: www.youtube.com/c/wpplus

        Это я понимаю smile Я не понимаю зачем создавать в БД черновик, который потом не виден. К примеру, я захожу, чтобы написать пост. Открыл страницу, потом подумал - нет вдохновения, закрыл страницу. Я не написал ни 1 символа, просто зашёл на страницу и ушёл, а в БД запись есть под статусом auto-draft. И в списке записей нет поста "Черновик" или ещё что-либо, чтобы можно было удалить или отредактировать. То есть эта запись в БД осталась мёртвым грузом, никому не нужная, мусором. Меня не устраивает лишь это и больше ничего smile Это можно почистить только зайдя в БД, через админку добраться до неё уже никак.

        P.S.: Спасибо за правки в коде!

        Ответить1.9 год назад #
  • Дмитрий

    Добрый день, а как быть с отложенными записями? Как я понимаю тут уже этот хук не работает?

    Ответить1.8 год назад #
    • Kama7099

      Если нужно делать что-то именно при публикации записи, то читай wp_transition_post_status(). save_post срабатывает только при обновлении записи или публикации так сказать вручную. Но если ВП автоматом меняет статус поста с, например, «черновик» на «опубликован», то save_post не сработает. Поэтому тут нужны другие хуки основанные на функции что я дал выше, там все написано...

      Ответить1.8 год назад #
  • @ campusboy3079 cайт: www.youtube.com/c/wpplus

    А во втором примере есть очистка sanitize_text_field. Есть ли в ней смысл? Вроде как в add_metadata есть строка:

    $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
    Ответить1.7 год назад #
    • Kama7099

      Она не очищает, а включает фильтры, а в том примере мы именно чистим... Т.е. результат если их убрать будет другой...

      1
      Ответить1.7 год назад #
  • @ Алексей

    так вышло, что админ сайта дал мне на редактирование только 1 файл - шаблон страницы темы, которая сама, в свою очередь, наследуется из ТвэнтиТен.
    я пишу по сути экспорт материалов сайта в спец. формат для моб. приложения, и весь алгоритм уже готов, осталось только прицепить хук на кнопку сохранить, но он не срабатывает.
    я так пишу в своём шаблоне страницы:
    add_action('save_post_scriptures', 'theBookIsUpdated', 10, 3);

    если я его позову в своём же файле, так:
    do_action('save_post_scriptures', $bk->ID, $bk, 0);
    то всё работает.

    но по нажатию кнопки в админке, ни в базу(мою, не сайта), ни в лог, ничего не пишется, т.е хук не срабатывает. я новичок в программировании для ВП, и тут какой-то нюанс, которого мне не хватает. знающие люди, помогите, подскажите, куда рыть, как можно проверить где затык?

    Ответить1.2 год назад #
  • Юрий

    У меня вот такой вопрос. Я сделал php скрипт, который никак не связан с wordpress, но он создает статьи в БД WordPress, т.е вставляется строка в таблицу wp_posts и прописывается категория в wp_term_relationships.
    Всё хорошо, за исключением того, что в этом случае стандартный поиск не работает.
    Подскажите, куда еще нужно внести изменения, чтобы работал поиск по сайту.
    Если созданную таким образом статью открыть и сохранить, то поиск начинает работать.

    Ответить2 месяца назад #
    • @ campusboy3079 cайт: www.youtube.com/c/wpplus

      А с каким статусом создаётся статья по вашему методу?

      Ответить2 месяца назад #
      • Юрий

        В запросе стоит 'publish', она сразу видна на сайте

        Ответить2 месяца назад #
Здравствуйте, !     Войти . Зарегистрироваться