最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

hooks - RTrouble passing arguments to action

programmeradmin1浏览0评论

I know there are several posts on this topic. I have followed many of them as well as other resources on the web and thought I had it down, but it does not seem to be working. In my case, I have 2 functions hooked to 2 separate actions that need the same data.

$data = array('red', 'green', 'blue');

do_action('use_colors_here', $data);
add_action('wp_body_open', 'use_colors_here', 10, 1); 
function use_colors_here($data) {
  $out = '<h1>Colors</h1>';
  $out .= '<p>Color 1: ' . $data[1] . '</p>';
  $out .= '<p>Color 2: ' . $data[2] . '</p>';

  echo $out;
}

do_action('use_colors_there', $data);
add_action('wp_enqueue_scripts', 'use_colors_there', 10, 1); 
function use_colors_there($data) {
  wp_enqueue_script('color-script-1', get_stylesheet_directory_uri() . '/js/colors_' . $data[1] . '.js');
  wp_enqueue_script('color-script-2', get_stylesheet_directory_uri() . '/js/colors_' . $data[2] . '.js');
}

The expected behavior was for the values of $data[1] and $data[2] (green and blue respectively) to be accessible by the 2 functions and printed out in the markup each is responsible for adding to the page. Unfortunately, $data was not accessible inside the functions and I end up with markup looking like:

<h1>Colors</h1>
<p>Color 1: </p>
<p>Color 2: </p>

What am I doing wrong?

UPDATE

After reading a bit closer, I see that I have to use the hook rather than the function name as the 1st argument of do_action. So I changed it to:

do_action('wp_body_open', $data);

and it seems to be working.

FINAL CODE (using accepted answer)

function get_component_config() {
  return ['red', 'green', 'blue'];
}

add_action('wp_body_open', 'use_colors_here'); 
function use_colors_here() {
  $data = get_component_config();
  $out = '<h1>Colors</h1>';
  $out .= '<p>Color 1: ' . $data[1] . '</p>';
  $out .= '<p>Color 2: ' . $data[2] . '</p>';

  echo $out;
}

add_action('wp_enqueue_scripts', 'use_colors_there'); 
function use_colors_there() {
    $data = get_component_config();
    wp_enqueue_script('color-script-1', get_stylesheet_directory_uri() . '/js/colors_' . $data[1] . '.js');
    wp_enqueue_script('color-script-2', get_stylesheet_directory_uri() . '/js/colors_' . $data[2] . '.js');
}

I know there are several posts on this topic. I have followed many of them as well as other resources on the web and thought I had it down, but it does not seem to be working. In my case, I have 2 functions hooked to 2 separate actions that need the same data.

$data = array('red', 'green', 'blue');

do_action('use_colors_here', $data);
add_action('wp_body_open', 'use_colors_here', 10, 1); 
function use_colors_here($data) {
  $out = '<h1>Colors</h1>';
  $out .= '<p>Color 1: ' . $data[1] . '</p>';
  $out .= '<p>Color 2: ' . $data[2] . '</p>';

  echo $out;
}

do_action('use_colors_there', $data);
add_action('wp_enqueue_scripts', 'use_colors_there', 10, 1); 
function use_colors_there($data) {
  wp_enqueue_script('color-script-1', get_stylesheet_directory_uri() . '/js/colors_' . $data[1] . '.js');
  wp_enqueue_script('color-script-2', get_stylesheet_directory_uri() . '/js/colors_' . $data[2] . '.js');
}

The expected behavior was for the values of $data[1] and $data[2] (green and blue respectively) to be accessible by the 2 functions and printed out in the markup each is responsible for adding to the page. Unfortunately, $data was not accessible inside the functions and I end up with markup looking like:

<h1>Colors</h1>
<p>Color 1: </p>
<p>Color 2: </p>

What am I doing wrong?

UPDATE

After reading a bit closer, I see that I have to use the hook rather than the function name as the 1st argument of do_action. So I changed it to:

do_action('wp_body_open', $data);

and it seems to be working.

FINAL CODE (using accepted answer)

function get_component_config() {
  return ['red', 'green', 'blue'];
}

add_action('wp_body_open', 'use_colors_here'); 
function use_colors_here() {
  $data = get_component_config();
  $out = '<h1>Colors</h1>';
  $out .= '<p>Color 1: ' . $data[1] . '</p>';
  $out .= '<p>Color 2: ' . $data[2] . '</p>';

  echo $out;
}

