テーマカスタマイザーのスタイルを外部CSSにする

リニューアル用のテーマを作っているときに、当お題目をやろうとして悩んだこと。

 

通常、WordPressでテーマカスタマイザーでは、$wp_customizeを使ってカスタマイズ項目を並べていく。

で、こいつを実際にユーザーが見るページに反映させようとすると、wp_headかwp_footerにフックして<style></style>を出力。

そして、カスタマイザーで設定したスタイルをこの中に書いていかなければならないと言う状態になってしまう。

 

自分もこのならいに則って今まで同じようにしぶしぶCSSを前時代的に書き出ししていた。

wp_headにフックした際はこれだと設定できるスタイル項目を増やすと<head></head>の中でえらい文字数になる。

かといって、wp_footerでフックしようものなら、transitionとかを行っている要素部分で遅延したアニメーションが発生してしまう。

 

カスタマイザーを本格的に使い出すようになって、ああこれどうしようもねーやみたいなことを思っていたが、同時にこれはとても引っかかっていた部分だ。

今回のリニューアルで、その辺も少しステップアップしようかと思い、このスタイルを外部CSSとして扱うようにしたいと思った。

 

で、「wordpress カスタマイザー 外部CSS」のキーワードで偉大なGoogle先生にお尋ねしたものの・・・

 

既に俺が知っている情報と、プラグイン情報しか出ねぇ・・・

 

いやいや、それでも同じようなこと考えてる人は絶対にいるだろうし、少しはあるでしょ?と思って10分ほど調べてみたがうんともすんとも。

 

結論:じゃあ作るか。

 

で、どういう手順でそいつを書き出すかをまずは練った。

 

  1. 従来通りの方法で、$wp_customizeを使って項目に設定したスタイルシートの文字列を作っておく。
  2. そいつをset_theme_modでテーマ用のオプション値(theme_mod)へ保存させる。
  3. どのタイミングで保存させるか?そりゃもちろんテーマカスタマイザーで保存をした後でしょう。
  4. オプション値を参照させて外部CSS内のスタイルシートの文字列を動的に出力する。
  5. 従来の<style></style>を書いていたところで生成した外部CSSを<link href=”” />で呼んでやる。

 

3を飛ばして1→2→4→5はうまく行った。

 

で、問題は3のテーマカスタマイザーで保存をした後にどうやってテーマ用のオプション値(theme_mod)を挿入&更新してやるか。

ここが俺の一番の問題だった。WordPressのことならなんでも書いてるWordPressのコーデックスへGO。

 

customize_registerだとかcustomize_preview_initその他ちょこっとしか書いてなかった・・・。

いやいや、カスタマイズAPIの使用法のことなんかどうだっていいんだ・・・。こんなのTwentyFifteenからコピーできるし。

 

というわけでカスタマイザーのフックをWordPressの公式(英語)で再度お勉強。

辞書を片手に読む始末。だいぶ前のMagento2で導入したり弄ったりしていた間は多少なりと辞書なくても読めるようにはなっていた。

だが、もうだいぶ時が過ぎたせいでボケた。ふがふが。

 

・・・やっと見つけたよ。

「customize_save_after」ってフックあるじゃん。まんまじゃねーか。

 

ともあれ、これで俺の思っている外部CSSが実現できる・・・ということで、ここからソースコード。

無論、既に$wp_customizeでテーマカスタマイザーでのオプション値の挿入&更新は問題なく設定できるようにしておくことが前提なので割愛。

そして、テーマカスタマイザーとかの設定をfunctions.phpに直書きしている事前提で話は進めようと思う。(自分はお作法にならってカスタマイザー関係はインクルードしてるけど。)

 

テーマカスタマイザーの保存時処理

function theme_customize_save_after($wp_customize){
	$styles = '
	body{
		background-color:'.get_theme_mod('body_background_color', '#ffffff').';
		color:'.get_theme_mod('body_color', '#000000').';
	}
	p{
		color:'.get_theme_mod('visual_body_color', '#000000').';
	}
	';
	$styles = preg_replace('/\r\n|\n|\r|\t/', '', $styles);
 
	set_theme_mod('site_styles', $styles);
}
add_action('customize_save_after', 'theme_customize_save_after');

まずは、一番悩んだ部分からだ。「customize_save_after」でフックしてオプションの保存を実行する。

上記の書き方で、$wp_custmizeでset_theme_modでのオプション値更新が来た後にテーマオプション値の’site_styles’がセットされる。

 

