[_s] functions.phpの構成

WordPressのfunctions.phpは、テーマの中で共通して使われる関数をまとめたファイルです。 テンプレートファイルとは役割が異なり、その名前の通りテーマに色々な機能を与えるために使われます。

_sでは、functions.php、またfunctions.phpがrequireするphpファイルから成り立っています。

PHPマニュアル require

functions.phpにはたくさんの関数が書かれていますが、それぞれは大きく以下の構成に従って書かれており、それぞれのまとまりを作っています。

  1. 追加したい機能
  2. 追加したい機能がすでに定義されているか確認
  3. あるタイミングでその関数を実行したい場合は登録

コードとしては具体的には下のような構成になっていて、追加したい機能ごとにこの組み合わせを繰り返します。(もちろん、追加したい機能だけを書く場合もあります)

// 2.以前に定義されているかを確認する。
if ( ! function_exists( '_s_hoge' ) ) :

  function _s_hoge() {
    // 1.追加したい機能を書く。
  }

endif;

// 3.あるタイミングに対してその関数を実行する場合は登録する。
add_action( 'タイミング名', '_s_hoge' );
//戻り値を使いたい場合は add_filter( 'タイミング名', '_s_hoge' ) を使う

追加したい機能

追加したい機能をコードで記述します。

以前に定義されているかを確認

if ( ! function_exists( ‘_s_hoge’ ) ) は、そのまま「’s_hoge’という関数がない場合は以下に進んでください」という意味で、同名の関数がこのファイル以前に定義されていないかを確認しています。

wordpressに限らずphpでは、同じ名前の関数を2つ読み込もうとすると、fatal error が発生してそこで処理を止めてしまうので、一般的に関数の衝突を避けるためにこういう書き方をするそうです。

しかし、_sでは、この関数の衝突を避けるというのが目的ではないようです。もしこの目的であるならば、functions.phpで定義する全ての関数でこの確認を行うはずですが、_sではこの確認を行っている箇所と行っていない箇所があります。

それではなぜわざわざ以前に定義されている関数かどうかの確認をするかというと、子テーマを作る時(そのテーマを引き継いで新しいテーマを作る時)、その関数の置き換えを簡単に行えるようにするためだそうです。

codexには以下のように書かれています。

The fact that a child theme’s functions.php is loaded first means that you can make the user functions of your theme pluggable —that is, replaceable by a child theme— by declaring them conditionally.

子テーマのfunctions.phpが先に読み込まれるということは、関数を条件分岐するように宣言しておくことで、親テーマの関数をpluggableに、つまり子テーマによって置き換え可能にすることができます。

if ( ! function_exists( 'theme_special_nav' ) ) {
    function theme_special_nav() {
        //  Do something.
    }
}

In that way, a child theme can replace a PHP function of the parent by simply declaring it beforehand.

こうすることで、子テーマはただ単純に関数を宣言するだけで、親テーマのPHP関数を置き換えることができます。

https://developer.wordpress.org/themes/advanced-topics/child-themes/

WordPressでは子テーマを使う際に、functions.phpでは、子テーマのfunctions.php → 親テーマのfunctions.phpという順で読み込まれます。そこで、親テーマで function_exists を使って子テーマでその関数が定義されていない場合はその関数を実行すると書いておくことで、子テーマで同じ名前を使って関数を簡単に置き換えることができるようになります。

add_action()とadd_filter()

以前、header.phpで確認をしましたが、headerで読み込まれるwp_head()という関数は、ヘッダー部分で必要な様々なタグを書き出すために使われます。

このwp_head()関数は、/wp-includes/general-template.php で do_action( ‘wp_head’ ) と定義されていました。そして、この ‘wp_head’ は、 /wp-includes/default-filters.php に、add_action( ‘wp_head’, ‘_wp_render_title_tag’, 1 ) …で登録されていました。

functions.phpでは、このwp_head()の仕組みと同じような、WordPress全体で行われている、特定のタイミングで特定の処理を行う仕組みを、独自に定義することができます。

つまり、既に定義されている do_action( タイミング名 ) を読み込みタイミング、または自分で定義した do_action( タイミング名) を読み込むタイミング で、add_action( タイミング名, 処理 ) と書かれた処理を実行することができます。

多くのタイミングがWordPress本体に既に定義/登録されているので、普通はこれら既に定義されているタイミングにadd_actionで処理を追加することで対応できます。

ちなみに、このadd_actionで処理を追加することを処理をhookすると表現したり、タイミングのことをhookと言ったり、少しややこしいですが、どのように実行されているのか、単純に考えるのが良いと思います。

アクションとフィルターの違い

add_action() と同じような関数で、add_filter() があります。この2つの関数は実際はほとんど同じで、違いは戻り値があるかないだけです。add_action関数自体、add_filterを使うことで書かれていますというか、ほぼそのままadd_filter関数です。

https://developer.wordpress.org/reference/functions/add_action/#source

add_action()とadd_filter()の違いについては、以下の記事でとても分かりやすく説明されています。

add_action()とadd_filter()の違いはサブルーチンとファンクションの違いのようなもの