5/17 〜 5/18 に WordOnsen Sapporo 2014 が開催されました。定山渓温泉にてゆったり WordPress の勉強会という企画であります。 🙂
セミナー講師を担当させていただきましたが、温泉ということでいつもの SaCSS の勉強会と趣を変えようかと、モニターにコードを映しながら、お題を「functions.php を使い、pre_get_posts フックを用いてカスタム投稿をソートする」と決めてライブコーディングする形式でしゃべらせて頂きました。
東京から来られましたまがりん様に相談しながら、ライブコーディングしていたら夢中になってしまい、気がついたら 90分も演っていたということで、すいませんすいません。。(←本人はとても楽しかったらしい…
ということで、申し訳ないので、このブログにてソースなどまとめてみたいと思います。 お役立ていただけたらと思います。
functions.php について
- functions.php は WordPress の初期化後すぐに評価されるテーマ内のファイル。
- functions.php にフックの追加処理を記述しておくことにより、WordPress 初期化後に実行されるメイン処理の挙動をテーマから変更することができる。
- WordPress には処理の変更が行えるように、たくさんのフックが定義されている。
- 今回はテンプレートファイルのループで出力される記事の抽出条件を変えることができる pre_get_posts フックを活用して、カスタムフィールドの値で記事の順番をソートすることをお題としました。
フィルターフックの基本形
add_filterに関数名(ここでは change_query)を設定する。
function change_query($query) { $query->set('posts_per_page', 1); } add_filter('pre_get_posts', 'change_query');
PHP 5.3 以降では無名関数が利用でき、フックが関数定義なしでかけるので、直感的で便利。(以下のコードはこの形式でかきます)
add_filter('pre_get_posts', function($query) { $query->set('posts_per_page', 1); });
pre_get_posts フィルターフックによるメインクエリー改変
pre_get_posts フックから渡されてくる引数($queryオブジェクト)に set メソッドでパラメータを上書き設定すると記事の抽出条件が変更ができる。
例えば posts_per_page パラメータには出力する記事数が設定できる。
add_filter('pre_get_posts', function($query) { // var_dump($query); $query->set('posts_per_page', 1); });
存在するパラメータは Codex の WP_Query をみるか、var_dump($query); をすると知ることができる。
pre_get_posts で改変できるクエリーは、サイト上の表示だけでなく WordPress の管理画面の一覧表示などでも使われるため、テンプレートファイルからのメインクエリー出力時のみ変更するように、次のような if で条件を絞る。
add_filter('pre_get_posts', function($query) { if(!is_admin() && $query->is_main_query()) { $query->set('posts_per_page', 1); } });
pre_get_posts を使ったカスタムフィールド値でのソート処理
サイト上に配置された「昇順」「降順」などのリンククリックから、記事をカスタムフィールドに設定された値でソートを行う。例えば、カスタムフィールド PRICE に設定された値段で、商品の表示順をソートする場合。
商品を登録するカスタム投稿(post_menu)を定義。
add_action('init', function() { register_post_type('post_menu', array( // 管理画面ラベル名 'label' => '商品', 'public' => true, 'supports' => array( 'title', 'editor', 'thumbnail', 'custom-fields' ), )) });
「昇順」「降順」のリンクとアーカイブページを作成するため、カスタム分類(sort)を定義。
add_action('init', function() { register_taxonomy('sort', // この分類はカスタム投稿 post_menu に属する array('post_menu'), array( // 管理画面ラベル名 'label' => 'ソート', // 管理画面に表示する 'show_ui' => true, ) ); });
カスタム分類ができたら、「昇順」「降順」という分類を管理画面から登録し、スラッグをそれぞれ asc と desc に設定。(設定後、このカスタム分類は管理画面上に表示しなくてもよいため、show_ui を false にしてもOK)
functions.php でカスタム投稿・分類の設定を行った後は、管理画面から「パーマリンク」を一度ひらいてあげて、設定をリフレッシュしましょう。(←現地でわすれてまがりん様につっこまれる)
サイト上にカスタム分類(sort)のリンクを出力するため、テーマのテンプレートファイルに wp_list_categories テンプレートタグを配置。この分類には記事が属せず、そのままだとリンクが出力されないため、hide_empty を false に設定。(← true にしようとしてまがりん様につっこまれる)
<?php wp_list_categories(array( 'title_li' => '', 'taxonomy' => 'sort', 'hide_empty' => false )); ?>
「昇順」「降順」リンクがサイトに出力されるも、そのままのクエリーだと、単純に分類に属する記事を抽出しようとするので、何もでてこない。
ここで pre_get_posts の出番。クエリーを改変し、「カスタム分類 sort 出力時は、カスタム投稿(post_menu)に属している記事」という条件にまずは変更。$query が持つ条件分岐タグ is_tax でクエリー改変条件を絞り込み。
add_filter('pre_get_posts', function($query) { // メインクエリーでカスタム分類 sort 時のクエリーを変更 if(!is_admin() && $query->is_main_query() && $query->is_tax('sort')) { // カスタム投稿 post_menu の記事を抽出対象にする $query->set('post_type', 'post_menu'); // カスタム分類 sort による抽出を削除してしまう $query->set('sort', ''); } });
この処理で「昇順」「降順」リンクをクリックで表示されるカスタム分類アーカイブページで、商品が日付順で出力されるようになる(まだどちらのリンクも同じ抽出結果)。
カスタムフィールド PRICE によるソート処理を追加。
add_filter('pre_get_posts', function($query) { // メインクエリーでカスタム分類 sort 時のクエリーを変更 if(!is_admin() && $query->is_main_query() && $query->is_tax('sort')) { // カスタム投稿 post_menu の記事を抽出対象にする $query->set('post_type', 'post_menu'); // カスタムフィールド PRICE でソートするようにクエリーを設定 $query->set('meta_key', 'PRICE'); $query->set('orderby', 'meta_value_num'); // 押されたリンクにより昇順か降順のソートをクエリーに設定 if($query->get('sort') == 'asc') { $query->set('order', 'ASC'); } else { $query->set('order', 'DESC'); } // カスタム分類 sort による抽出を削除してしまう $query->set('sort', ''); } });
これにて完成です。 🙂
まとめると、カスタム分類 sort を作成することにより、カスタム分類アーカイブページの URL(クエリー)を WordPress 上に作成し、リンククリック時のクエリーを pre_get_posts により改変しカスタムフィールドでソートするという合わせ技となります。
この方法は、アーカイブページのクエリーに相乗りすることでページネーションも普通に行うことができますので、便利なのではないかと思います。
なお、セミナー中でも少しふれましたが、カスタムフィールドを使ったソートは、WP_Query で対応しているものの、WordPress の実装上、DB インデックスがあたらなかったり、value カラムが varchar になっている関係もあり、表示速度はそれほど期待できません。 記事が多いサイトで利用する場合は、事前に速度をテストしたり、もし遅い場合は、キャッシュ系の技術を併用するなどの対策を行ってください。
というわけで、WordOnsen Sapporo はセミナー後、開発合宿及び懇親会に突入。
まがりん様がもくもくと Stop the Bokettch のバージョンをあげ、マリメロ様が wp-otenki のカスタムお天気画像をつくり、気がつけばマミリンがぐーすか寝ているなど、盛り上がりをみせておりました。
翌日は円山公園散策。まがりん様のリス写真。
健康的! 楽しかったです(^ ^アリガトー