フロントエンドのスタイルシート書き出し(ライブプレビュー用のスタイル枠含む)

function theme_customize_styles(){
	$styles = '<link rel="stylesheet" href="'.get_template_directory_uri().'/theme-css.php'.'" type="text/css" media="all" />';
	if(is_customize_preview()){
		$styles .= '<style type="text/css" id="theme-customize-preview-styles"></style>';
	}
	$styles = preg_replace('/\r\n|\n|\r|\t/', '', $styles);
 
	echo $styles;
}
add_action('wp_head', 'theme_customize_styles');

#theme-customize-preview-stylesは、自分はライブプレビューの際に’postMessage’を使用してスタイルシートをJS使って追記させているから。

まぁそれはどうでもいいが、それより大事なのが、get_template_directory_uri().’/theme-css.php’のところ。

こいつが、テーマオプション値の’site_styles’を元にして動的に生成される外部CSS。そいつを読み込んでいる。

動的なCSSの書き出し

require_once(【wp-load.phpのあるディレクトリ】.'/wp-load.php');
 
header('Content-type: text/css; charset=utf-8');
 
echo get_theme_mod('site_styles');

上記を「theme-css.php」という名前でfunctions.phpと同階層へ配置。

require_once()でインストールしているWordPressのwp-load.phpを読み込む。

 

で、【wp-load.phpのあるディレクトリ】とは書いているが、普通にWordPressを使っている場合、十中十でwp-load.phpはWordPressをインストールしたディレクトリ直下にある。

すなわち、これはインストールしたディレクトリからfunctions.phpを見た場合であれば、WPディレクトリ→wp-contentディレクトリ→themeディレクトリ→テーマ本体のディレクトリとなる。

なので、当該の部分の指定は相対パスで「dirname(__FILE__).’/../../..’」となる。

 

これで「theme-css.php」で、get_theme_modの他、WordPressの関数が全て使用可能になる。

 

そして、これがキモだが、この「theme-css.php」というPHPファイルにはtext/cssヘッダーを付けてブラウザ側にはCSSと認識させる(昔からよくある技法)。無論書いたPHPのコードはちゃんと実行される。

 

以上で、自分の求めていた動作ができるようになった。

 

しかし・・・やはりまだ引っかかるのが、冒頭でも書いたように同じようなこと考えてる人は絶対にいるはずなのに中々それを公開してらっしゃるサイトが見つからないこと。

よくあるWeb制作でのワンオフ型のテーマ作成だと、時短のためにBootstrapにテンプレート関数ぶっこんで行くだけだし、そもそもテーマカスタマイザー自体がワンオフ型の制作には使わない機能なのかもね。

PHPを外部CSSとして扱う手法は昔からあるし、わざわざ書く必要がないからみんな書いてないだけかもしれないけど。

カテゴリ

この記事のコメント

  1. 面白い記事だなと思いました。
    私はインラインに吐き出す方法を調べていたので、むしろファイルに出来るんだーって感心しました。

    テーマカスタマイザーを使うようになると色々悩みますよね・・・

    ただ、気になったのはそこまでやるならtheme-css.cssにしちゃえば良いのでは?と思いました。
    都度cssを吐き出させれば影響も無いのでは?

    ともかく、ありがとうございました。

    1. コメントいただきありがとうございます。

      実はコメントのいただいた通り、当時は実体ファイルの書き出しをできないかとも頭の片隅で考えていました。

      fopenやfwrite等でCSSファイルを生成して書き込むのは確かにカンタンです。
      ただ、WPではMovableType等のCMSと違ってファイルを書き出すタイミングが常に択一・一様というわけはないので、特にカスタマイザーのようにタイミングが不定(手軽に更新できる)だとファイルにデッドロックが生じやすいのです。
      他にもブラウザキャッシュの問題等もあって、しっちゃかめっちゃかになった記憶があります。

      スクリプト系で独自のアプリを作るときにファイルを読み書きする際は、ファイル名を一旦ハッシュ化したり、日付時刻や処理者名等にしてしまって最終的に挿げ替えてそれを回避するのですが・・・。
      そこまでの機能をテーマ側にガリガリとコード書いてパフォーマンスを悪くしたり、リスクを組み込むのも気が引けました。

      そんなわけで、せっかくtheme_modにオプションがあるのならそれを単に読んできて、直接配置してある同一のPHP内でWP同様に動的処理させちゃえば確実だしいいじゃん!ということでこんな仕様になった次第です(´・ω・`)

コメントを残す

メールアドレスが公開されることはありません。