物件リスト絞込みフォームの作成

一覧リストに表示する物件を、ユーザーが好みの条件で絞り込みできるよう、操作フォームを設置します。絞り込みの項目は、物件タイプ(アパート、マンション、一戸建て)、間取り、向き、家賃、築年数および、こだわり条件(新築、角部屋、オートロック、...etc)とします。

賃貸物件リストのビューの編集画面(「管理」 > 「サイト構築」 > 「Views」 > 「賃貸物件リスト」)にアクセスしてください。

左側の下のほうに、FILTER CRETERIA というブロックがあると思います。ここは一覧リストを作成する際、どういった条件でコンテンツをリストアップするか、ということを設定するところです。現在、「コンテンツ: 掲載 (はい)」と「コンテンツ: タイプ (= 賃貸物件)」、そして前回追加した「コンテンツ: アクセス:delta (=0)」という項目が入っていると思いますが、これは

  • 「掲載/非掲載」の設定が「掲載」に設定されている。
  • コンテンツタイプは「賃貸物件」である。

という条件で、ノードをリストアップする、という意味です(「コンテンツ: アクセス:delta (=0)」については少し難しいので、別の機会に説明します)。実際のページの表示も、そうなっていると思います。

絞り込みフォームの設定はここで行います。実は条件の追加項目は、内部の設定として追加するだけでなく、ユーザーのフォーム操作による動的な設定として、追加することが出来るのです。これを Exposed Filter(公開フィルター)といいます。

まず最初に、物件タイプ(アパート、マンション、一戸建て)を選択できるフォームを設置してみましょう。通常のフィルターを追加するのと同様に、右側の「追加」ボタンをクリックしてください。

For のセレクトボックスが「All displays」となっていることを確認、フィルターのセレクトボックスは、「コンテンツ」を選択し、「コンテンツ: 物件タイプ (field_bukken_type)」という項目を探してチェックを入れ、「Apply (all displays)」ボタンをクリックします。

「コンテンツ: 物件タイプ (field_bukken_type)」フィルターの設定画面です。ここで「Expose this filter to visitors, to allow them to change it」のところにチェックを入れてください。これにチェックを入れることで、このフィルターは公開フィルターとなり、一覧リストの上部に操作フォームが追加されるようになります。ラベルに「物件タイプ」と入力、少しスクロールして、「Allow multiple selections」のところにチェックを入れ、「Apply (all displays)」ボタンをクリックします。

ビューの編集画面に戻ったら、画面右上の「保存」ボタンをクリックして、ビューの設定を保存してください。

ビューのページにアクセスすると、物件タイプを選択できる操作フォームが設置されました。デフォルトでは図のような位置に表示されます。ここでユーザーが「マンション」を選択すれば、マンションの物件だけがリストアップされます。複数選択も可能です。

同様に、「コンテンツ: 間取り (field_partition)」と、「コンテンツ: 向き (field_facing)」のセレクトボックスも追加してください。

次に、「家賃」の選択フォームを設置します。ビューの管理画面から、FILTER CRITERIA の「追加」ボタンをクリック、FILTER CRITERIA の追加画面で、For のセレクトボックスが「All displays」となっていることを確認、フィルターのセレクトボックスは、「コンテンツ」を選択し、「コンテンツ: 家賃 (field_rent)」という項目を探してチェックを入れ、「Apply (all displays)」ボタンをクリックします。

「Expose this filter to visitors, to allow them to change it」のチェックボックスにチェックを入れ、ラベルに「家賃」と入力、Operator は「is between」を選択して、「Expose operator」にチェックを入れます。「Apply (all displays)」ボタンをクリック。

ビューの編集画面に戻ったら、画面右上の「保存」ボタンをクリックして、ビューの設定を保存してください。

「家賃」で設定したフォーム(「is between」)は、ここでは少しカスタマイズが必要なようです。デフォルトでは2つのテキストフィールドにそれぞれ(家賃の)最小値、最大値を入力するようになっています。これを、あらかじめ設定した選択肢の中からクリックで選択できるよう、セレクトボックスに変更します。カスタムモジュールに、以下のコードを追加してください。

/**
 * Implementation of hook_form_FORM_ID_alter()
 */
