フィルターフック・アクションフック

WordPress にはフィルターフック・アクションフックと 呼ばれるプラグイン用の API が用意されています。

これらのフックは、WordPress が動作する様々なタイミングで、 プラグインから登録された関数があるか判断し、もしあれば その関数を走らせることによって、WordPress のデフォルトの 動作を変更します。

例えば「the_content」というフィルターフックに関数を登録すれば、記事本文を変更できます。

function korosukenize( $content ) {
  $content = preg_replace(
    "/ます([。、]?)/" ,
    "るなりよ$1" ,
    $content );
  return $content;
}
add_filter('the_content', 'korosukenize');

こんな感じのプラグインを書いてやるだけで、
記事本文の語尾をコロ助風に変換できます。

適切なフックを探すには?

では、自分のプラグインで使用したいフィルターフック・アクションフックを探すにはどうすれば良いでしょうか?
通常は、WordPress Codex のフィルターフック一覧アクションフック一覧を参照します。

しかし Codex に詳しく載ってないような、マニアックな
フィルタフック・アクションフックを探したい時は、
どうすれば良いでしょうか?

私の場合は WordPress のソースから使えそうな
アクションフック・フィルタフックを探します。

ただし、WordPress のソースを頭から全部読んでたら
日が暮れるので、それらしいところのニオイを嗅ぎ分ける
鼻を養う必要があります。

その辺のノウハウを実際の例を交えて簡単に説明します。

WordPress ソースの探索

以下の2点に注意して、WordPress ソース内を探検していきます。
使用する武器は grep 辺りが適切でしょう。

他の方法としては wp-includes/default-filters.php を眺めて見るのもアリです。
このファイルを眺めると、デフォルトで登録されているフィルタフックが確認できます。

似たようなことをしている既存の WordPress プラグインのソースを見ても良いでしょう。
その場合は add_filter(), add_action() を探してみてください。

では、使えるプラグインフックの探索方法を実例を交えて紹介します。

RSSフィードに独自のテンプレートを適用できるか?

RSSフィード用のテンプレートは、コアファイルにしか存在
しないため、通常の WordPress テーマでは、RSSフィードは
カスタマイズできません。
しかし、これを変更して右上にアイコンを表示したいとかの
要望が出てきたらどうすれば良いでしょうか?

これは、適切なプラグインフックを使用することで実現できます。

フィードのテンプレートとしては wp-includes/feed-rss.php が読み込まれています。
これは、使用しているテーマに関わらず固定です。

WordPress のソースを grep して feed-rss.php を読み込んでいるところを探索しましょう。

→ wp-includes/functions.php の do_feed_rss() で読み込んでますね。

/**
 * Load the RSS 1.0 Feed Template
 *
 * @since 2.1.0
 */
function do_feed_rss() {
	load_template( ABSPATH . WPINC . '/feed-rss.php' );
}

続いて、この do_feed_rss() 関数を呼び出しているところを探索しましょう。

→ wp-includes/default-filters.php の中で
 add_action('do_feed_rss', 'do_feed_rss', 10, 1); していますね。

// 2 Actions 2 Furious
add_action( 'do_feed_rdf',                'do_feed_rdf',             10, 1 );
add_action( 'do_feed_rss',                'do_feed_rss',             10, 1 );
add_action( 'do_feed_rss2',               'do_feed_rss2',            10, 1 );
add_action( 'do_feed_atom',               'do_feed_atom',            10, 1 );
add_action( 'do_pings',                   'do_all_pings',            10, 1 );
add_action( 'do_robots',                  'do_robots'                      );
add_action( 'sanitize_comment_cookies',   'sanitize_comment_cookies'       );
add_action( 'admin_print_scripts',        'print_head_scripts',      20    );
add_action( 'admin_print_footer_scripts', 'print_footer_scripts',    20    );
add_action( 'admin_print_styles',         'print_admin_styles',      20    );
add_action( 'init',                       'smilies_init',             5    );
add_action( 'plugins_loaded',             'wp_maybe_load_widgets',    0    );
add_action( 'plugins_loaded',             'wp_maybe_load_embeds',     0    );
add_action( 'shutdown',                   'wp_ob_end_flush_all',      1    );
add_action( 'pre_post_update',            'wp_save_post_revision'          );
add_action( 'publish_post',               '_publish_post_hook',       5, 1 );
add_action( 'future_post',                '_future_post_hook',        5, 2 );
add_action( 'future_page',                '_future_post_hook',        5, 2 );
add_action( 'save_post',                  '_save_post_hook',          5, 2 );
add_action( 'transition_post_status',     '_transition_post_status',  5, 3 );
add_action( 'comment_form', 'wp_comment_form_unfiltered_html_nonce'        );
add_action( 'wp_scheduled_delete',        'wp_scheduled_delete' );

