製品とカテゴリーで絞り込みができるようにする – WordPressプラグインの作成 17

投稿者: | 2018年3月24日

オンラインヘルプの設定ページを表示すると、製品とカテゴリーを絞り込むドロップダウンリスト部分で、エラー表示されていることが分かります。これはドロップダウンリスト部分で使用する $settings 配列変数に、'product''category' の要素が存在しないからです。
まだ新規作成部分を作成している途中ですが、今回は先に、製品とカテゴリーでリストを絞り込めるようにしていきます。

エラーが出ないようにする

まずはエラーが出ないようにコードを修正します。$settings のデフォルト値を定義している下記の部分に、コードを追加します(onlinehelp_admin.php : 34-35行目)。

    private $settings = [
        'sortlink' => '',
        'itemlink' => '',
        'sorted' => 0,
        'sorted-order' => 0,
        'row_begin' => 0,
        'row_end' => -1,
        'rows' => 25,
        'pagination' => self::EMPTY_PAGINATION,
        'product' => 0,
        'category' => 0,
    ];

これでエラーが表示されなくなりました。

絞り込みの選択状態を取得する

絞り込みを行うには、ドロップダウンリストの状態を取得し、データベースからリストを取得する際の条件に設定する必要があります。状態を取得するのは設定画面からPOSTを受信したときになるので、validate_top 関数に処理を追加します。
validate_top 関数を以下のように修正します(onlinehelp.php : 206-216行目)。

    public function validate_top($command)
    {
        // 現在の状態の取得
        $product = filter_input(INPUT_POST, 'product');
        $category = filter_input(INPUT_POST, 'category');

        // 絞り込み状態
        if ($product !== 'none') {
            $this->settings['product'] = intval($product);
        }
        if ($category !== 'none') {
            $this->settings['category'] = intval($category);
        }

        // 押されたボタンによって分岐
        switch ($command) {
            case 'new':
                $this->form = 'new';
                break;
        }
    }

なお、submitに設定されているどのボタンをユーザーがクリックしても、絞り込みの状態が変更できるようになります。[適用]ボタンを用意しているのに、[適用]ボタン以外でも絞り込みできるようにするのには理由があります。
たとえば、ページネーションでページの切り替えを行ったときを考えてみます。製品で絞り込みをすでに行っていて、ページネーションでページを切り替えたとします。このとき、製品で絞り込みを行っているという情報を取得しなかった場合、絞り込み状態がリセットされてしまいます。これを防ぐためには、現在のドロップダウンリストの状態を常に取得して、リストの表示に適用する必要があります。その副作用として、どのsubmitボタンでも絞り込みができてしまうという結果になります。
これはこれで問題があるのですが、当面は今の仕様で進めていきます。
[適用]ボタンだけで絞り込みを行い、リストを正しく(違和感なく)表示するには、hidden 属性の input 要素でデータを持たせるか、設定をセッションやデータベースなどに保存しておく方法があります。

絞り込みの設定に基づいてデータを取得する

データベースからレコードを取得する関数を以前作成したとき、すでに絞り込みに対応させていました。この関数へ、絞り込みの情報を渡してやれば、絞り込んだ結果が返ってきます。
print_admin_page関数を、以下のように修正します(onlinehelp_admin.php : 86行目)。

            default:
                $items = $onlinehelp_db->fetch_helps($this->settings['product'], $this->settings['category'],
                    $this->settings['sorted'], $this->settings['sorted-order']);

                // データの設定
                $pagination = $this->settings['pagination'];

バグの修正

SQL文のバグ

動作確認のため、ドロップダウンリストでカテゴリーや製品を選択して[適用]ボタンを押すと、エラーが表示されると思います。エラーメッセージによれば、SQL文に誤りがあるようです。このエラーを解決するため、以下のようにコードを修正しました(onlinehelp_db.php : 54行目)。

        if (count($where) > 0) {
            $sql .= " WHERE ";

            for ($i = 0; $i < count($where); $i++) {
                if ($i > 0) {
                    $sql .= " AND ";
                }
                $sql .= $where[$i];
            }
        }

forループの条件式が count($where) - 1 となっていたため、count($where) が 1 だったときにループが一度も実行されず、SQL文の where 部分が不完全になっていました。

ドロップダウンリストのバグ

もう一つ、エラーメッセージが表示されないバグがあります。絞り込みのドロップダウンリストから製品(またはカテゴリー)を選択して、[適用]ボタンを押すと、再表示されたドロップダウンリストは何も選択されていない(「製品の選択」が選択された状態)になります。再表示されたときは、選択した製品(またはカテゴリー)が選択されていることが正しい結果です。
以下のように修正してください(top.php : 38、46行目)。

                <span style="margin-right: 1rem;">
                    <select name="product">
                        <option value="none">製品の選択</option>
                        <?php foreach ($products as $_product): ?>
                            <option value="<?=esc_attr($_product->product_id)?>" <?=intval($this->settings['product']) === intval($_product->product_id) ? 'selected' : ''?>><?=esc_html($_product->prod_name)?></option>
                        <?php endforeach;?>
                    </select>
                </span>
                <span style="margin-right: 1rem;">
                    <select name="category">
                        <option value="none">カテゴリーの選択</option>
                        <?php foreach ($categories as $_category): ?>
                            <option value="<?=esc_attr($_category->cat_id)?>" <?=intval($this->settings['category']) === intval($_category->cat_id) ? 'selected' : ''?>><?=esc_html($_category->cat_name)?></option>
                        <?php endforeach;?>
                    </select>
                </span>

$this->settings['product']$_product->product_id$this->settings['category']$_category->cat_id が、それぞれ等しい場合、そのオプション項目が選択されていることになります。この比較に === (型を含むイコール) を使用しているため、型が異なると判断されていたようです。そこで、両辺を intval で整数に変換し、型を合わせることにしました。なお、== (型を含まないイコール)の場合、想定外の判断がなされることがあり、セキュリティ上の脆弱性にもつながりかねないため、使用しないことをおすすめします。
これで、ようやく絞り込みができるようになりました(ただし、データがないため実際にどう表示されるかは確認できませんが)。

ADs
  

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)