Как избежать бесконечного цикла в save_post callback

7 мая 2012 г., 13:21:14
Просмотры: 16.2K
Голосов: 22

Я часто использую этот сайт для решения своих проблем, но на этот раз не смог найти ответ на свой вопрос.

Я получаю бесконечный цикл при использовании wp_update_post внутри функции, которая вызывается на save_post. Я знаю, что это распространённая проблема, но не могу понять, как её избежать.

Мне нужно сохранить порядок моих записей (которые относятся к типу 'section'). Я создал пользовательский метабокс, содержащий сортируемые html-элементы. В каждом элементе есть скрытое поле input с name='sectionorder[]'. Когда я нажимаю стандартную кнопку WordPress 'Обновить', массив со всеми ID записей (в порядке сортировки) отправляется через POST. Вот код, где я получаю массив и хочу сохранить порядок:

    // Обновляем порядок сортировки секций
$sectionorder = $_POST['sectionorder'];
if (isset($sectionorder)) { // Избегаем ошибки, если секции ещё не добавлены
    foreach( $sectionorder as $no => $sectionID ) {
        $post_update = array();
        $post_update['ID'] = $sectionID;
        $post_update['menu_order'] = $no;
        wp_update_post( $post_update );
    }
}

Проблема в том, что это вызывает бесконечный цикл. Как этого избежать? Возможно, есть другой способ реализации?

Буду благодарен за помощь!

0
Все ответы на вопрос 3
5
44

Вы можете удалить колбэк из хука save_post, обновить запись, а затем снова добавить колбэк к хуку. В Кодексе приведён пример.

add_action('save_post', 'wpse51363_save_post');

function wpse51363_save_post($post_id) {

    // Проверяем, что это не автосохранение
    if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
          return;

    // Проверяем права пользователя
    if ( !current_user_can('edit_post', $post_id) ) 
          return;

    // Проверяем nonce!

    // Если вызываем wp_update_post, отключаем эту функцию, чтобы избежать бесконечного цикла
    remove_action('save_post', 'wpse51363_save_post');

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

    // Снова подключаем эту функцию
    add_action('save_post', 'wpse51363_save_post');
}
7 мая 2012 г. 13:43:21
Комментарии

Вау. Спасибо за быстрый ответ. Работает отлично! Не понимаю, как я сам не заметил этот пример кода..

elgehelge elgehelge
7 мая 2012 г. 14:08:23

@Stephen, я использую update_post_meta в функции, привязанной к save_post, нужно ли также отвязывать и снова привязывать после update_post_meta?

Anagio Anagio
14 нояб. 2013 г. 21:20:55

Нет, update_post_meta (обычно) не вызывает срабатывание save_post.

Stephen Harris Stephen Harris
14 нояб. 2013 г. 21:49:13

Потратив час, нашел это, и это сэкономило мне еще больше времени, спасибо.

Manchumahara Manchumahara
22 дек. 2019 г. 07:39:16

работает для меня в 2020 году

gray gray
2 мая 2020 г. 02:00:38
3
19

У меня пока нет достаточной репутации для комментариев, поэтому я добавляю ответ, хотя ответ Стивена отличный и правильный. Просто он не учитывает случаи, когда нужно установить приоритет действия.

Если вы установите приоритет при добавлении действия, но не укажете его при удалении, это всё равно приведёт к бесконечному циклу.

add_action('save_post', 'wpse51363_save_post', 25 );

// НЕПРАВИЛЬНЫЙ способ обработки — приводит к бесконечному циклу

remove_action('save_post', 'wpse51363_save_post');
wp_update_post(array('ID' => $post_id, 'post_status' => 'private'));
add_action('save_post', 'wpse51363_save_post');

// ПРАВИЛЬНЫЙ способ обработки — выполняется только один раз

remove_action('save_post', 'wpse51363_save_post', 25 );
wp_update_post(array('ID' => $post_id, 'post_status' => 'private'));
add_action('save_post', 'wpse51363_save_post', 25 );
20 июн. 2014 г. 21:05:37
Комментарии

Вау, спасибо! Я уже сходил с ума, пытаясь понять, почему у меня все еще возникает бесконечный цикл, даже при добавлении remove_action/add_action.

Banjer Banjer
25 авг. 2014 г. 03:27:25

WordPress Codex :: Plugin API/Action Reference/save post :: Избежание бесконечных циклов Они демонстрируют это. Если посмотреть на WordPress Codex :: Function Reference/remove action :: Использование "Приоритет функции (как определено при первоначальном подключении функции)." Если не указан, используется приоритет по умолчанию (10). То есть - вы должны указать ТОТ ЖЕ приоритет, что и при добавлении действия, чтобы ДЕЙСТВИТЕЛЬНО удалить его.

Michael Ecklund Michael Ecklund
2 дек. 2016 г. 18:50:11

Это именно тот ответ, который я искал. Спасибо :)

José Manuel Blasco José Manuel Blasco
6 июн. 2019 г. 12:34:05
0

Это довольно быстрый и грязный трюк, но один из способов — создать глобальную переменную, например $my_plugin_name_saving, установить её в true перед вызовом wp_update_post и проверить, не установлена ли переменная заранее.


<?php
/* Plugin Name: My plugin name */

$my_plugin_name_saving = false;

function cc_publish_wpse_263985( $postid ) {
    global my_plugin_name_saving;

    if ( ! empty( $my_plugin_name_saving ) ) {
        return;
    }

    $my_plugin_name_saving = true;
    wp_update_post(array('ID' => $postid, 'post_status' => 'private'));

}

add_action('save_post', 'cc_publish_wpse_263985');
14 сент. 2022 г. 02:33:54