10

So there is the following scenario.

I add an action to clean logs from the database:

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

Now I want to run this action periodically:

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

and execute it manually:

do_action( 'myplugin_clean_logs' );

The method MyPlugin_Logs::clean_logs returns the count of affected rows or false if something went the other direction.

Now I want to display the number of rows that have been deleted. I would imagine something like this:

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

But as do_action will not return any value, I have no idea how to get the return value.

Should I execute the method directly on a manual run, but use the action on schedule events?

  • 1
    You don't want to be echo'ing anything on a scheduled event, so yes, I would execute the method directly on a manual run (I'm assuming the administrator would trigger this, and you want to show them the output). – Tim Malone Apr 21 '16 at 22:55
11

The cool thing is a filter is the same as an action, only it returns a value, so just set it up as a filter instead:

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

Then something like:

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

should pass $affected_rows to clean_logs() (and whatever other functions you may have hooked to myplugin_clean_logs) and assign the return value back to $affected_rows.

  • 4
    downvoted as this is hacking code instead of developing software. If actions were just a subset of filters there would not have been any need of them. Cron can not pass value therefor it should not be hooked as a filter even if the buggy core code allows you to do such shemigans :) – Mark Kaplun Apr 21 '16 at 21:27
  • 1
    Point taken. I get that the intent of the two different things, but to look at the core code here, the whole do_action() thing is nothing more than an elaborate hack of apply_filters() :) – Caspar Apr 21 '16 at 22:00
  • not the only bad design in core which in part is what leads to confusion that lead to questions like this – Mark Kaplun Apr 21 '16 at 22:05
  • 1
    We need to work with what we've got, so while I understand Mark's point of view I still think this is a legit answer - unless of course core changes this approach in future, but I think that unlikely due to the massive backwards compatibility problems it would introduce. – Tim Malone Apr 21 '16 at 22:57
  • 3
    Thanks, @TimMalone. I do appreciate @mark-kaplun 's objection. My answer describes how to work around do_action() not returning a value rather than how to design a solution in congruence with do_action()s intent. If someone is able to do what he's asking, that answer deserves to be the accepted answer. My first thought would be to have the hooked method (assuming the OP is using an OOP design for this plugin) drop it's result into a protected property of the plugin class and then write a quick getter to pull it out at some later point. But that's just a wild hair of an idea! – Caspar Apr 22 '16 at 2:05
-1

Never used this function and haven't tested this, but might it work? 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);

If that doesn't work, why not just filter the thing like Caspar suggested? I mean, that is the purpose of a filter, and in this case the number of affected rows is the thing being filtered. (I miss the old MortCore. Anyone remember how it handled return values, pass-by-reference, and arguments with just a single three parameter function?)

  • This is a horrible answer, as passing in and modifying values by reference is really bad practice. Honestly, this answer really doesn't provide value in the context of the question and should likely be removed or changed to a comment. Additionally, using anonymous functions with hooks is also bad practice, as it makes them impossible to unhook. – Hybrid Web Dev Oct 30 '19 at 21:12
  • I agree for the same above mentioned reasons, that this is not a recommended path. If you for some reason need to get a return value from an action, and need something quick and dirty, I would prefer Caspars solution. If you are developing something with a life-cycle ahead of it, I would look for a more robust way. Coming to think of, how about admin notices? developer.wordpress.org/reference/hooks/admin_notices – jgangso Jan 21 at 9:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.