Как получить возвращаемое значение при использовании do_action?
Итак, рассмотрим следующий сценарий.
Я добавляю действие для очистки логов из базы данных:
add_action( 'myplugin_clean_logs', array( 'MyPlugin_Logs', 'clean_logs' ) );
Теперь я хочу запускать это действие периодически:
wp_schedule_event( current_time( 'timestamp' ), 'daily', 'myplugin_clean_logs' );
и выполнять его вручную:
do_action( 'myplugin_clean_logs' );
Метод MyPlugin_Logs::clean_logs
возвращает количество затронутых строк или false, если что-то пошло не так.
Теперь я хочу отобразить количество удаленных строк. Я представлял это примерно так:
$affected_rows = do_action( 'myplugin_clean_logs' );
echo $affected_rows . ' записей было удалено.';
Но поскольку do_action
не возвращает никакого значения, я не знаю, как получить возвращаемое значение.
Стоит ли выполнять метод напрямую при ручном запуске, но использовать действие для запланированных событий?

Круто то, что фильтр — это то же самое, что и действие, только он возвращает значение, поэтому просто настройте его как фильтр:
add_filter( 'myplugin_clean_logs', array( 'MyPlugin_Logs', 'clean_logs' ) );
Затем что-то вроде:
$affected_rows = '';
$affected_rows = apply_filters( 'myplugin_clean_logs', $affected_rows );
должно передать $affected_rows
в clean_logs()
(и любые другие функции, которые вы могли подключить к myplugin_clean_logs
) и присвоить возвращаемое значение обратно переменной $affected_rows
.

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

Принято к сведению. Я понимаю назначение этих двух разных вещей, но если посмотреть на код ядра, вся штука с do_action()
— не более чем сложный хак над apply_filters()
:)

не единственная плохая архитектура в ядре, что частично приводит к путанице и таким вопросам

Нам нужно работать с тем, что есть, поэтому, хоть я и понимаю точку зрения Марка, всё же считаю этот ответ допустимым — если только ядро WordPress не изменит этот подход в будущем, но думаю, это маловероятно из-за серьёзных проблем с обратной совместимостью, которые это вызовет.

Спасибо, @TimMalone. Я действительно учитываю возражение @mark-kaplun. Мой ответ описывает, как обойти отсутствие возвращаемого значения в do_action()
, а не как разработать решение в соответствии с задумкой do_action()
. Если кто-то сможет сделать то, о чём он просит, такой ответ заслуживает быть принятым. Первое, что пришло мне в голову — чтобы hooked-метод (предполагая, что автор использует ООП-дизайн для этого плагина) сохранял свой результат в protected-свойстве класса плагина, а затем можно было бы быстро написать геттер для извлечения этого значения позже. Но это просто сырая идея!

@Casper, документация WordPress явно различает actions и filters. Насколько я понял, фильтр предназначен именно для фильтрации данных и является скорее инструментом, чем исполнителем. Возможно, это лишь теория, и разница больше в дизайне кода, чем в реальной практике. Изначально у меня была похожая идея передавать переменную по ссылке (хотя я не проверял, сработает ли это), но я избежал этого, чтобы не усложнять код.

@TimMalone, иногда, когда у вас возникает запутанная проблема с кодом, стоит остановиться и спросить себя - это проблема кодирования или проблема проектирования

@Aley, извините, на самом деле написал комментарий к вопросу, но видимо забыл отправить, но вы можете понять суть моего мнения (вам нужно обрабатывать это по-разному в обоих случаях) из комментариев здесь

Почему бы просто не использовать вызов PHP-функции, тогда не понадобятся do_action или apply_filters. Разместите функцию в файле functions.php.

Это очень старый вопрос, но чтобы ответить на исходный вопрос "Как использовать do_action и получить возвращаемое значение?" для всех, кто ищет решение, можно использовать буферизацию вывода.
ob_start();
do_action( 'myplugin_clean_logs' );
$action_data = ob_get_clean();
Таким образом вы можете сохранить содержимое do_action в переменную.

Никогда не использовал эту функцию и не тестировал, но может ли это сработать? do_action_ref_array().
function myplugin_clean_logs_fn() {
$args = array(
'param1' => 'val1',
'param2' => 'val2',
'affected_rows' => 0,
);
do_action_ref_array( 'myplugin_clean_logs', &$args );
return $args['affected_rows'];
}
// ВЫЗОВ ФУНКЦИИ
$affected_rows = my_plugin_clean_logs();
echo $affected_rows .' запис'. ($args['affected_rows']*1===1?'ь':'ей') .' удалено.';
// НАСТРОЙКА РАСПИСАНИЯ
add_action('myplugin_clean_logs_call_fn', 'myplugin_clean_logs_fn');
wp_schedule_event( current_time( 'timestamp' ), 'daily', 'myplugin_clean_logs_call_fn' );
// ПРИМЕР ФИЛЬТРА
add_action('myplugin_clean_logs', function($args) {
// Процесс очистки
// Для каждой затронутой записи увеличиваем $args['affected_rows'] соответственно
}, 10, 3);
Если это не работает, почему бы просто не отфильтровать данные, как предложил Caspar? Ведь именно для этого и нужны фильтры, а в данном случае количество затронутых строк — это то, что фильтруется. (Скучаю по старому MortCore. Кто-нибудь помнит, как он обрабатывал возвращаемые значения, передачу по ссылке и аргументы всего одной функцией с тремя параметрами?)

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

Я согласен по вышеуказанным причинам, что это не рекомендуемый путь. Если вам по какой-то причине нужно получить возвращаемое значение из действия и вам нужно что-то быстрое и грязное, я бы предпочел решение Caspar. Если вы разрабатываете что-то с долгосрочной перспективой, я бы искал более надежный способ. Кстати, как насчет admin notices? https://developer.wordpress.org/reference/hooks/admin_notices/
