WordPressの子テーマを作成する時にハマった3つのこと

  • 更新日:
  • 公開日:

「WordPressの子テーマ作成なんて簡単でしょ」と侮っていたらハマったお話です。

3つの点で躓きました。

 「Template」の指定はフォルダ名で

子テーマとして認識させるにはstyle.cssが必要です。このスタイルシートには最低限、

/*
Theme Name: childtheme
Template: twentyfourteen
*/

という2行の記述をしておく必要があります。この「Template」の項目は親テーマのフォルダ名を指定しましょう。間違えると以下のエラーが発生してしまいます。

「壊れているテーマ
以下のテーマはインストールされていますが不完全です。テーマにはスタイルシートとテンプレートが一つずつ必要です。
親テーマが見つかりません。”◯◯” の親テーマをインストールしてください。」

例えば自分は「Template」の項目に親テーマの名前(style.cssで設定されたテーマ名)を入力しちゃいました。これでは駄目なんですね、フォルダ名を指定しましょう。

child-theme-bewildered01
このようなエラーが出ます

テーマディレクトリを取得する関数に注意

CSSやJavaScriptを読み込むためにURL指定する時、テーマのディレクトリを取得するためget_template_directory_uri()を使いますよね。

しかし、この関数を子テーマのテンプレートで使用すると親テーマのディレクトリURLが返ってきてしまいます。

ではどうするのかというと、子テーマではget_stylesheet_directory_uri()を使えば子テーマのディレクトリURLが返ってきます。

参考: 関数リファレンス/get stylesheet directory uri – WordPress Codex 日本語版

functions.phpは上書きされない

基本的に子テーマは(親テーマのテンプレートを継承するので)style.cssだけで動きます。

WordPressに必要なテンプレートが子テーマに無い場合、親テーマのテンプレートを参照します。そして手を加えたいテンプレートのみ、親テーマから子テーマのフォルダへコピーして書き変えます。子テーマにテンプレートがあった場合、親テーマのテンプレートを上書きするイメージです。

このような感じで必要なテンプレートをどんどん親テーマからコピーして良いのですが、1つだけ例外があります。それはテーマ用の関数をまとめるfunctions.phpです。

functions.phpだけは親テンプレートの上書きがされず、

  1. 子テーマのfunctions.php
  2. 親テーマのfunctions.php

という順番で読み込まれる仕様になっています(上書きされません)。なので、例えば継承元の親テーマのfunctions.phpが子テーマ作成に対応したソースコードになっていなければ、テンプレートをそのままコピーしてしまうとPHPエラーが発生します。

どうしてそのままコピーするとエラーが発生するかというと、上書きされず順番に読み込まれてしまうのでfunctions.phpに書かれた、主に関数(その他ではクラスやグローバルな変数など)が二度定義されることになってしまうのです。二重定義が起こるとPHPはエラーを吐きます。

この問題を解決する方法は3つ

この関数の二重定義を回避する方法は3つあります。それは、

  1. 子テーマのfunctions.phpから関数(やその他被ったら困るソースコード)を削除する
  2. 関数名を変更する
  3. 既に定義されているかを調べるPHPの関数で回避する

です。

1つ目は特別なことが無ければコピーしてきたfunctions.phpの中身を全部削除しちゃっても良いと思います。「あ、これ必要だった」と気付いたらまたコピペで良いでしょう。

1,2の方法で大体の場合はOKなのですが、3つ目の「PHPの関数で回避する」というのはどういう状況で必要かというと、子テーマが作成されることを想定している時なんですね。

この二重定義を回避するには、関数が既に定義されているか調べる関数function_exists()でif判定する必要があります。(クラスを使用する方法もあります。)

例えば

functions.phpをそのまま子テーマにコピーした例を示してみます。

 親テーマのfunctions.php

//タイトルの文字数制限 by 親テーマ
add_filter('the_title', 'my_the_title', 10, 2);
function my_the_title($title, $id) {
    $title = mb_strimwidth($title, 0, 80, "…","UTF-8");
    return $title;
}

親テーマのfunctions.phpが上記のようになっていて、これをそのまま子テーマにコピーするとfunctions.phpの内容は以下のようになります。(もちろん子テーマを有効化している場合ですね)

//タイトルの文字数制限 by 親テーマ
add_filter('the_title', 'my_the_title', 10, 2);
function my_the_title($title, $id) {
    $title = mb_strimwidth($title, 0, 80, "…","UTF-8");
    return $title;
}

//タイトルの文字数制限 by 親テーマ
add_filter('the_title', 'my_the_title', 10, 2);
function my_the_title($title, $id) {
    $title = mb_strimwidth($title, 0, 80, "…","UTF-8");
    return $title;
}

先述した通り同じ関数が2つ出来上がってしまい、二重定義となりエラーになります。なので先ほど挙げた関数function_exists()の出番です。この関数に引数として渡した文字列の関数名が既に定義されていた場合、TRUEが返ってくるのでコレを利用します。

//タイトルの文字数制限 by 親テーマ
if (!function_exists('my_the_title')) {
    add_filter('the_title', 'my_the_title', 10, 2);
    function my_the_title($title, $id) {
        $title = mb_strimwidth($title, 0, 80, "…","UTF-8");
        return $title;
    }
}

こうすることで関数の二重定義を防げます。

子テーマが作成される、もしくは作成されるかもしれない場合はこの点に注意したいですね。(WordPressのデフォルトテーマは子テーマが作成されることを想定し、同様の処理がされています)

参考: PHP: function_exists – Manual

photo credit: thisismyurl via photopincc

書いた人

Symbol Mark

Ryoichi(しつ)

除菌ティッシュを買い込んで使いきれずによく乾かす人。

療養目的で退職し、どうやって生きていくか模索中。最近は勉強目的でLaravelやVue.js弄ったり、趣味で音で遊んでます。

※2019年10月16日現在ブログリニューアル中です。崩れなどが発生していたらすみません。

うぇぶ: @s_ryone