Как получить возвращаемое значение при использовании do_action?

21 апр. 2016 г., 19:47:49
Просмотры: 21.2K
Голосов: 12

Итак, рассмотрим следующий сценарий.

Я добавляю действие для очистки логов из базы данных:

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 не возвращает никакого значения, я не знаю, как получить возвращаемое значение.

Стоит ли выполнять метод напрямую при ручном запуске, но использовать действие для запланированных событий?

1
Комментарии

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

Tim Malone Tim Malone
22 апр. 2016 г. 01:55:28
Все ответы на вопрос 3
10
16

Круто то, что фильтр — это то же самое, что и действие, только он возвращает значение, поэтому просто настройте его как фильтр:

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.

21 апр. 2016 г. 21:18:22
Комментарии

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

Mark Kaplun Mark Kaplun
22 апр. 2016 г. 00:27:11

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

Caspar Caspar
22 апр. 2016 г. 01:00:13

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

Mark Kaplun Mark Kaplun
22 апр. 2016 г. 01:05:58

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

Tim Malone Tim Malone
22 апр. 2016 г. 01:57:48

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

Caspar Caspar
22 апр. 2016 г. 05:05:51

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

Aley Aley
22 апр. 2016 г. 10:22:12

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

Mark Kaplun Mark Kaplun
22 апр. 2016 г. 10:47:16

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

Mark Kaplun Mark Kaplun
22 апр. 2016 г. 10:48:28

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

Solomon Closson Solomon Closson
18 окт. 2016 г. 21:39:25

Для справки, вот как это делает WooCommerce в своих шаблонах. Независимо от теории или лучших практик, по сути, это общепринятый способ, поскольку WooCommerce теперь официально является частью WordPress/Automattic.

Michael Thompson Michael Thompson
16 нояб. 2016 г. 22:16:59
Показать остальные 5 комментариев
0

Это очень старый вопрос, но чтобы ответить на исходный вопрос "Как использовать do_action и получить возвращаемое значение?" для всех, кто ищет решение, можно использовать буферизацию вывода.

ob_start();
    do_action( 'myplugin_clean_logs' );
$action_data = ob_get_clean();

Таким образом вы можете сохранить содержимое do_action в переменную.

20 июл. 2020 г. 00:41:57
2

Никогда не использовал эту функцию и не тестировал, но может ли это сработать? 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. Кто-нибудь помнит, как он обрабатывал возвращаемые значения, передачу по ссылке и аргументы всего одной функцией с тремя параметрами?)

8 авг. 2019 г. 22:54:27
Комментарии

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

Hybrid Web Dev Hybrid Web Dev
30 окт. 2019 г. 23:12:07

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

jgangso jgangso
21 янв. 2020 г. 11:55:50