【WordPress】子テーマでfunctions.phpを正しく拡張する方法

WordPress

子テーマでfunctions.phpを拡張すると、親テーマのアップデートに影響されずに安全なカスタマイズを積み重ねられます。読み込み順やフックの使い方、親子でのパス解決、スタイルの継承方法を正しく押さえておくと、将来の保守が容易になり不具合の混入も避けられます。

子テーマのfunctions.phpが読み込まれる順序と基本原則

WordPressは子テーマのfunctions.phpを先に読み込み、その後に親テーマのfunctions.phpを読み込みます。この順序を前提に、子側では「新規の機能追加」や「親で用意されたフックの上書き」などを実装します。直接親テーマのファイルを書き換える必要はなく、必ず子テーマ側に処理を集約します。

子テーマの準備と最低限のファイル

子テーマ用ディレクトリを作成し、style.cssにヘッダーコメントでTemplateに親テーマのディレクトリ名を指定します。functions.phpは空でもかまいませんが、後述のスタイル継承を正しく定義すると運用が安定します。

/*
 Theme Name: 親テーマ名 Child
 Template: parent-theme-slug
*/

親テーマのスタイルを正しく継承する

多くの親テーマは独自のハンドル名でCSSをenqueueしています。子テーマでは親のハンドルを依存にして子のCSSを後から読み込むのが安全です。親のハンドルが不明な場合は親テーマのfunctions.phpを確認し、適切なハンドルに合わせて依存を設定します。

<?php
add_action('wp_enqueue_scripts', function () {
  $parent_handle = 'parent-style'; // 親テーマが実際に使っているハンドル名に合わせる
  // 親のCSSを念のため読み込む(親側で既に読み込まれていれば二重読み込みは避ける)
  if (!wp_style_is($parent_handle, 'enqueued')) {
    wp_enqueue_style(
      $parent_handle,
      get_template_directory_uri() . '/style.css',
      [],
      filemtime(get_template_directory() . '/style.css')
    );
  }
  // 子のCSSを後から読み込み、親に依存させる
  wp_enqueue_style(
    'child-style',
    get_stylesheet_directory_uri() . '/style.css',
    [$parent_handle],
    filemtime(get_stylesheet_directory() . '/style.css')
  );
}, 20);

子テーマでのスクリプトやCSSの追加読み込み

子テーマ固有のアセットはget_stylesheet_directory_uriを使って参照します。親テーマのアセットを参照したい場合はget_template_directory_uriを使います。filemtimeをバージョンに用いるとキャッシュが自動更新されます。

<?php
add_action('wp_enqueue_scripts', function () {
  wp_enqueue_script(
    'child-common',
    get_stylesheet_directory_uri() . '/assets/js/common.js',
    ['jquery'],
    filemtime(get_stylesheet_directory() . '/assets/js/common.js'),
    true
  );
});

親テーマ機能の拡張と上書きの考え方

親テーマがフックで提供している振る舞いはremove_actionやremove_filterでいったん外し、子テーマ側で置き換えるのが安全です。親テーマの読み込みは子の後なので、remove_*はinitなど十分後段のフックで実行すると安定します。

<?php
add_action('init', function () {
  // 例:親テーマが登録したフックを外して差し替える
  remove_action('wp_head', 'parent_theme_head_meta', 10);
  add_action('wp_head', 'child_theme_head_meta', 10);
});
function child_theme_head_meta() {
  echo '<meta name="format-detection" content="telephone=no">' . "\n";
}

親テーマがfunction_existsでガードした関数(いわゆるプラッガブル関数)を持っている場合、同名関数を子テーマで先に定義すれば上書きできます。ガードのない関数は再定義できないため、必ずフック経由の拡張を選びます。

<?php
if (!function_exists('parent_helper_title')) {
  function parent_helper_title() {
    // 子テーマ側の実装が優先される
  }
}

get_template_*とget_stylesheet_*の正しい使い分け

親テーマのパスやURLはget_template_directoryとget_template_directory_uri、子テーマのパスやURLはget_stylesheet_directoryとget_stylesheet_directory_uriを使います。親子いずれかを自動解決してほしい場合はget_theme_file_pathとget_theme_file_uriが有効で、子テーマに同名ファイルがあれば子を、なければ親を返すため、モジュール分割や差し替えに強い構成になります。

<?php
// 子テーマに inc/seo.php があればそちらが優先される
$seo_file = get_theme_file_path('inc/seo.php');
if (file_exists($seo_file)) {
  require_once $seo_file;
}

after_setup_themeでの初期化は優先度で調整する

親子の両方でafter_setup_themeを使う場合、子テーマで親の設定を上書きしたいときはより遅い優先度を指定して呼び出します。これによりサムネイルサイズやメニュー登録などを後から上書きできます。

<?php
add_action('after_setup_theme', function () {
  add_theme_support('post-thumbnails');
  add_image_size('thumb-wide', 1200, 675, true);
}, 20); // 親より遅く

翻訳ファイルの読み込みとテキストドメイン

子テーマで独自の翻訳を用意する場合はload_child_theme_textdomainを使います。テキストドメインは親と子で一致させると置き換えが効きやすく、languagesディレクトリにmoファイルを配置しておきます。

<?php
add_action('after_setup_theme', function () {
  load_child_theme_textdomain('parent-textdomain', get_stylesheet_directory() . '/languages');
}, 5);

テンプレート階層と関数の責務分離

見た目やマークアップの変更はsearch.phpやsingle.phpなどテンプレートで、ロジックやフックの変更はfunctions.phpで、という役割分担を守ると保守性が高まります。functions.phpが肥大化する場合はincディレクトリを作り、require_onceで役割ごとに分割するのが定石です。get_theme_file_pathを使えば親子差し替えにも強く、子テーマから同名のモジュールで置き換えが可能です。

管理画面だけに適用する調整と読み込み漏れの防止

管理画面固有のCSSやJSはadmin_enqueue_scriptsで、投稿画面など特定画面のみに限定して読み込みます。hook名や$hook値の取り違えが多いため、get_current_screenでの判定を併用すると安全です。

<?php
add_action('admin_enqueue_scripts', function ($hook) {
  $screen = function_exists('get_current_screen') ? get_current_screen() : null;
  if ($hook === 'post.php' || $hook === 'post-new.php' || ($screen && $screen->id === 'settings_page_child-options')) {
    wp_enqueue_style('child-admin', get_stylesheet_directory_uri() . '/assets/admin.css', [], filemtime(get_stylesheet_directory() . '/assets/admin.css'));
  }
});

よくある落とし穴と実務での回避策

親テーマのハンドル名不一致で依存関係が崩れ、子テーマのCSSが正しく後勝ちしないケースはよく発生します。enqueueの依存に親の正しいハンドルを指定すること、バージョンにfilemtimeを使ってキャッシュを確実に更新すること、remove_actionが効かない場合は親がフックしている優先度を確認して同じかそれより後でremoveすること、get_template_*とget_stylesheet_*の取り違えを避けて参照先を明確にすることが安定運用の鍵になります。

まとめ

子テーマのfunctions.phpは「親の更新に強い拡張点」として使い、スタイルは親への依存を明示して後から読み込み、機能拡張はフックで差し替え、パス解決は親子自動解決の関数を活用するのが基本方針です。読み込み順、依存関係、フック優先度、パス関数の使い分けを押さえれば、親テーマの恩恵を受けつつ安全にカスタマイズを積み上げられ、長期運用でも壊れにくいテーマ構成を実現できます。