Craft CMS でキーワード検索をする

過去記事を読み返していて検索インデックスの更新には言及しているものの、キーワード検索を Twig テンプレートで実装すること自体には触れていませんでした。

Searching | Craft CMS Documentation | 4.x
https://craftcms.com/docs/4.x/searching.html

そこで改めて Craft CMS でキーワード検索をする方法について、おさらいしてみたいと思います。
これは Craft CMS Advent Calendar 2022 25日目の記事です。

キーワード検索を実装するには

Craft CMS のテンプレートでキーワード検索をする場合、次の2つのステップが必要です。

URL パラメータから検索キーワードを取得

craft.app.request.getQueryParam で任意の URL パラメータを取得し、変数にセットします。

{% set searchQuery = craft.app.request.getQueryParam('q') %}

サンプルは検索フォームの input[name="q"] にキーワードをセット後、検索結果ページに遷移している想定です。

指定されたキーワードでエントリを検索

前段でセットした変数を .search() の引数とし、エントリを検索します。.orderBy('score') を追加しておくことで、検索結果は指定されたキーワードと関連性が高い順になります。

{% set searchResults = craft.entries()
  .search(searchQuery)
  .orderBy('score')
  .all() %}

検索結果をページ分割したい場合は、.all() の代わりに {% pagenate %} タグを利用します。

キーワード構文について

.search() にセットするキーワードをあらかじめ整形しておくことで、より細かい条件を指定できます。管理画面の検索ボックスでも同様に処理されます。

キーワード構文ヒットするエレメント
salty「salty」を含む
salty dog「salty」と 「dog」を両方含む
salty OR dog「salty」または 「dog」(もしくは、両方)を含む
salty -dog「salty」を含むが 「dog」を含まない
"salty dog"「salty dog」という正確なフレーズを含む
body:saltybody フィールドに 「salty」を含む
body:salty body:dogbody フィールドに 「salty」と 「dog」を両方含む
body:salty OR body:dogbody フィールドに 「salty」または 「dog」を含む
body:salty -body:dogbody フィールドに 「salty」を含むが「dog」を含まない
body:"salty dog"body フィールドに 「salty dog」という正確なフレーズを含む
body::saltybody フィールドに 「salty」だけがセットされている
body::"salty dog"body フィールドに 「salty dog」だけがセットされている
*ty「ty」で終わる単語を含む
*alt*「alt」を含む単語を含む
body:*tybody フィールドに「ty」で終わる単語を含む
body:*alt*body フィールドに「alt」を含む単語を含む
body::salty*body フィールドに「salty」で始まる単語を含む
body::*dogbody フィールドが「dog」で終わる
body:*body フィールドが何らかの値を持つ
-body:*body フィールドが空

なお、これらはあくまでデータベースに保存されている検索インデックスを対象とするテキスト検索で有効となる構文です。

日付や数値の範囲で検索する場合は、Craft CMS で日付や数値を指定してエントリを絞り込むも参考にしてください。

検索インデックスの登録内容を確認する

自分が試した範囲だと、Matrix フィールドの個々のブロックを foo.bar:* のような形で検索することはできないようです。とはいえ、Matrix フィールド自体で「このフィールドの値を検索キーワードとして使用する」を有効にしてあれば、フィールド全体を対象としたキーワード検索が可能です。

これらはシステムの設定によって左右されてしまうため、どのフィールドで絞り込みができそうか次の SQL で確認してみるのがオススメです。

SELECT
  f.handle,
  si.keywords,
  e.type,
  si.fieldId,
  si.attribute,
  f.name,
  f.context
FROM searchindex AS si
  LEFT JOIN fields AS f ON f.id = si.fieldId
  LEFT JOIN elements AS e ON e.id = si.elementId
WHERE
  si.keywords != '' AND
  si.fieldId NOT IN (0) AND
  f.context IN ('global')
ORDER BY
  e.type ASC,
  si.fieldId ASC

実行結果は次のようになります。

SQL の実行結果

ここから、カテゴリ(craft\elements\Category)やエントリ(craft\elements\Entry)を対象とする場合、text_singleLine:* のように絞り込みが可能であることを判断できます。

最後に

今回は Craft CMS でキーワード検索する方法をおさらいしてみました。

以前も記事にした気がしていたものの、どうやら公式ドキュメントを翻訳したときと記憶が混ざっているようです(。-_-。)
そう考えると、基本的な内容でも改めてまとめた方が良いことがありそうですね。