「ショップガイドを作ってみよう」でも述べたように、投稿を絞り込む機能はPHPで実装すべきだと考えていたものの、私の技術レベルでは実現が難しく、なかなか形にできずにいました。ですが、ついに完成させることができました。
そこで今回は、「ショップガイドを作ってみよう」で紹介したJavaScriptによる「カテゴリーで絞り込む」機能を、PHPで実装する方法を解説します。
完成イメージ
例えば、[B1]をクリックするとB1のショップが表示され、[絞り込む]をクリックすると、B1のショップの中から選択されたカテゴリーに該当する店舗のみを表示します。
前提条件
ブロックテーマ・カスタム投稿タイプ・カスタムタクソノミー を使用していることを前提にしています。
カスタムタクソノミー
これから紹介するコードは、以下のタクソノミーとタームを使用しています。
タクソノミー:shop_category、shop_floor
shop_categoryのターム:fashion、lifestyle、cosmetics、dining、food、services
ブロックテーマ
ブロックテーマを使用しているため、shop_floor
タクソノミーアーカイブページのメインクエリをカスタマイズしています。
注意点
セキュリティ対策が不十分なため、実際に導入する際は対策が必要です。
HTMLフォームは、Webアプリケーションに対する攻撃経路のひとつです。 自分自身を含めたユーザーからの入力は常に不確実なものとして扱い、サーバーに送信された全てのデータを検証し、適切に処理する必要があります。
HTMLフォームの脆弱性
- クロスサイトスクリプティング (XSS)
- SQLインジェクション
- クロスサイトリクエストフォージェリ(CSRF)
サーバーサイドでの対策
- 入力データの検証:入力されたデータが想定される範囲内であるか、不正な文字が含まれていないかなどをチェックする
- サニタイジング:入力データのエスケープ処理などを行い、安全な形式に変換する
HTMLコード
選択したカテゴリーに基づいてショップを絞り込むためのフォームを作成します。
コードは、カスタムHTMLブロックを使って記述します。
<form method="post">
<fieldset>
<legend>カテゴリーで絞り込む</legend>
<label><input type="checkbox" name="category[]" value="fashion">Fashion</label>
<label><input type="checkbox" name="category[]" value="lifestyle">Lifestyle</label>
<label><input type="checkbox" name="category[]" value="cosmetics">Cosmetics</label>
<label><input type="checkbox" name="category[]" value="dining">Dining & Café</label>
<label><input type="checkbox" name="category[]" value="food">Food & Groceries</label>
<label><input type="checkbox" name="category[]" value="services">Services</label>
</fieldset>
<button type="submit" name="shop_category_filter" value="filtered">絞り込む</button>
</form>
フォーム
POSTメソッドを使用してデータをサーバーに送信する
チェックボックス
name属性:選択されたカテゴリーの値を配列としてサーバーに送信するよう、すべてのチェックボックスにcategory[]という名前を付ける
value属性:各チェックボックスにカテゴリーのスラッグを割り当て、サーバー側でどのカテゴリーが選択されたか判断できるようにする
ボタン
フォームデータを送信するためのボタンを設置する
HTTPリクエストの表示
ブラウザの開発者ツールで、送信されたデータを確認できます。
- 開発者ツールを開く
- Networkタブを選択
- Nameタブからフォームが設置されているページのURLを選択
- Headersタブでリクエストヘッダーを確認
- Payloadタブで送信データを確認
PHPコード
POSTリクエストから選択されたカテゴリーを取得し、それを基にshop_floorというタクソノミーのアーカイブページのメインクエリを変更して、投稿をフィルタリングします。
今回は、PHP EngineerというGPTにコードの作成とデバッグを手伝ってもらいました。
コードの記述場所としては、子テーマのfunctions.phpファイルやCode Snippetsなどのプラグインが挙げられます。プラグインを利用すると、テーマを変更してもカスタマイズが維持されます。
/**
* POSTリクエストから選択されたカテゴリーを取得する関数
*
* この関数は、POSTリクエストが送信された際に、'shop_category_filter'が設定されているか確認します。
* その後、選択されたカテゴリーがあれば配列として返します。
*
* @return array 選択されたカテゴリーのスラッグが入った配列を返します。
*/
function get_selected_categories() {
$selected_categories = [];
// リクエストメソッドがPOSTであり、'shop_category_filter'が設定されているか(ボタンがクリックされたか)確認
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['shop_category_filter'])) {
// 'category'が設定されているか、配列であるか確認
if (isset($_POST['category']) && is_array($_POST['category'])) {
// 選択されたカテゴリーを$selected_categories配列に設定
$selected_categories = $_POST['category'];
}
}
// 選択されたカテゴリーの配列を返す
return $selected_categories;
}
/**
* 選択されたショップカテゴリーで投稿をフィルタリングする関数
*
* この関数は、WordPressの 'pre_get_posts' アクションにフックし、
* メインクエリを選択されたカテゴリーでフィルタリングするために使用されます。
* 選択されたカテゴリーは 'get_selected_categories' 関数から取得されます。
*
* @param WP_Query $query メインのWordPressクエリオブジェクト。
*/
function filter_shop_by_category($query) {
// 管理ページのクエリではなく、メインクエリであるかを確認
if (!is_admin() && $query->is_main_query()) {
// 'shop_floor'タクソノミーのアーカイブページかを確認
if(is_tax('shop_floor')) {
// POSTリクエストから選択されたカテゴリーを取得
$selected_categories = get_selected_categories();
// 選択されたカテゴリーがある場合、クエリをそれに基づいてフィルタリング
if (!empty($selected_categories)) {
// 選択されたカテゴリーでフィルタリングするためのtax_query配列を作成
$tax_query_array = [
[
'taxonomy' => 'shop_category', // フィルタリング対象のタクソノミー
'field' => 'slug', // スラッグでフィルタリング
'terms' => $selected_categories, // 選択されたカテゴリーのスラッグ(配列)
]
];
// クエリにtax_queryを設定し、投稿をフィルタリング
$query->set('tax_query', $tax_query_array);
}
}
}
}
// 'filter_shop_by_category' 関数を 'pre_get_posts' アクションにフック
add_action('pre_get_posts', 'filter_shop_by_category');
HTTPメソッドとリクエストデータに関する関数
$_SERVER[‘REQUEST_METHOD’]:ページにアクセスする際に使用されたリクエストのメソッドを取得する
$_POST[‘キー’]:POSTメソッドで送信されたデータを取得する(’キー’の部分には、input要素のname属性に指定した値が入る)
変数と配列の判定に関する関数
isset($変数名):指定した変数が定義されていて、nullではないかどうかを調べる
is_array($変数名):指定した変数が配列かどうかを調べる
empty($変数名): 指定した変数が空かどうかを調べる
WordPress環境に関する関数
is_admin(): 現在のリクエストが管理画面に対するものかどうかを調べる
is_main_query():現在のクエリがメインクエリかどうかを調べる
is_tax():現在のクエリがカスタムタクソノミーのアーカイブページのものかどうかを調べる
WP_Queryクラスのタクソノミーパラメータ
tax_query (array):タクソノミーに関する条件を指定する
taxonomy (string):対象とするタクソノミーの名前
field (string):タクソノミータームを指定する方法(term_id、name、slug、term_taxonomy_id)
terms (int/string/array) :対象とするタクソノミーターム
詳しくは、WP_Queryクラスのタクソノミーパラメータを参照してください。
WordPressのフック
pre_get_posts:クエリが実行される直前に呼び出されるアクションフック
まとめ
HTMLフォームに加えて、WordPressクエリの知識も必要になるため、難しく感じたかもしれません。慣れるまで時間がかかるかもしれませんが、実際に手を動かして試してみることで、理解が深まります。基本的な概念を理解すれば、応用次第でさまざまなことができるようになります。この記事を活かして、絞り込み検索をPHPで実装する課題に挑戦してみてください!