2

I am struggling with this problem for hours now, what is going on is that somewhere before inserting the values into the db, this action is being called.

do_action_ref_array('h5p_alter_user_result', array(&$data, $result_id, $content_id, $user_id));

Following are the values and how they are being populated.

$user_id = get_current_user_id();
    $result_id = $wpdb->get_var($wpdb->prepare(
        "SELECT id
        FROM {$wpdb->prefix}h5p_results
        WHERE user_id = %d
        AND content_id = %d",
        $user_id,
        $content_id
    ));

$table = $wpdb->prefix . 'h5p_results';
$data = array(
  'score' => filter_input(INPUT_POST, 'score', FILTER_VALIDATE_INT),
  'max_score' => filter_input(INPUT_POST, 'maxScore', FILTER_VALIDATE_INT),
  'opened' => filter_input(INPUT_POST, 'opened', FILTER_VALIDATE_INT),
  'finished' => filter_input(INPUT_POST, 'finished', FILTER_VALIDATE_INT),
  'time' => filter_input(INPUT_POST, 'time', FILTER_VALIDATE_INT)
);
if ($data['time'] === NULL) {
  $data['time'] = 0;
}
$format = array(
  '%d',
  '%d',
  '%d',
  '%d',
  '%d'
);

$content_id = 1;

what I am trying to do is that I am wanting to modify these values before they are being saved in the database ( and yes this hook is called before saving in db ), for this I have created the following functionality in my plugin.

add_action( 'h5p_alter_user_result',           'diff_test_callback' );

function diff_test_callback($args)
{
    global $wpdb;
  $user_id = 1;
    $result_id = 1;
$content_id = 1;
    $table = $wpdb->prefix . 'h5p_results';
    $data = array(
      'score' => 777,
      'max_score' => 189,
      'opened' => 333,
      'finished' => 222,
      'time' => 111
    );
    if ($data['time'] === NULL) {
      $data['time'] = 0;
    }
    $args = array( $data, $result_id, $content_id, $user_id );
    return $args;
}

But the values are not being modified, is there some thing wrong?

2
  • Actions allow one to do something, take an additional action, HOWEVER If you want to change the data being used at the time, a 'filter' is what you need. Your callback gets passed the data, your code modifies it (or not) and passes the data back. That do_action is not using the data you are setting.
    – anmari
    Aug 18, 2018 at 7:36
  • I understand, but the plugin I am modifying uses action to change values. I will keep this is mind
    – hede
    Aug 18, 2018 at 18:02

1 Answer 1

1

Correct way of modifying a variable using hooks

If you want to modify a variable or any value using hooks, it's best to do that using filter hooks (instead of action hooks). Although internally the implementation is almost the same for actions and filters, the convention is:

  1. With action hooks, you do something, echo output etc. inside the callback function, but neither return anything, nor change the arguments outside the scope of that callback function.

  2. With filter hooks, you return a value from the callback function and either use it somewhere or assign it to a variable outside of the callback function.

So use the apply_filters CODE like this:

// using apply_filters() instead of the following do_action_ref_array() line
// do_action_ref_array( 'h5p_alter_user_result', array( &$data, $result_id, $content_id, $user_id ) );
$data = apply_filters( 'h5p_alter_user_result', $data, $result_id, $content_id, $user_id );

To match this, use add_filter and the callback function like this:

// Declare number of parameters to be passed in add_filter.
// According to our apply_filters() call,
// we expect 4 parameters to be passed to the callback function
add_filter( 'h5p_alter_user_result', 'diff_test_callback', 10, 4 );
function diff_test_callback( $data, $result_id, $content_id, $user_id ) {
    // do something with $data
    // remember: manipulation of $data doesn't have any affect
    // outside of this function
    // So we need this return
    return $data;
}

do_action_ref_array issues in your CODE:

From your do_action_ref_array call, looks like you are trying to pass $data as reference:

do_action_ref_array( 'h5p_alter_user_result', array( &$data, $result_id, $content_id, $user_id ) );

However, since PHP 5.4, this behaviour has been changed. do_action_ref_array no longer passes the reference of the argument to the callback function, instead, it passes a copy.

Also, call time pass by reference is not accepted since PHP 5.4. So best is to use the apply_filters method as shown in the above CODE.

Even though not recommended, what you tried to do can be done with reference pointers as function parameters inside an array. Like this:

// add_action without passing the number of parameters
add_action( 'h5p_alter_user_result', 'diff_test_callback' );
// callback function implementation with reference pointer `&`
// for parameters you are expecting with reference
function diff_test_callback( $args ) {
    // we need the reference of $data, so using & operator here.
    $data = &$args[0];
    $result_id = $args[1];
    $content_id = $args[2];
    $user_id = $args[3];

    // now making changes to $data
    // will be reflected outside the scope of this function
    // no return is necessary
}

// at the time of executing the action,
// create the $args array with reference to $data
$args = array( &$data, $result_id, $content_id, $user_id );
do_action_ref_array( 'h5p_alter_user_result', array( $args ) );

Warning: Once again, although do_action_ref_array method works if you carefully handle the references, it's highly recommended that you use the filter hook method in this scenario.

0

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.