WordPress で機能を追加するにはプラグインがいいか、functions.php に書くほうがいいかという疑問があります。私はプラグインほぼなしの自作テーマで運用していますので、どうしても functions.php が煩雑になってきます。それを解消する方法として、プラグインにするのではなく、同等の別ファイルにして管理しやすい状態で functions.php に組み込もうと思います。
01プラグインはいつ読み込まれるのか…
WordPress に機能を追加する場合にプラグインで追加するか、テーマの functions.php に書くかは、結局、いつ読み込まれるかの違いでしかなく、同じコードであれば基本システムにかける負荷は同じだと思います。
まずそれを確認するためにプラグインや functions.php がいつ読み込まれるのかみてみましょう。WordPress のバージョンは 6.6 です。
WordPress が各種ファイルを読み込む順序は、
index.php → wp-blog-header.php → wp-load.php → wp-config.php → wp-settings.php
とすべてルートディレクトリ直下のファイルで進み、この wp-settings.php からは wp-includes ディレクトリのファイルを読み始めます。プラグインも wp-settings.php の中で処理されます。その512行目からのコードです。
// Load active plugins.
foreach ( wp_get_active_and_valid_plugins() as $plugin ) {
wp_register_plugin_realpath( $plugin );
$_wp_plugin_file = $plugin;
include_once $plugin;
$plugin = $_wp_plugin_file; // Avoid stomping of the $plugin variable in a plugin.
/**
* Fires once a single activated plugin has loaded.
*
* @since 5.1.0
*
* @param string $plugin Full path to the plugin's main file.
*/
do_action( 'plugin_loaded', $plugin );
}
有効なプラグインがあれば順番に読み込んでいます。そして、do_action という関数が登場します。これは wp-settings.php の中で先立って読み込まれる wp-includes/plugin.php の中で定義されている関数で、add_action を呼び出すためのアクションフックポイントを定義するものなんですが、この do_action( ‘plugin_loaded’, $plugin ) は何をしているのでしょう。各プラグインファイルを引数にして plugin_loaded アクションフックを設定しているということだと思いますが、これが何をしているのか今のところよくわかりません。plugin_loaded のアクションフックはシステムファイルの中でも使われていません。
とにかく、ここで有効なプラグインを読み込んでいることはわかりました。そして、もう少しコードを読み進んでいきますと548行目から次のコードがあります。
/**
* Fires once activated plugins have loaded.
*
* Pluggable functions are also available at this point in the loading order.
*
* @since 1.5.0
*/
do_action( 'plugins_loaded' );
ここで plugins_loaded というアクションフックポイントが設定されています。ただ、ここではまだテーマの functions.php は読み込まれていませんので、このアクションフックポイントを使いたい場合はプラグインの中で使うしかありません(多分…)。と思うんですが、であればプラグインそのものにやりたいことを書けばいいわけですから、これ、どういう使い方をするんでしょう。多分基本システムの中で使われているんだと思います。
確かにシステムファイル内を全文検索しますと、10ファイルくらいヒットしますので、結構使われているようです。折があれば調べてみましょう。
02テーマの functions.php はいつ読み込まれるのか…
さらに読み進みますと、625行目からの行にやっと setup_theme というアクションフックポイントが登場します。ただ、これも functions.php 読み込み前のアクションフックポイントです。全文検索しますと数ファイルがヒットしますのでシステム内で使われているようです。
/**
* Fires before the theme is loaded.
*
* @since 2.6.0
*/
do_action( 'setup_theme' );
そして、やっと665行目にテーマディレクトリの functions.php の読み込みコードが登場します。また、テーマ読み込み後には after_setup_theme のアクションフックポイントが設定されています。
// Load the functions for the active theme, for both parent and child theme if applicable.
foreach ( wp_get_active_and_valid_themes() as $theme ) {
if ( file_exists( $theme . '/functions.php' ) ) {
include $theme . '/functions.php';
}
}
unset( $theme );
/**
* Fires after the theme is loaded.
*
* @since 3.0.0
*/
do_action( 'after_setup_theme' );
という流れですので、もしアクションフックを使ってプラグインと同等の機能を追加しようと思いますと、この after_setup_theme 以降になります。その直後には do_action( ‘init’ ) のアクションフックポイントがありますので、アクションフックを使う場合は init が最適だと思います。
ただ、何もわざわざアクションフックを使わなくても functions.php を読み込む際に一緒に読み込めばいいという考えもあるわけで、結局、次の方法をとることにしました。functions.php の最初に自作の追加機能ファイルを読み込んでおけばプラグインと同等ということになります。
03functions.php の最初にプラグインを読み込む…
ということで、functionsphp の最初に次のように書けば自作プラグインを読みことができます。
<?php
if (! defined('ABSPATH')) {exit;}
// 自作クラスなど関数ファイルの読み込み
$imz_files = glob(dirname(__FILE__) . '/inc/imz-*.php');
foreach($imz_files as $file) {
include_once ($file);
}
// 以下、add_action など自作コード
テーマディレクトリに inc ディレクトリをつくり、そこに自作ファイルを保存しておきます。そうしますと functons.php が読み込まれた時、まず最初に inc ディレクトリ内のファイルから glob関数でパターンにマッチするファイルを取り出し、順次読み込まれます。
たとえば、前記事で公開した「WordPress:Amazonアソシエイトリンク作成プラグイン」は inc/imz-associate-link.php として保存しておきます。
<?php
/*
* Plugin Name: imz-associate-link
* Plugin URI: https://imuza.com
* Description: amazon のアソシエイトリンクをショートコードから作成する
* Version: 1.0.0
* Author: imuza
* Author URI: https://imuza.com
* License: GPLv2
*/
if (! defined('ABSPATH')) { exit; }
class ImzAssociateLink
{
private $wpdb;
private $table;
static function init()
{
return new self();
}
public function __construct()
{
// 以下略
}
ImzAssociateLink::init();
これで望み通りのテーマ管理ができるようになります。つまり、テーマディレクトリさえ移せば同じサイトができるということであり、追加機能もひとつずつ切り離されていますので見通しがよくなりメンテナンスもしやすいということです。
ということで functions.php の整理に取り掛かりましょう。