Como do_action e obter um valor de retorno?

10

Portanto, existe o seguinte cenário.

Eu adiciono uma ação para limpar logs do banco de dados:

add_action( 'myplugin_clean_logs', array( 'MyPlugin_Logs', 'clean_logs' ) );

Agora eu quero executar esta ação periodicamente:

wp_schedule_event( current_time( 'timestamp' ), 'daily', 'myplugin_clean_logs' );

e execute-o manualmente:

do_action( 'myplugin_clean_logs' );

O método MyPlugin_Logs::clean_logsretorna a contagem de linhas afetadas ou false se algo foi na outra direção.

Agora eu quero exibir o número de linhas que foram excluídas. Eu imaginaria algo assim:

$affected_rows = do_action( 'myplugin_clean_logs' );
echo $affected_rows . ' entries have been deleted.';

Mas como do_actionnão retornará nenhum valor, não tenho idéia de como obter o valor de retorno.

Devo executar o método diretamente em uma execução manual, mas usar a ação em agendar eventos?

Aley
fonte
11
Você não deseja fazer eco de nada em um evento agendado; portanto, sim, eu executaria o método diretamente em uma execução manual (suponho que o administrador acionaria isso e você deseja mostrar a saída).
Tim Malone

Respostas:

13

O legal é que um filtro é o mesmo que uma ação, mas ele retorna um valor, então configure-o como um filtro:

add_filter( 'myplugin_clean_logs', array( 'MyPlugin_Logs', 'clean_logs' ) );

Então algo como:

$affected_rows = '';
$affected_rows = apply_filters( 'myplugin_clean_logs', $affected_rows );

deve passar $affected_rowspara clean_logs()(e quaisquer outras funções às quais você possa ter se conectado myplugin_clean_logs) e atribuir o valor de retorno de volta $affected_rows.

Caspar
fonte
4
diminuído como este é o código de hackers em vez de desenvolver software. Se as ações fossem apenas um subconjunto de filtros, não haveria necessidade delas. Cron não pode passar o valor para esse fim não deve ser viciado como um filtro, mesmo se o código do núcleo de buggy permite que você faça tais shemigans :)
Mark Kaplun
11
Ponto tomado. Tenho que o propósito das duas coisas diferentes, mas ao olhar para o código do núcleo aqui, toda do_action()coisa é nada mais do que um truque elaborado de apply_filters():)
Caspar
não é o único mau design no núcleo que, em parte, é o que leva à confusão que levam a perguntas como esta
Mark Kaplun
11
Precisamos trabalhar com o que temos, por isso, embora eu entenda o ponto de vista de Mark, ainda acho que essa é uma resposta legítima - a menos que o núcleo mude essa abordagem no futuro, mas acho que isso é improvável devido aos enormes problemas de compatibilidade com versões anteriores isso iria introduzir.
Tim Malone
3
Obrigado, @TimMalone. Agradeço a objeção de @ mark-kaplun. Minha resposta descreve como contornar do_action()não retornando um valor, e não como projetar uma solução em congruência com do_action()a intenção de s. Se alguém é capaz de fazer o que está pedindo, essa resposta merece ser a resposta aceita. Meu primeiro pensamento seria ter o método hooked (supondo que o OP esteja usando um design OOP para este plugin) solte o resultado em uma propriedade protegida da classe plugin e, em seguida, escreva um getter rápido para retirá-lo em algum momento posterior. Mas isso é apenas uma idéia selvagem!
Caspar
-1

Nunca usou essa função e não a testou, mas poderia funcionar? 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'];
}

// CALL IT
$affected_rows = my_plugin_clean_logs();
echo $affected_rows .' entr'. ($args['affected_rows']*1===1?'y':'ies') .' deleted.';

// SCHEDULE IT
add_action('myplugin_clean_logs_call_fn', 'myplugin_clean_logs_fn');
wp_schedule_event( current_time( 'timestamp' ), 'daily', 'myplugin_clean_logs_call_fn' );

// A SAMPLE FILTER
add_action('myplugin_clean_logs', function($args) {
    // Cleaning process
    // For each log affected, increment $args['affected_rows'] accordingly
}, 10, 3);

Se isso não funcionar, por que não filtrar o que Caspar sugeriu? Quero dizer, esse é o objetivo de um filtro e, nesse caso, o número de linhas afetadas é o que está sendo filtrado. (Sinto falta do antigo MortCore. Alguém se lembra de como ele lidava com valores de retorno, passagem por referência e argumentos com apenas uma única função de três parâmetros?)

Goofball
fonte
Essa é uma resposta horrível, pois passar e modificar valores por referência é uma prática muito ruim. Honestamente, essa resposta realmente não fornece valor no contexto da pergunta e provavelmente deve ser removida ou alterada para um comentário. Além disso, o uso de funções anônimas com ganchos também é uma prática ruim, pois impossibilita que eles sejam desengatados.
Hybrid Web Dev
Concordo pelas mesmas razões acima mencionadas, que este não é um caminho recomendado. Se, por algum motivo, você precisar obter um valor de retorno de uma ação e precisar de algo rápido e sujo, eu preferiria a solução Caspars. Se você estiver desenvolvendo algo com um ciclo de vida à frente, eu procuraria uma maneira mais robusta. Pensando nisso, que tal avisos de administração? developer.wordpress.org/reference/hooks/admin_notices
jgangso em 21/01