WordPressテーマを作成する時に、機能を追加した後に、別の機能に取り替えたいことがあると思います。テーマに機能が密接に関わっているとコードの変更に手間と不具合を起こしてしまう恐れがあります。
なのでカスタマイズしやすく汎用性の高いものを作ろうと思いました。
今回はその私なりのテーマ作成の考え方を紹介します。
テーマとプラグインの役割を明確にする
WordPressはテーマとプラグインでサイトを構成します。
- テーマ : 表示に関する内容を操るもの
- プラグイン : 機能を拡張するもの
これに準じて、なるべくテーマに機能をもたせず作成することで、プラグインとの衝突を防ぐことがで、多種多様なプラグインを柔軟に使うことができます。
しかし、テーマにあらかじめ機能をつけておきたいケースもあります。
テーマの使い手としては、テーマをインストールしたらすぐに使える状態が望ましいです。インストール後にプラグインを入れて設定を整えるのは煩わしい作業に感じる場合もあります。
また、プラグインによってはテーマのテンプレートファイルに編集を加える必要があるものもあります。これらの対処方法は後述します。
テンプレートファイルに関数や変数を定義しない
テーマに機能を追加しておきたい時は、header.php``footer.php
などのテンプレートファイルには関数や変数などを定義しないようにしています。機能を追加する場合はfunctions.php
を作成しそこへ関数などを定義します。
functions.php
に記述すればテンプレートファイルで使えるように自動で読み込んでくれるので定義した関数を使えるようになります。
テンプレートファイルには主にブラウザに出力されるコードやテキストを書きます。
以下は「パンくずリスト」をテーマに追加する例です。
悪い例
<?php get_header(); ?> <div id="content"> <?php function prefix_breadcrumb() { // パンくずリストのコード echo 'パンくずリスト'; } prefix_breadcrumb(); ?> <?php get_template_part( 'main' ); ?> </div><!-- .#content --> <div id="side"> <?php get_sidebar(); ?> </div><!-- .#side --> <?php get_footer(); ?>
上記はindex.php
に直接定義したものです。このような場合、複数のファイルに散らばって管理しづらく、HTMLと混ざって見通しも悪くなります。
良い例 (1)
<?php function prefix_breadcrumb() { // パンくずリストのコード echo 'パンくずリスト'; }
<?php get_header(); ?> <div id="content"> <?php if( function_exists( 'prefix_breadcrumb' ) ) { prefix_breadcrumb(); } ?> <?php get_template_part( 'main' ); ?> </div><!-- .#content --> <div id="side"> <?php get_sidebar(); ?> </div><!-- .#side --> <?php get_footer(); ?>
function_exists
は、指定した関数が定義されている場合にTRUE
を返すPHPの関数です。関数の定義はfunctions.php
に書いているので、定義されているか確認のために条件分岐しています。もし定義がされていなくても、エラーを出さず実行処理してくれます。
function_exists
について詳しくはPHPドキュメントを参考にしてください。
良い例 (2)
<?php add_action( 'prefix_before_main', 'prefix_breadcrumb' ); function prefix_breadcrumb() { // パンくずリストのコード echo 'パンくずリスト'; }
<?php get_header(); ?> <div id="content"> <?php do_action( 'prefix_before_main' ); ?> <?php get_template_part( 'main' ); ?> </div><!-- .#content --> <div id="side"> <?php get_sidebar(); ?> </div><!-- .#side --> <?php get_footer(); ?>
上記はアクションフックを使ってパンくずリストを表示する例です。あらかじめテンプレートファイルにフックを引っ掛ける場所を仕込んでおけば、関数が定義してあるファイルで有効にしているかどうかわかりやすくなります。テンプレートファイルも見通しが良くなります。
パンくずリストについては以下の記事を参考にしてみてください。
疎結合にする
テーマにも機能をつけたり、プラグインによってテーマに編集が必要な場合は密結合しないように疎結合を意識しています。そうすることで機能やプラグインの入れ替えがしやすくなります。
前述した「テンプレートファイルに関数や変数を定義しない」についてもなるべく密結合しないように機能拡張についてはfunctions.php
に定義し、実行するコードをテンプレートファイルなどに書くようにしています。
以下はテーマに「パンくずリスト」機能を実装していて後に、プラグインの「Breadcrumb NavXT」に変更する場合の例です。
例
WordPressで運営しているサイトに「Breadcrumb NavXT」インストールします。プラグインを有効化します。左サイドの管理メニューから「設定」→「Breadcrumb NavXT」と進「Breadcrumb NavXT」の設定を行います。設定は設定画面の右上の「ヘルプ」を参考にしてみてください。
「テンプレートファイルに関数や変数を定義しない」の良い例 (2)のようにアクションフックを使ったコードの書き方をしておけば、下記のようfunctions.php
で一元管理することが出来ます。
<?php /** * テーマにデフォルトで用意したパンくずリストの機能を * アクションフック「prefix_before_main」に表示する */ // add_action( 'prefix_before_main', 'prefix_breadcrumb' ); function prefix_breadcrumb() { // パンくずリストのコード echo 'パンくずリスト'; } /** * プラグイン「Breadcrumb NavXT」を * アクションフック「prefix_before_main」に表示する */ if( function_exists( 'bcn_display' ) ) { add_action( 'prefix_before_main', 'prefix_bcn' ); function prefix_bcn() { ?> <div class="breadcrumbs" typeof="BreadcrumbList" vocab="http://schema.org/"> <?php bcn_display(); ?> </div> <? php } }
<?php // ~~~ 省略 ~~~ ?> <div id="content"> <?php do_action( 'prefix_before_main' ); // ここにフックされて表示される ?> <?php get_template_part( 'main' ); ?> </div><!-- .#content --> <?php // ~~~ 省略 ~~~
上記コードはテーマにデフォルトで用意したパンくずリストの機能をアクションフックprefix_before_main
に追加していた7行目をコメントアウトして機能しないようにし、「Breadcrumb NavXT」を表示するものを新しく書き加えて、アクションフックprefix_before_main
に追加しています。
function_exists
を使って条件分岐しているのは、もしプラグインを停止または削除したとしてもエラーにならないようにするためです。
元に戻す場合は、functions.php
の7行目のコメントアウトの//
を削除し、18行目のadd_action( 'prefix_before_main', 'prefix_bcn' );
をコメントアウトすればOKです。
または、「Breadcrumb NavXT」が有効の場合は、プラグインのパンくずリストを表示し、停止または存在しない場合はデフォルトのパンくずリストを表示するようには以下のように書くことが出来ます。
<?php /** * テーマにデフォルトで用意したパンくずリストの機能を * アクションフック「prefix_before_main」に表示する */ // add_action( 'prefix_before_main', 'prefix_breadcrumb' ); function prefix_breadcrumb() { // パンくずリストのコード echo 'パンくずリスト'; } /** * プラグイン「Breadcrumb NavXT」を * アクションフック「prefix_before_main」に表示する */ if( function_exists( 'bcn_display' ) ) { add_action( 'prefix_before_main', 'prefix_bcn' ); function prefix_bcn() { ?> <div class="breadcrumbs" typeof="BreadcrumbList" vocab="http://schema.org/"> <?php bcn_display(); ?> </div> <? php } } else { add_action( 'prefix_before_main', 'prefix_breadcrumb' ); }
テンプレートファイルにべったり書かれていた場合と比べると、編集が楽になります。後にまた変更する時にも手間が少なく、ミスによって不具合を起こすことも減らせます。
コーポネント化する
機能や部品ごとににファイルを分けて管理しておくと、どのファイルを編集すればいいか明確にわかり、機能の入れ替えも簡単に行えるようになります。
例
<?php /** * テーマにデフォルトで用意したパンくずリストの機能を * アクションフック「prefix_before_main」に表示する */ // add_action( 'prefix_before_main', 'prefix_breadcrumb' ); function prefix_breadcrumb() { // パンくずリストのコード echo 'パンくずリスト'; } /** * プラグイン「Breadcrumb NavXT」を * アクションフック「prefix_before_main」に表示する */ if( function_exists( 'bcn_display' ) ) { add_action( 'prefix_before_main', 'prefix_bcn' ); function prefix_bcn() { ?> <div class="breadcrumbs" typeof="BreadcrumbList" vocab="http://schema.org/"> <?php bcn_display(); ?> </div> <? php } } else { add_action( 'prefix_before_main', 'prefix_breadcrumb' ); }
<?php require_once locate_template( 'breadcrumbs.php' ); // パンくずリスト関連のファイル
パンくずリストを表示するコードをbreadcrumbs.php
にまとめて、functions.php
に読み込むようにしました。上記のようにしておけばfunctions.php
のrequire_once
している箇所一行をコメントアウトするだけで機能を停止にしておけます。
ファイルの管理方法については以下の記事も参考にしてみてください。
アクションフックとフィルターフックを使う
テンプレートファイルにアクションフックや機能追加のために作成した関数にフィルターフックを入れると、ベースとなるファイルやコードに手を加えず、コンテンツを追加したり挙動を変更したりできます。こうしておくと変更した部分や追加したコンテンツを分けて管理でき、元に戻しやすく何を変更したのか明確になります。
ここまでに何回かアクションフックを使う例とfunction_exists
で条件分岐する例を使ってきましたが、アクションフックを使うパターンの方がより汎用的になります。
以下は、パンくずリストを別の最新の記事一つ表示に変更する場合の例です。
例
<?php /** * パンくずリストの表示する関数 */ function prefix_breadcrumb() { // パンくずリストのコード echo 'パンくずリスト'; }
<?php /** * 最新の記事一つ表示する関数 */ function prefix_new_post() { // 最新の記事一つ表示するコード echo '最新の記事'; }
<?php require_once locate_template( 'breadcrumbs.php' ); // パンくずリスト関連のファイル require_once locate_template( 'new-post.php' ); // 最新記事関連のファイル
上記のように関数を定義してあるとして、以下はfunction_exists
を使った条件分岐でパンくずリストを表示するコードをテンプレートファイルに記述してある状態です。
<?php // ~~~ 省略 ~~~ ?> <div id="content"> <?php if( function_exists( 'prefix_breadcrumb' ) ) { prefix_breadcrumb(); } ?> <?php get_template_part( 'main' ); ?> </div><!-- .#content --> <?php // ~~~ 省略 ~~~
これを「最新の記事一つ表示」に変更するにはテンプレートファイル内のコードを以下のように書き換えなければなりません。
<?php // ~~~ 省略 ~~~ ?> <div id="content"> <?php if( function_exists( 'prefix_new_post' ) ) { prefix_new_post(); } ?> <?php get_template_part( 'main' ); ?> </div><!-- .#content --> <?php // ~~~ 省略 ~~~
アクションフックを使った場合は以下のように書くことが出来ます。
<?php /** * パンくずリストの表示する関数 */ // add_action( 'prefix_before_main', 'prefix_breadcrumb' ); function prefix_breadcrumb() { // パンくずリストのコード echo 'パンくずリスト'; }
<?php /** * 最新の記事一つ表示する関数 */ add_action( 'prefix_before_main', 'prefix_new_post' ); function prefix_new_post() { // 最新の記事一つ表示するコード echo '最新の記事'; }
<?php require_once locate_template( 'breadcrumbs.php' ); // パンくずリスト関連のファイル require_once locate_template( 'new-post.php' ); // 最新記事関連のファイル
<?php // ~~~ 省略 ~~~ ?> <div id="content"> <?php do_action( 'prefix_before_main' ); // ここにフックされて表示される ?> <?php get_template_part( 'main' ); ?> </div><!-- .#content --> <?php // ~~~ 省略 ~~~
テンプレートファイルに予めアクションフックを入れておけばそこに追加して、そのタイミングでコードを実行できます。アクションフックに追加するadd_action
もまとめて管理することができるので、このコードが使われているのかどうかわかりやすくなります。
上記の場合「パンくずリスト」はadd_action
がコメントアウトされているので、表示されず「最新の記事一つ表示」するコードのみ実行されます。
また、両方を同時に表示することも優先順位を付けて表示する順番も変更でき、その他のコンテンツも予め用意したprefix_before_main
のアクションフックに追加すれば、複数表示させることまで可能です。フックを使うことによって編集するファイルが少なくなり、拡張性も高くなります。
アクションフック、フィルターフックについては以下のリンク先を参考にしてみてください。
機能をWidgetにする
アクションフックを使えばコンテンツをコード側で自由に追加したり出来るのに対して、WidgetはWordPressの管理画面でドラッグ&ドロップでコンテンツの順番を入れ替えたり表示させたりすることができます。
Widgetはよくサイドバーで使われますが、メインコンテンツの上下やフッターにも使えるようにしておくとサイトのコンテンツの配置に自由度が増します。
Widgetについては以下リンク先を参考にしてみてください。
テーマ作成にはWordPressのテンプレートタグや関数を使う
テンプレートタグとは、ブログ内の特定の情報を表示したり、なんらかのアクションを起こすWordPressに定義されているPHP関数です。
テンプレートタグには以下の様なものがあります。
the_content
- 現在の投稿の本文を出力します。 このテンプレートタグはループの中で使わなければなりません。
the_tags
- このテンプレートタグは、現在の記事に付けられたタグを表示します。 各タグは、そのタグのアーカイブページへリンクします。 タグが付けられていない場合は、何も表示しません。 必ずループの中で使います。
category_description
- 現在のカテゴリーについて、カテゴリー管理画面(投稿 > カテゴリー)で設定した「カテゴリーの説明」を返します。 archive.php テンプレートで使う場合、条件分岐タグ is_category() の内側で使ってください。 そうしないと、月別アーカイブや他のアーカイブページの処理がこの関数のところで停止してしまいます。
テンプレートタグにはアクションフックやフィルターフックが用意されており、多くのプラグインがそのフックに追加して機能拡張しています。WordPressのテンプレートタグや関数を使うことで多くのプラグインに対応できるようになります。
また既にある機能をfunctions.php
に再定義する必要もないので管理するファイルやコードの量が少なくなります。
まとめ
- テンプレートファイルに関数や変数を定義しない
- 疎結合にする
- コーポネント化する
- アクションフックとフィルターフックを使う
- 機能をWidgetにする
- テーマ作成にはWordPressのテンプレートタグを使う
最後に
コーポネント化したりアクションフックを入れたりして汎用性や拡張性が高くなりますが、パフォーマンスは下がるかもしれません。あまりコロコロプラグインを入れ替えたり機能を追加してカスタマイズしないサイトを運営するにはここまで必要はないかもしれませんが、何かの役にたてば幸いです。