wp_get_theme内で利用されているget_raw_theme_rootという関数

get_raw_theme_root関数は$wp_theme_directoriesの配列数をチェックしている

$wp_theme_directoriesをregister_theme_directoryで操作している場合は注意

ブログ単位でテーマディレクトリを分けてマルチサイトを運用する方法を模索中なのだが、

管理画面からテーマの有効化やライブプレビューを行った際に「間違えましたか?」というWordPress特有の現象に遭遇した。

テーマディレクトリの分割を実装するにあたり、マルチサイト初期化プラグインで以下のカスタマイズを行っている。

  • theme_rootフィルターの利用
  • register_theme_directoryでブログ毎に異なるテーマフォルダを指定

そして、$wp_theme_directoriesの内部を固有のパスのみにしていたのだが、

array(1) {
  [0]=>
  string(62) "C:\xampp\htdocs\vhost\wordpress3.8ja2/wp-content/themes/sites/5"
}

この状態にしておくと、

テーマの有効化やライブプレビューがうまく動作しない。

theme-activate-preview

WordPress管理画面の

外観 → テーマ

で上の画像にある有効化やライブプレビューを実行すると以下のエラーになるという現象。

chin-up

この原因を調べるために、まずリクエストURLを参考にWordPressを調べた。

sub1.blog.local/wp-admin/themes.php?action=activate&stylesheet=twentyfourteen&_wpnonce=c9f6f1d5e3

上のURLがテーマを有効化するためのURLになっている。

themes.php内部の冒頭付近でwp_get_themeという関数が利用されているのだが、この関数内部で利用されている

get_raw_theme_root

という処理に原因があった。

get_raw_theme_root内では$wp_theme_directoriesの配列数をチェックしている

get_raw_theme_root内部では$wp_theme_directoriesの配列数をチェックしており、配列数が1もしくは0の場合には、wordpressデフォルトのテーマディレクトリを返す仕様になっている。

そのため、$wp_theme_directoriesをブログサイト毎に異なるディレクトリパスにカスタマイズしていたとしても、配列数が1つしかなければ、

return '/themes';

というテーマディレクトリをデフォルトのパスで上書きする処理が返される。その結果、デフォルトディレクトリ内に有効化しようとしているテーマが見つからずエラーになるという現象。

get_raw_theme_rootは、以下のパスに配置されているファイル内で定義されている。

wp-includes\theme.php

$wp_theme_directoriesにダミーのパスを追加することで対処

register_theme_directory関数の処理は、パスの追加であって置き換えではない。そのため、register_theme_directoryを一度実行すると、デフォルトのパスとカスタマイズしたパスというデータ構造になる。

しかし、このデータ構造だと双方のパスからテーマを合算して管理画面で表示するという状態になってしまう。そのため、上で示したようにカスタマイズしたパスのみが配列に格納された状態にするため、あえてデフォルトのテーマディレクトリを削除する処理を行っていた。

デフォルトのテーマディレクトリを削除することで、テーマの合算表示問題を克服することができるが、先に述べたget_raw_theme_root内で$wp_theme_directoriesの配列数が1つしかないため、

return '/themes';

でテーマフォルダが上書きされてしまい、

「間違えましたか?」

というエラーになるというデバッグするのが難しい状況を作り出していた。

問題への対処方法

$wp_theme_directoriesという変数の状態によりget_raw_theme_root内でカスタマイズしたテーマディレクトリが上書きされてしまうことが原因なので、$wp_theme_directoriesの配列数を偽装することで対処した。

下のようになっている問題が生じさせている配列を

array(1) {
  [0]=>
  string(62) "C:\xampp\htdocs\vhost\wordpress3.8ja2/wp-content/themes/sites/5"
}

以下のように偽装することにした。

array(2) {
  [0]=>
  string(62) "C:\xampp\htdocs\vhost\wordpress3.8ja2/wp-content/themes/sites/5"
  [1]=>
  string(62) "C:\xampp\htdocs\vhost\wordpress3.8ja2/wp-content/themes/dummy"
}

dummyという空のフォルダを作成しておき、その階層をregister_theme_directoryでテーマフォルダとして登録し、上のようなデータ構造を作り出せば、get_raw_theme_root内の配列チェックをスルーすることができる。

この方法により

  • テーマの有効化
  • ライブプレビュー

双方の処理が行えるようになった。

Webエンジニアブログにコメント

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

wp_get_theme内で利用されているget_raw_theme_rootという関数の記事にコメントを投稿