WordPress の、 do_action って関数を見てみた

現在ほとんどデフォルトのままの WordPress 。
とりあえず、差し迫って必要なことは無いのだけど、なにかいじってみたいので Google Analytics を挿入してみようと思います。

結論を言いますと、結局先人の開発したすばらしいプラグイン Ultimate Google Analytics plugin for WordPress を使用しました。

なので、以下は単にソースを読んだときのメモです。

吐き出されたHTMLソースから、どうやら wp_footer() という関数に、好きなコードを吐き出させるみたい。んで、この wp_footer が何をしているのかたどっていく。

すると、

wp-content\themes\default\footer.php(14)
wp-includes\general-template.php(1362)
wp-includes\plugin.php(299)

までたどり着いたのですが、この、 plugin.php にある

function do_action

ていうのはよく読まないと先へ進めないです。
で、私なりに読んで解釈したのをメモします。
ちなみに、この関数はいたるところで呼び出されていると思いますが、今回はあくまでもフッタの記述。つまり、引数として “wp_footer” っていう文字列を渡している場合に限られます。そして、トップページでの呼び出しでのみ調べたことなので、ページが異なれば挙動が変わる可能性も大いにありです。

function do_action($tag, $arg = '') {
  // 4つのグローバル変数を関数内で展開
  global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;

  // 配列 $wp_actions に "wp_footer" をプッシュ。
  if ( is_array($wp_actions) )
    $wp_actions[] = $tag;
  else
    $wp_actions = array($tag);

  // 配列 $wp_current_filter にも "wp_footer" をプッシュ。(これは、空の配列でした)
  $wp_current_filter[] = $tag;

  // $wp_filter['all'] はセットされていないのでパス
  // Do 'all' actions first
  if ( isset($wp_filter['all']) ) {
    $all_args = func_get_args();
    _wp_call_all_hook($all_args);
  }

  /*-------------------------------------
   $wp_filter[$tag] がセットされていなければ、
   $wp_current_filter から先ほどの "wp_footer" をポップして終了しますが、
   $wp_filter['wp_footer'] に値があるので続く。
   この、 $wp_filter の該当する箇所を抜き出すとこんな風。

  array(
    [wp_footer] => array
    (
      [10] => array
      (
        [wp_print_footer_scripts] => array
        (
          [function] => wp_print_footer_scripts
          [accepted_args] => 1
      )

      )

    )
  )

  ここに、処理内容をスタックさせているのでしょう。
  ---------------------------------------*/
  if ( !isset($wp_filter[$tag]) ) {
    array_pop($wp_current_filter);
    return;
  }

  // $args には何もセットされない。
  $args = array();
  if ( is_array($arg) && 1 == count($arg) && is_object($arg[0]) ) // array(&$this)
    $args[] =& $arg[0];
  else
    $args[] = $arg;
  for ( $a = 2; $a < func_num_args(); $a++ )
    $args[] = func_get_arg($a);

  /*----------------------------------------
  $merged_filters[$tag] がセットされていないので

  ksort($wp_filter[$tag]);
  $merged_filters[ $tag ] = true;

  っていう処理を行う。けど、$wp_filter['wp_footer'] は、
  1つしか要素が無いので順番は変わらない。 reset してもポインタに影響なし。
  -----------------------------------------*/
  // Sort
  if ( !isset( $merged_filters[ $tag ] ) ) {
    ksort($wp_filter[$tag]);
    $merged_filters[ $tag ] = true;
  }

  reset( $wp_filter[ $tag ] );

  /*-------------------------------------------
  いよいよここで、$wp_filter['wp_footer']
  にセットされたタスクを処理

  current だとか、array にキャストだとか、
  私が使ったことの無い、良く分からんけど なんかかっこいい
  テクニックが最後に出てきてしまいましたが、
  要は $wp_filter['wp_footer'] から、配列を抜き出して、
  その配列を foreach でループさせているのですね。(違う?)
  PHPでポインタとか考えたこと無かったんで、この辺ちょっと勉強不足です。

  で、実際に何を実行しているかというと、

  関数 wp_print_footer_scripts() の呼び出しなのですね。
  受け取る引数の数が 1 ですが、 $args には何も入っていないので、
  wp_print_footer_scripts() には、空の配列が渡されて終了。
  -------------------------------------------*/
  do {
    foreach ( (array) current($wp_filter[$tag]) as $the_ )
      if ( !is_null($the_['function']) )
        call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));

  } while ( next($wp_filter[$tag]) !== false );

  // 最初にプッシュした "wp_footer" をポップして(空に戻る)終了。
  array_pop($wp_current_filter);
}