add_action('wp_enqueue_scripts', 'use_colors_there'); 
function use_colors_there() {
    $data = get_component_config();
    wp_enqueue_script('color-script-1', get_stylesheet_directory_uri() . '/js/colors_' . $data[1] . '.js');
    wp_enqueue_script('color-script-2', get_stylesheet_directory_uri() . '/js/colors_' . $data[2] . '.js');
}
Share Improve this question edited Feb 10, 2021 at 8:12 Daveh0 asked Feb 9, 2021 at 9:19 Daveh0Daveh0 1912 silver badges13 bronze badges 3
  • i'm a little confused, none of your action names seem to match, you tried to fire an action named use_colors_here but no functions were added to that action so it does nothing. Then you have a function with that same name added to an unrelated action wp_body_open, but you try to use a $data argument, but wp_body_open does not provide any arguments! And then, you fire off a 3rd action use_colors_there that has nothing added to it either, so that doesn't do anything ( was this a typo? _there? _here? ). – Tom J Nowell Commented Feb 9, 2021 at 10:18
  • I suspect you've fallen into the X Y problem trap. Would I be right that your actual problem is displaying the colours on the body open action? And that all of the action stuff you asked about it just you trying to figure out how to solve that problem? I also see you have a use_colors_there function, but it's not used anywhere – Tom J Nowell Commented Feb 9, 2021 at 10:23
  • @TomJNowell - yes that sounds about right. I believe I've misused add_action. I'm trying to pass $data to both functions, use_colors_here and use_colors_there, which hook to wp_body_open and wp_enqueue_scripts respectively. – Daveh0 Commented Feb 9, 2021 at 10:30
Add a comment  | 

1 Answer 1

Reset to default 0

You have an action hook named use_colors_here and you run the hook using do_action( 'use_colors_here', $data ), but I don't see where you call add_action() for that hook?

I mean, the do_action() and add_action() should be used like so:

// This adds a callback to the use_colors_here hook.
add_action( 'use_colors_here', 'some_function' );

// And this is the callback which accepts one parameter from the use_colors_here hook.
function some_function( $data ) {
    var_dump( $data );
}

// And this do_action() executes the above callback (and other callbacks added to the
// `use_colors_here` hook).
$data = array( 'red', 'green', 'blue' );
do_action( 'use_colors_here', $data );

UPDATE (revised)

I see that I have to use the hook rather than the function name as the 1st argument of do_action

Yes that's right, the first parameter for do_action() is indeed the hook name, whereas the second and the rest of parameters are the parameters passed to the hook callbacks — but in the case of two or more parameters, you need to use the 4th parameter for add_action() to specify the number of parameters that your callback accepts.

// This fires the some_hook hook which has two parameters.
do_action( 'some_hook', 'param 1', 'param 2' );

// So when adding your action, if you want (to access) both the above parameters
// from your callback, then you must set the 4th parameter below to 2.
add_action( 'some_hook', 'some_function', 10, 2 );

function some_function( $param1, $param2 ) {
    var_dump( $param1, $param2 );
}

And do_action() (although indirectly) actually uses call_user_func_array() to run the actions for a specific (action) hook, or to run the callbacks registered to run on that hook, so if you understand how call_user_func_array() works, then you'd also understand how do_action() works.

function my_callback( $foo, $bar ) {
    var_dump( $foo, $bar, __FUNCTION__ );
}

$data = 'using call_user_func_array()';
// this calls my_callback() directly
call_user_func_array( 'my_callback', array( $data, 'second param' ) );

add_action( 'hook_name', 'my_callback', 10, 2 );
$data = 'using do_action()';
// but this fires the "event"/hook named hook_name and then it calls
// my_callback() indirectly via call_user_func_array()
// i.e. it calls call_user_func_array( 'my_callback', array( $data, 'yay, it works!' ) )
do_action( 'hook_name', $data, 'yay, it works!' );

I just need to be able to access $data from inside my 2 functions, use_colors_here and use_color_there

Then you're doing it correctly, i.e. when you do do_action('wp_body_open', $data), the $data will be passed to your 2 functions (and all other actions/callbacks for the hook).

But without calling do_action() manually and without using the global keyword or even $GLOBALS, the other possible way to access the $data variable is by using a closure; however, the drawback is that it'll be next to impossible to remove the specific action using remove_action() — because closures are anonymous functions, so what name would we use when removing the action?

add_action( 'some_hook', 'some_function', 10, 2 );
// that can be easily removed like so:
remove_action( 'some_hook', 'some_function', 10 );

$data = array( 'red', 'green', 'blue' );
add_action( 'some_hook', function () use ( $data ) {
    var_dump( $data );
} );
// now with that one, how do we remove it?
//remove_action( 'some_hook', ??, 10 );

Therefore, if you just wanted to get access to the data in the $data, then you could use a custom function which returns the data:

function get_colors() {
    return array( 'red', 'green', 'blue' );
}

add_action( 'wp_body_open', 'use_colors_here' );
function use_colors_here() {
    $data = get_colors();
    var_dump( $data );
}

I thought it would be better to keep everything in functions.php rather than adding more code to header.php... just for organizational purposes.

Yes (although not exactly "everything"), I thought the same as well. But in my original "Update" section, I was just saying you could (or that it's just fine if you) explicitly call your actions after the hook is fired. I.e.

// Let's say you define $data here. (in same file or block of code)
$data = array( 'red', 'green', 'blue' );

// So instead of..
do_action( 'wp_body_open', $data );

// You can do..
wp_body_open(); // this fires the wp_body_open hook
use_colors_here( $data );

// But that means, use_colors_here() should no longer be hooked on to the hook.

Does calling the function directly in header.php have any significant performance advantages?

No, but calling it directly means you can easily pass the $data and other parameters..

Otherwise, for local variables like the $data above, then we would need to use a closure in order to access the variable (and eventually the data inside or referenced to by that variable).

发布评论

评论列表(0)

  1. 暂无评论