【実践】Welcartとブログの共存~WordPress.org申請テーマ編
スポンサーリンク
Welcart用無料テーマを制作するにあたり、非常に苦労した「ブログとの共存」。改めてその方法をまとめたいと思います。
今回はWordPress.orgにテーマ申請をした経緯から、「通常のブログ・ウェブサイト」がベースとなり、その上でWelcartが共存可能なテーマの作り方になります。プラグインありきのテーマはWordPress.orgの公式ディレクトリでは認められないとのこと。
もくじ
1. Welcartの仕様について
Welcartとブログを共存させるのが難しい理由の一つは、「WelcartがWordPressのデフォルトのカテゴリーと記事ページを商品にも使っている」点にあります。
アーカイブ用のページや検索ページなどで、ブログ記事と商品が一緒に表示されないように配慮する必要があります。
A. 投稿用のトップページ
任意の固定ページをトップページに指定する時、投稿の一覧でブログ記事と商品が一緒に表示されないようにします。
読み込まれるのは設定によりfront_page.phpかhome.phpですが、条件としてはif(is_home())です。
これはクエリを書き換える方法で対応します。
B. アーカイブページ
タグや日付アーカイブのページでは、ブログ記事と商品が混ざらないようにします。
Welcartプラグインの下で登録される商品は、全て「商品(スラッグ:item)」というカテゴリーに属させることになっています。
従って、表示の振り分けの基本条件は「記事が”item”というスラッグを持ったカテゴリーに属するかどうか」がポイントになってきます。
C. 検索フォームと検索結果ページ
Welcartには「Welcartキーワード検索」というウィジェットが用意されています。
「商品カテゴリー複合検索」というリンクが用意されている以外は、このウィジェットの機能は普通のWordPressの検索と同じです。これがまた、厄介の元。
ブログを共存させ、且つブログでも検索を使いたい場合は、商品用の検索フォームと検索結果ページは、それとは別になるように作り分けなければいけません。この方法についても後述します。
D. 商品ページ・カートページ・メンバーページ
Welcart用の商品ページやカートページ、メンバーページなどは、Welcartプラグイン内に用意されているものが読み込まれます。
カスタマイズしたい場合はプラグインフォルダに入っている、wc_templatesフォルダ内の各テンプレートを、使用中のテーマにコピー。するとそれが優先的に読み込まれる仕組みになっています。
この場合は別途テンプレートを用意したり、読み込みを振り分ける必要はありません。
2. テンプレートの用意
WordPressでは、例えば「category-item.php」というテンプレートを作れば、itemというスラッグが付いたカテゴリーのアーカイブを表示する際には、自動的にそのテンプレートが読み込まれることになります。
ただ、その場合はtag-item.phpやdate-item.phpも作らなければならず、テンプレートがとにかく多くなってしまいます。
そこで今回はWordPress.orgへのテーマ申請にあたり、商品用アーカイブはarchive-item.phpとしてひとつにまとめ、functions.phpでテンプレートの振り分けを行うことにしました。
(補足)archive-slug.phpは、category-slug.php等のように、スラッグがついたものを自動で振り分ける機能はありません。飽くまでも「テンプレートを減らす為」に作ったので、functions.phpでの振り分けが必要になります。
通常のブログ・固定ページ用 | Welcart用 | |
---|---|---|
アーカイブページ | archive.php | archive-item.php |
検索結果ページ | search.php | search-item.php |
検索結果ページも同様に、商品用としてsearch-item.phpを作ります。これにも自動で振り分ける機能はないため、functions.phpでテンプレート読み込みとクエリの振り分けを行います。
3. 検索フォームの設計
次に複雑なのが、検索フォーム。
※検索フォームをブログ用と商品用に分けて置かない場合は必要ありません。
商品用の検索フォームの時には商品を、通常の検索フォームの時にはブログ記事を、それぞれ検索対象として絞りこむ必要があります。(混ざってもよければ別にいいですが)
Welcartの検索ウィジェットはプラグイン側で用意されていますが、カスタマイズすると更新時に上書きされてしまいます。なので今回は仕方なく通常の検索フォームをカスタマイズすることにしました。
通常の検索フォームのテンプレート(searchform.php)を作ったら、formの最後にhidden要素として以下のコードを追加し、商品以外の検索であることを知らせます。
<input type="hidden" name="searchitem" value="posts">
こうすることにより、searchform.phpで作られた検索フォームを使って検索すると
http://www.example.com/?s=キーワード&searchitem=posts
というように、URLにnameとvalueが反映されます。
これを利用して、振り分け条件として「searchitemがセットされているか?」(セットされていればブログ用・いなければ商品用とする)を指定することが出来るようになります。
4. functions.phpで表示を振り分け
4-1. テンプレートの振り分け
テンプレートを使い分けるには、テンプレート表示を制御するためのフィルターフックを使います。
- category_template:カテゴリーページ
- tag_template:タグページ
- search_template:検索結果ページ
アーカイブページの種類には「カテゴリー」「タグ」「日時」「作成者」の4種類がありますが、商品には「日時」「作成者」のアーカイブは不要です。なのでここではフィルターを設定しません。
その代わり、次の「4-2. クエリの変更」で「日時」と「作成者」アーカイブの時はブログ記事だけを表示させるクエリにします。
4-1-1. カテゴリーページのフィルター : category_template
「祖先にitemというスラッグのカテゴリーがあるか(またはitemというスラッグのカテゴリーページかどうか)」が条件です。「ある」場合は商品用のarchive-item.phpを読み込みます。
add_filter( 'category_template', 'blanc_category_item_template' ); function blanc_category_item_template($category_item_template) { $category_id = get_query_var('cat'); $parent_ids = get_ancestors($category_id, 'category'); $parent_slugs = array(); foreach ($parent_ids as $parent_id){ $parent = get_category($parent_id); $parent_slugs[] = $parent->slug; } if (in_array('item', $parent_slugs) || is_category('item')){ $category_item_template = dirname( __FILE__ ) . '/archive-item.php'; } return $category_item_template; }
祖先カテゴリーを得る為に、やや長いコードとなっています。
4-1-2. タグページのフィルター : tag_template
「投稿がitemというスラッグのカテゴリーに入っているかどうか」が条件です。「入っている」場合は商品用のarchive-item.phpを読み込みます。
add_filter( 'tag_template', 'blanc_tag_item_template' ); function blanc_tag_item_template($tag_item_template) { if ( in_category( 'item' )) { $tag_item_template = dirname( __FILE__ ) . '/archive-item.php'; } return $tag_item_template; }
注意すべきなのは、同じタグをブログと商品で共有させないことです。共有させてしまうと、タグページではブログ記事のほうが優先されてしまい、通常のアーカイブテンプレート(archive.php)が読み込まれます。
4-1-3. 検索結果ページのフィルター : search_template
「searchitemという値が送信されているか否か」が条件です。「送信されていない」場合は、商品用の検索結果ページsearch-item.phpを読み込みます。
add_filter( 'search_template', 'blanc_search_item_template' ); function blanc_search_item_template($search_item_template) { if ( is_search() && !isset($_GET['searchitem'])){ $search_item_template = dirname( __FILE__ ) . '/search-item.php'; } return $search_item_template; }
これらの設定は、単にテンプレートの読み込みを振り分けているだけですので、生成されるクエリはまだ「商品」「ブログ」が混在して吐き出されます。そこで、次にクエリの変更を行います。
4-2. クエリの変更
更に、それぞれのテンプレートで表示する内容を、「ブログ記事だけ」と「商品だけ」に振り分けるため、クエリを変更させるpre_get_postsというアクションフックを使います。
ここでは、投稿記事の固定トップページ([表示設定]>[フロントページ]>[投稿ページ]で任意の固定ページを設定した場合)を設定した際に、商品が一覧に載ってしまわないような配慮も行っています(下記コード9~11行目)。
add_action('pre_get_posts', 'blanc_query'); function blanc_query($query){ $item_cat = get_category_by_slug('item'); //itemというスラッグを持つカテゴリーの情報を取得 $item_cat_id = $item_cat->cat_ID; //itemというスラッグを持つカテゴリーのIDを取得 if ( is_admin() || ! $query->is_main_query() ){ return; } //投稿記事のトップページ・作成者アーカイブ・日付アーカイブの際は、カテゴリーitem以外の投稿を取得 if ( $query->is_home() || $query->is_author() || $query->is_date() ){ $query->set('category__not_in', $item_cat_id); } //ブログ記事の検索の際は、カテゴリーitem以外の投稿を取得 if ( $query->is_search && isset($_GET['searchitem']) ) { $query->set('category__not_in', $item_cat_id); } //商品の検索の際は、カテゴリーitemに属する記事のみ表示 if ( $query->is_search && !isset($_GET['searchitem']) ){ $query->set('category_name','item'); } }
ここでは表示件数はいじっていませんが、商品アーカイブや商品の検索ページで表示件数をWordPressの設定とは変更したい場合は、
$query->set('posts_per_page','20');
というようなコードを条件の中に追加すればOKです。
5. まとめ
WordPress.orgに申請するには、誰がどんな風に使っても大丈夫なようにテーマを設計する必要があったため、ご覧の通り、まことに骨が折れるカスタマイズとなりました。
最初からWelcartありきでテーマを設計する場合は、不要な箇所は作る必要がないため、多少は楽になるかと思います。個人的には、ここまで複雑なことをするくらいなら、Welcartとブログは別々に運営したほうが管理が楽で良いかと。
Welcartとブログを共存させる最大のメリットは、ブログにも商品データが使えることですかね。ショートコードを利用すれば、ブログ記事にカートボタンを表示させることも可能となります。
[button_to_cart item="item_code" sku="sku_code" value="text"]
この記事がどなたかの役に立てば嬉しいです。