症状
既存のテンプレートに新しい変数を1つ足しました。ビルダー側(PHP)でちゃんと値を渡している。ところが Twig 側では、その変数が常に空(false)扱いになる。条件分岐を書いても、if の中に一度も入らない。
// PHP 側:値を渡しているつもり
$build = [
'#theme' => 'my_sidebar',
'#is_apply_page' => TRUE, // 渡している
];
{# Twig 側:常に false 扱いで、中に入らない #}
{% if is_apply_page %}
{# ここが一度も実行されない #}
{% endif %}
エラーは出ません。 例外も警告もなく、ただ値が届かない。だから「PHP 側の値が本当に TRUE か」を延々と疑ってしまう。実際には PHP 側は正しく、届いていないだけでした。
原因: hook_theme に宣言していない変数は捨てられる
Drupal の #theme によるレンダリングでは、テンプレートに渡せる変数が hook_theme() の variables 配列でホワイトリスト化されています。ここに列挙されていないキーは、render array に入れても Twig へ渡らずに捨てられます。
function mymodule_theme() {
return [
'my_sidebar' => [
'variables' => [
'items' => [],
// 'is_apply_page' を追記していない!
],
],
];
}
variables に is_apply_page が無いと、#is_apply_page で渡しても Twig には来ません。しかも Twig 側では、宣言されていない変数は**テンプレート宣言時のデフォルト(暗黙的に空)**として扱われるので、{% if is_apply_page %} は常に false になる。
要するに、「渡す側」と「受け取れる側」の two-list があって、両方に載せないと届かない。片方だけ足しても silent に落ちます。
対策: hook_theme の variables に登録する
新しい変数を追記します。
function mymodule_theme() {
return [
'my_sidebar' => [
'variables' => [
'items' => [],
'is_apply_page' => FALSE, // これを足す(デフォルト値も書く)
],
],
];
}
そして drush cr。theme registry はキャッシュされるので、hook_theme() を変えたらキャッシュクリアが要ります。これを忘れると「コードは直したのにまだ空」でもう一段はまります。
デバッグの勘所
このバグは「値が違う」ではなく「値が届かない」ので、PHP 側のロジックをいくら追っても原因が見つかりません。次の症状が出たら、最初に hook_theme() を疑うのが速い。
- テンプレートに if を書いたのに、条件が常に false
- render array で渡しているはずなのに、Twig 側で空
- エラーは一切出ていない
いずれも「変数がホワイトリストに載っていない」で説明がつきます。PHP 側の値を疑う前に、hook_theme() の variables にそのキーがあるかを確認する。そこに無ければ、PHP 側がどれだけ正しくても届きません。
まとめ
hook_theme()のvariablesに列挙していないキーは、render array に入れても Twig に渡らず silent に捨てられる。 エラーは出ない- 未宣言の変数は Twig で暗黙の空になる。 だから
{% if %}が常に false になる - 新しい変数を渡すときは、渡す側(render array)と受け取る側(hook_theme の variables)の両方に足す。 片方だけでは届かない
hook_theme()を変えたらdrush cr。 theme registry はキャッシュされる- 「if が常に false」「render array で渡したのに空」は、まず hook_theme を疑う。 PHP 側の値を疑う前に
この記事は、事業・Webサイトの売買プラットフォーム RIKKA M&A を開発する中で得た知見です。RIKKA M&A は GitHub リポジトリを解析する技術デューデリジェンスを備え、Drupal 11 / PHP / LLM で構築・運用しています。