で、肝心のフッタの挿入ですが、 wp_print_footer_scripts は、 print_footer_scripts を呼び出していています。(ふぅーっ)

ここまできて、これはやはり先人のご意見を伺おうとググってみたわけです。

「WordPress Google」 ここまで入力した時点で、アナリティクス(って、しかもカタカナで)補完(笑)

はい、すばらしいプラグインがありました。

http://www.oratransplant.nl/uga/

ありがとう御座いました。

すごいこれ!
ログイン中のユーザーに対してはスクリプト吐き出さないんですね!

function do_action($tag, $arg = ”) {
// 4つのグローバル変数を関数内で展開
global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;

// 配列 $wp_actions に “wp_footer” をプッシュ。
if ( is_array($wp_actions) )
$wp_actions[] = $tag;
else
$wp_actions = array($tag);

// 配列 $wp_current_filter にも “wp_footer” をプッシュ。(これは、空の配列でした)
$wp_current_filter[] = $tag;

// $wp_filter['all'] はセットされていないのでパス
// Do ‘all’ actions first
if ( isset($wp_filter['all']) ) {
$all_args = func_get_args();
_wp_call_all_hook($all_args);
}

/*————————————-
$wp_filter[$tag] がセットされていなければ、 $wp_current_filter から先ほどの “wp_footer” をポップして終了しますが、 $wp_filter['wp_footer'] に値があるので続く。
この、 $wp_filter が興味深い。該当する箇所を抜き出すとこんな風。

array(
[wp_footer] => array
(
[10] => array
(
[wp_print_footer_scripts] => array
(
[function] => wp_print_footer_scripts
[accepted_args] => 1
)

)

)
)

ここに、処理内容をスタックさせているのでしょう。
—————————————*/
if ( !isset($wp_filter[$tag]) ) {
array_pop($wp_current_filter);
return;
}

// $args には何もセットされない。
$args = array();
if ( is_array($arg) && 1 == count($arg) && is_object($arg[0]) ) // array(&$this)
$args[] =& $arg[0];
else
$args[] = $arg;
for ( $a = 2; $a < func_num_args(); $a++ )
$args[] = func_get_arg($a);

/*—————————————-
$merged_filters[$tag] がセットされていないので

ksort($wp_filter[$tag]);
$merged_filters[ $tag ] = true;

っていう処理を行う。けど、$wp_filter['wp_footer'] は、1つしか要素が無いので順番は変わらない。 reset してもポインタに影響なし。
—————————————–*/
// Sort
if ( !isset( $merged_filters[ $tag ] ) ) {
ksort($wp_filter[$tag]);
$merged_filters[ $tag ] = true;
}

reset( $wp_filter[ $tag ] );

/*——————————————-
いよいよここで、$wp_filter['wp_footer']
にセットされたタスクを処理

current だとか、array にキャストだとか、
私が使ったことの無い良く分からんけど、
なんかかっこいいテクニックが最後に出てきてしまいましたが、
要は $wp_filter['wp_footer'] から、配列を抜き出して、
その配列を foreach でループさせているのですね。(違う?)
ポインタとか考えたこと無かったんで、この辺ちょっと勉強不足です。

で、実際に何を実行しているかというと、

関数 wp_print_footer_scripts() の呼び出しなのですね。
受け取る引数の数が 1 ですが、 $args には何も入っていないので、
wp_print_footer_scripts() には、空の配列が渡されて終了。
——————————————-*/
do {
foreach ( (array) current($wp_filter[$tag]) as $the_ )
if ( !is_null($the_['function']) )
call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));

} while ( next($wp_filter[$tag]) !== false );

// 最初にプッシュした “wp_footer” をポップして(空に戻る)終了。
array_pop($wp_current_filter);
}

コメントをどうぞ