function custom_form_views_exposed_form_alter(&$form, &$form_state) {
  // css を追加。
  drupal_add_css(drupal_get_path('module', 'custom') .'/custom.css');

  // カスタマイズを適用するフォームIDをまとめる。
  $ids = array(
    'views-exposed-form-forrent-bukken-list-page' => 'forrent',
    'views-exposed-form-forrent-bukken-list-page-area' => 'forrent',
    'views-exposed-form-forrent-bukken-list-page-route' => 'forrent',
    'views-exposed-form-forsale-bukken-list-page' => 'forsale',
    'views-exposed-form-forsale-bukken-list-page-area' => 'forsale',
    'views-exposed-form-forsale-bukken-list-page-route' => 'forsale',
  );

  if (isset($ids[$form['#id']])) {
    // 賃貸物件「家賃」フィルターのカスタマイズ。
    // デフォルトではテキストフィールドなので、セレクトボックスにする。
    if ($ids[$form['#id']] == 'forrent') {
      $form['field_rent_value']['#type'] = 'item';

      $rent_min_options[''] = t('下限なし');
      foreach (range(3, 30) as $value) {
        $rent_min_options[(string)($value * 10000)] = $value .'万円';
      }
      $form['field_rent_value']['min'] = array(
        '#type' => 'select',
        '#options' => $rent_min_options,
        '#weight' => 1,
      );

      $form['field_rent_value']['between'] = array(
        '#markup' => '<div class="between"> ~ </div>',
        '#weight' => 2,
      );

      foreach (range(3, 30) as $value) {
        $rent_max_options[(string)($value * 10000)] = $value .'万円';
      }
      $rent_max_options[''] = t('上限なし');
      $form['field_rent_value']['max'] = array(
        '#type' => 'select',
        '#options' => $rent_max_options,
        '#weight' => 3,
      );

      $form['field_rent_value_op']['#type'] = 'value';
      $form['field_rent_value']['value']['#type'] = 'value';
    }

    // サブミット関数を追加します。
    array_unshift($form['#submit'], 'bukken_list_form_submit');

    // サブミットボタン、リセットボタンはいちばん最後に。
    $form['submit']['#weight'] = 99;
    $form['reset']['#weight'] = 100;

    // フォーム全体をフィールドセットに
    $form['#prefix'] = '<fieldset class="form-item collapsible form-wrapper" id="bukken-exposed-form-wrapper">
  <legend><span class="fieldset-legend">物件の条件を絞り込み</span></legend>
  <div class="fieldset-wrapper">';
    $form['#suffix'] = '</div></fieldset>';
  }
}

/**
 * 賃貸物件リストの Exposed Form のサブミット関数。
 */
function bukken_list_form_submit(&$form, &$form_state) {
  // 「家賃」セレクトボックスの処理。
  // 「上限なし」の場合はオペレータを 'is greater than' に変更する。
  if (isset($form_state['values']['field_rent_value'])) {
    if (!$form_state['values']['field_rent_value']['max']) {
      $form_state['values']['field_rent_value_op'] = '>';
      $form_state['values']['field_rent_value']['value'] = $form_state['values']['field_rent_value']['min'];
    }
  }
}

custom_form_views_exposed_form_alter() は hook_form_FORM_ID_alter() というフックで、hook_form_alter() というフックの適用範囲を限定したものです。hook_form_alter() は、Drupal の入力フォームをその生成過程において、内容を変更することができます。ここで、2つのテキストフィールドを、適当な選択肢のあるセレクトボックスに変更しました。ついでに、フォーム全体をフィールドセットの中に配置しました。

「家賃」フィールドの配置は図のようになりました。家賃の上限と下限を選択すれば、選択した範囲の家賃の物件がリストアップされます。

続いて「築年月」フィールドの操作フォームを追加します。家賃と同じ要領で、「築年月」フィールドのフィルターを追加してください。その際、Operator の設定は「is greater than or equal to」にし、「Expose operator」にはチェックを入れないようにします。カスタムモジュールの、フック custom_form_views_exposed_form_alter() の中の、条件文 if (isset($ids[$form['#id']])) { } の中に、以下のコードを追加してください。

// 「築年数」のカスタマイズ
$options = array('' => t('指定してください'));
$basetime = substr_replace((string)time(), '00000', -5);// 100,000秒間(約27時間)はフォームの値の整合性が保たれる。
foreach (array(1,2,3,4,5,10,15,20,25,30) as $y) {
  $period = $basetime - 60*60*24*365*$y;
  $options[(string)$period] = t('@y 年以内', array('@y' => $y));
}
$form['field_completion_value'] = array(
  '#type' => 'select',
  '#options' => $options,
  '#default_value' => isset($_GET['field_completion_value']) ? $_GET['field_completion_value'] : '',
);

「築年月」フィールドの操作フォームが追加されました。選択した期間以内の築年月の物件がリストアップされます。

