¿Cómo hacer_acción y obtener un valor de retorno?

10

Entonces, existe el siguiente escenario.

Agrego una acción para limpiar los registros de la base de datos:

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

Ahora quiero ejecutar esta acción periódicamente:

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

y ejecutarlo manualmente:

do_action( 'myplugin_clean_logs' );

El método MyPlugin_Logs::clean_logsdevuelve el recuento de filas afectadas o falso si algo fue en la otra dirección.

Ahora quiero mostrar el número de filas que se han eliminado. Me imagino algo como esto:

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

Pero como do_actionno devolverá ningún valor, no tengo idea de cómo obtener el valor de retorno.

¿Debo ejecutar el método directamente en una ejecución manual, pero usar la acción en eventos programados?

Aley
fuente
1
No desea repetir nada en un evento programado, así que sí, ejecutaría el método directamente en una ejecución manual (supongo que el administrador activará esto y desea mostrarles el resultado).
Tim Malone

Respuestas:

11

Lo bueno es que un filtro es lo mismo que una acción, solo que devuelve un valor, así que configúralo como un filtro:

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

Entonces algo como:

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

debe pasar $affected_rowsa clean_logs()(y a cualquier otra función a la que haya conectado myplugin_clean_logs) y asignar el valor de retorno nuevamente $affected_rows.

Caspar
fuente
44
rechazado ya que esto es hackear código en lugar de desarrollar software. Si las acciones fueran solo un subconjunto de filtros, no habría sido necesario. Cron no puede pasar el valor, por lo que no debe engancharse como un filtro, incluso si el código central con errores le permite hacer tales shemigans :)
Mark Kaplun
1
Punto a favor. Entiendo que la intención de las dos cosas diferentes, pero al mirar el código central aquí, todo el do_action()asunto no es más que un elaborado truco de apply_filters():)
Caspar
no es el único mal diseño en el núcleo, que en parte es lo que lleva a la confusión que lleva a preguntas como esta
Mark Kaplun
1
Necesitamos trabajar con lo que tenemos, así que, aunque entiendo el punto de vista de Mark, sigo pensando que esta es una respuesta legítima, a menos que, por supuesto, el núcleo cambie este enfoque en el futuro, pero creo que es poco probable debido a los enormes problemas de compatibilidad con versiones anteriores. Lo introduciría.
Tim Malone
3
Gracias, @TimMalone. Agradezco la objeción de @ mark-kaplun. Mi respuesta describe cómo trabajar para do_action()no devolver un valor en lugar de cómo diseñar una solución en congruencia con do_action()la intención de s. Si alguien puede hacer lo que está pidiendo, esa respuesta merece ser la respuesta aceptada. Mi primer pensamiento sería hacer que el método enganchado (suponiendo que el OP esté usando un diseño OOP para este complemento) deje caer el resultado en una propiedad protegida de la clase de complemento y luego escriba un captador rápido para sacarlo en algún momento posterior. ¡Pero esa es una idea descabellada!
Caspar
-1

Nunca usé esta función y no la he probado, pero ¿podría 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);

Si eso no funciona, ¿por qué no simplemente filtrar lo que sugirió Caspar? Quiero decir, ese es el propósito de un filtro, y en este caso el número de filas afectadas es lo que se está filtrando. (Extraño el viejo MortCore. ¿Alguien recuerda cómo manejó los valores de retorno, la referencia de paso y los argumentos con una sola función de tres parámetros?)

Goofball
fuente
Esta es una respuesta horrible, ya que pasar y modificar valores por referencia es realmente una mala práctica. Honestamente, esta respuesta realmente no proporciona valor en el contexto de la pregunta y probablemente debería eliminarse o cambiarse a un comentario. Además, el uso de funciones anónimas con ganchos también es una mala práctica, ya que hace que sea imposible desengancharlos.
Hybrid Web Dev
Estoy de acuerdo por las mismas razones mencionadas anteriormente, que esta no es una ruta recomendada. Si por alguna razón necesita obtener un valor de retorno de una acción y necesita algo rápido y sucio, preferiría la solución Caspars. Si está desarrollando algo con un ciclo de vida por delante, buscaría una forma más sólida. Ahora que lo pienso, ¿qué tal los avisos de administrador? developer.wordpress.org/reference/hooks/admin_notices
jgangso