このアクションフック do_feed_rss を実際に起動している
箇所を探索しましょう。

→ wp-includes/functions.php の do_feed() 内で
  'do_feed_' . $feed を do_action() しています。

function do_feed() {
	global $wp_query;

	$feed = get_query_var( 'feed' );

	// Remove the pad, if present.
	$feed = preg_replace( '/^_+/', '', $feed );

	if ( $feed == '' || $feed == 'feed' )
		$feed = get_default_feed();

	$hook = 'do_feed_' . $feed;
	if ( !has_action($hook) ) {
		$message = sprintf( __( 'ERROR: %s is not a valid feed template' ), esc_html($feed));
		wp_die($message);
	}

	do_action( $hook, $wp_query->is_comment_feed );
}

do_feed() 関数を実際に呼んでいるところを探索しましょう。

→ wp-includes/template-loader.php の中で is_feed() なら、
  この関数を呼んでますね。

if ( defined('WP_USE_THEMES') && constant('WP_USE_THEMES') ) {
	do_action('template_redirect');
	if ( is_robots() ) {
		do_action('do_robots');
		return;
	} else if ( is_feed() ) {
		do_feed();
		return;
	} else if ( is_trackback() ) {
		include(ABSPATH . 'wp-trackback.php');
		return;
	} else if ( is_404() && $template = get_404_template() ) {
		include($template);
		return;
	} else if ( is_search() && $template = get_search_template() ) {
		include($template);
		return;
	} else if ( is_tax() && $template = get_taxonomy_template()) {
		include($template);
		return;

これで、RSS フィードがリクエストされた場合、
WordPress が以下の動作をすることがわかりました。

  1. フィードがリクエストされたら do_feed() 関数を呼び出す
  2. do_feed() 関数が 'do_feed_rss' アクションフックを呼び出す
  3. アクションフックとして登録された do_feed_rss() 関数が動作する
  4. ABSPATH . WPINC . '/feed-rss.php' をテンプレートとしてロードする

do_feed_rss() 関数の中では、テンプレートファイルは「ABSPATH . WPINC . '/feed-rss.php'」固定です。
しかし、この do_feed_rss() 関数はアクションフックとして登録されているため、このアクションフックをリムーブ後、独自のアクションフックを登録すれば、目的のことができそうですね。

というわけで、テーマフォルダ内にあるRSSフィード用テンプレート(feed-rss.php)を読み込むプラグインができました。

// デフォルトアクションフック リムーブ
remove_filter('do_feed_rss', 'do_feed_rss', 10);

// アクションフック 追加
function custom_feed_rss( $for_comments ) {
	$template_file = '/feed-rss' . ( $for_comments ? '-comments' : '' ) . '.php';
	$template_file = ( file_exists( get_template_directory() . $template_file )
		? get_template_directory()
		: ABSPATH . WPINC
		) . $template_file;
	load_template( $template_file );
}
add_action('do_feed_rss', 'custom_feed_rss', 10);

他のフィード ( rss2, atom ) についても、同様にしてやれば安心です。

WordCamp Yokohama 公式サイトのプロフィール登録画面のカスタマイズも、プラグインフックを登録するだけで実現しています。

公式サイトのプロフィール登録画面で使用しているプラグインフックは以下のとおりです。

プラガブルファンクション