続いて、「こだわり条件」フィールドのチェックボックスを追加します。但し、Views の Exposed Form ではデフォルトではチェックボックス/ラジオボタンは現時点ではサポートされていないので、まずはデフォルトのままセレクトボックスとして配置します。

「間取り」や「向き」と同じ要領で、「こだわり条件」を追加します。その際、「ラベル」の欄は空欄にしてください。ここは後でフィールドセットに格納し、フィールドセットでラベルを指定するようにします。

Operator のところは「is all of」を選択してください。こうすることで、チェックされた全てのこだわり条件に合致する物件のみが抽出されます。オプションのところは「Allow multiple selections」(複数選択可)にチェックを入れ、設定を保存してください。

「こだわり条件」のセレクトボックスが追加されました。ラベルを空にしたので、ラベルは表示されていません。

次に、これをチェックボックスに変更します。通常 Drupal の Form API では、$form['要素名']['#type'] = 'checkboxes' とすれば、チェックボックスとして機能しますが、Views の Exposed Filter ではそのままでは機能しません。

そこで、ここではセレクトボックスのテンプレートに手を入れて、チェックボックスとして表示させる、という方法を採ります。カスタムモジュールに以下のコードを追加してください。

/**
 * Views の Exposed Filter のドロップダウンリスト入力フォームをチェックボックスとして出力します。
 * (これは hook_form_alter() では解決しません。何故なら構造的な違いがあるからです。)
 * 単に選択肢をチェックボックスとしてレンダリングするだけで、値の受け渡しは SELECT のままです。
 * FORM API も Views も、これをセレクトボックスとして扱います。
 * (hook_theme() にこれを登録し、hook_form_alter() でテーマを指定します。)
 */
function theme_select_as_checkboxes($variables) {
  $element = $variables['element'];
  $output = '';

  foreach($element['#options'] as $key => $value) {
    $id = $element['#id'] . '-' . $key;
    $selected = in_array($key, $element['#value']);

    $checkbox = '<input type="checkbox" '
    . 'name="'. $element['#attributes']['name'] .'" '
    . 'id="'. $id .'" '
    . 'value="'. $key .'" '
    . ($selected ? ' checked="checked" ' : ' ') .' />';

    $output .= '<div class="form-item form-type-checkbox form-item-' . strtr($element['#name'], '_', '-') . '-' . $key . '">'
    . $checkbox . '<label class="option" for="'. $id .'">' . $value .'</label></div>' . "\n";
  }
  return $output;
}

これはテーマ関数といい、テンプレートファイルと同様、最終的な HTML出力を担うものです。フォーム要素の配列をチェックボックスとしてレンダリングして返します。これをテーマレジストリに登録します。

/**
 * Implementation of hook_theme()
 */
function custom_theme() {
  return array(
    'select_as_checkboxes' => array(
      'render element' => 'element',
    ),
  );
}

カスタムモジュールに上記の hook_theme() を実装したら、テーマ管理ページ(/admin/appearance)にアクセスし、設定を更新してください。そのあと、パフォーマンスページ(/admin/config/development/performance)から「すべてのキャッシュをクリアー」ボタンをクリックして、キャッシュをクリアしてください。これで、「select_as_checkboxes」というテーマ関数が使えるようになります。

custom_form_views_exposed_form_alter() の中に、次のコードを追加してください。

    // セレクトボックスをチェックボックスにする
    // Views Exposed Form ではこれは単純に #type を変更してもうまく動作しないので、テンプレートの変更で対応する。
    if (isset($form['field_bukken_type_value'])) {
      $form['field_bukken_type_value']['#theme'] = 'select_as_checkboxes';
    }
    if (isset($form['field_partition_value'])) {
      $form['field_partition_value']['#theme'] = 'select_as_checkboxes';
    }
    if (isset($form['field_facing_value'])) {
      $form['field_facing_value']['#theme'] = 'select_as_checkboxes';
    }
    if (isset($form['field_good_value'])) {
      $form['field_good_value']['#theme'] = 'select_as_checkboxes';
      // 「こだわり条件」をフィールドセットに
      $form['field_good_value'] = array(
        '#type' => 'fieldset',
        '#title' => t('こだわり条件'),
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
        'field_good_value' => $form['field_good_value'],
      );
    }

フォーム要素の #theme に、今追加したテーマ関数 'select_as_checkboxes' を指定すれば、チェックボックスとして表示されます。物件タイプ、間取り、向きなど、他の要素も同様に設定しました。「こだわり条件」にはフィールドセットを追加しています。

あとは CSS で微調整を行い完了です。