WordPressで外部DBの検索フォームを作る

WordPressで外部データベースの複合検索機能を作る方法を紹介します。DBとの通信は、Ajaxを使って実装します。

デモサイトはこちら
今回は、WordPressで外部のデータベースに接続するで用意したデータベースを使います。

検索フォームを作る

ユーザー名、商品名、個数の入力フィールドを用意します。
通信時にリファラーをチェックするために、wp_referer_field関数を実行しておきます。

<?php wp_referer_field(); ?>
<label for="name">名前</label>
<input type="text" id="name" name="name" />
<label for="product">商品名</label>
<input type="text" id="product" name="product" />
<label for="quantity">個数</label>
<input type="number" id="quantity" name="quantity" />
<button type="button" id="js-submit">検索</button>

JavaScriptを読み込む

Ajaxを使うために、JavaScriptを読み込みます。
nonceを発行してJavaScriptに渡しておきましょう。

function my_enqueue_scripts() {
  if ( is_page('external-db-search-demo') ) {
    wp_enqueue_script(
      'my-external-db-search',
      get_theme_file_uri() . '/my_inc/js/external_db_search.js',
      array('jquery'),
      '1.0.0',
      true
    );
    $localize = [
      'ajax_url' => admin_url('admin-ajax.php'),
      'action' => 'external_db_search',
      'check_nonce' => wp_create_nonce('ajax-nonce-external-db-search')
    ];
    wp_localize_script('my-external-db-search', 'localize', $localize);
  }
}
add_action('wp_enqueue_scripts', 'my_enqueue_scripts');

Ajaxのリクエスト処理を追加する

フォーム送信時の処理を追加します。通信が成功したら、HTMLを挿入します。

jQuery(function($) {
  $('#js-submit').on('click', function() {
    $('#js-results').remove();  // 既に検索結果があれば削除する
    
    const http_referer = $('input[name="_wp_http_referer"]').val();

    // 入力内容を取得
    const name = $('input[name="name"]').val();
    const product = $('input[name="product"]').val();
    const quantity = $('input[name="quantity"]').val();

    $.ajax({
      type: "GET",
      url: localize.ajax_url,
      dataType: 'html',
      data: {
        action: localize.action,
        check_nonce: localize.check_nonce,
        _wp_http_referer: http_referer,
        name,
        product,
        quantity
      }
    }).done(function(data) {
      $('#js-submit').after('<div id="js-results">' + data + '</div>');  // レスポンスを挿入する
    }).fail(function() {
      console.log('ERROR');
    });
  });
});

Ajaxのレスポンス処理を追加する

まず、正しいリクエストかどうかをチェックします。

function my_external_db_search() {
  $error = TRUE;
  do {
    // nonceチェック
    if ( !check_ajax_referer('ajax-nonce-external-db-search', 'check_nonce', false) ) break;
    
    // リファラーチェック
    $referer = wp_get_referer();
    if ( strpos($referer, 'external-db-search-demo') === FALSE ) break;
    
    /* 中略 */
    
    $error = FALSE;
    
  } while ( FALSE );

  /* 中略 */

}
add_action('wp_ajax_external_db_search', 'my_external_db_search');
add_action('wp_ajax_nopriv_external_db_search', 'my_external_db_search');

続いて、wpdbクラスのインスタンスを生成して、SQLを組み立てます。

function my_external_db_search() {
  $error = TRUE;
  do {
    /* 中略 */
    
    $mydb = new wpdb(
      'dbuser',  // ユーザー名
      'dbpassword',  // パスワード
      'dbname',  // データベース名
      'dbhost'  // ホスト名
    );
    
    $sql = '
    SELECT
      orders.id AS id,
      users.name AS user_name,
      products.name AS product_name,
      orders.quantity AS quantity,
      orders.price AS price,
      orders.date AS date
    FROM
      orders
    LEFT JOIN
      users ON orders.user_id = users.id
    LEFT JOIN
      products ON orders.product_id = products.id';
    
    /* 中略 */
    
    $error = FALSE;
    
  } while ( FALSE );
  
  /* 中略 */
  
}
add_action('wp_ajax_external_db_search', 'my_external_db_search');
add_action('wp_ajax_nopriv_external_db_search', 'my_external_db_search');

検索フォームの入力内容があれば、WHERE句を追加します。
ユーザー名と商品名はあいまい検索、個数は完全一致検索で組み立てます。

function my_external_db_search() {
  $error = TRUE;
  do {
    /* 中略 */
    
    $wheres = array();
    if ( !empty($_GET['name']) ) {
      $wheres[] = array(
        'key' => 'users.name',
        'value' => $_GET['name'],
        'compare' => 'LIKE',
      );
    }
    if ( !empty($_GET['product']) ) {
      $wheres[] = array(
        'key' => 'products.name',
        'value' => $_GET['product'],
        'compare' => 'LIKE',
      );
    }
    if ( !empty($_GET['quantity']) ) {
      $wheres[] = array(
        'key' => 'orders.quantity',
        'value' => $_GET['quantity'],
        'compare' => '=',
      );
    }
    
    if ( $wheres ) {
      $args = array();
      $i = 1;
      foreach ( $wheres as $where ) {
        if ( $i === 1 ) {
          $sql .= "\nWHERE";
        } else {
          $sql .= "\nAND";
        }
        switch ( $where['compare'] ) {
          case '=' :
            $sql .= "\n{$where['key']} = %s";
            break;
          case 'LIKE' :
            $sql .= "\n{$where['key']} LIKE '%%%s%%'";
            break;
          default :
            break;
        }
        $args[] = $where['value'];
        $i++;
      }
    }
    
    $sql .= '
    ORDER BY
      orders.date ASC
    ';
    
    /* 中略 */
    
    $error = FALSE;
    
  } while ( FALSE );
  
  /* 中略 */
}
add_action('wp_ajax_external_db_search', 'my_external_db_search');
add_action('wp_ajax_nopriv_external_db_search', 'my_external_db_search');

WHERE句があればサニタイズして、SQLを実行します。
結果に応じてHTMLを組み立てて、実装完了です。

function my_external_db_search() {
  $error = TRUE;
  do {
    /* 中略 */
    
    // SQLを実行
    if ( $wheres ) {
      $results = $mydb->get_results($mydb->prepare($sql, $args));
    } else {
      $results = $mydb->get_results($sql);
    }
    
    $error = FALSE;
    
  } while ( FALSE );
  
  if ( $error ) {
    $html = '<p>ERROR</p>';
  } elseif ( !$results ) {
    $html = '<p>一致するデータはありません。</p>';
  } else {
    $html = '<table><tr><th>ID</th><th>名前</th><th>商品名</th><th>個数</th><th>単価</th><th>価格</th><th>注文日</th></tr>';
    foreach ( $results as $result ) {
      $html .= '<tr>';
      $html .= '<td>' . $result->id . '</td>';
      $html .= '<td>' . $result->user_name . '</td>';
      $html .= '<td>' . $result->product_name . '</td>';
      $html .= '<td>' . $result->quantity . '</td>';
      $html .= '<td>' . $result->price . '</td>';
      $html .= '<td>' . $result->quantity * $result->price . '</td>';
      $html .= '<td>' . $result->date . '</td>';
      $html .= '</tr>';
    }
    $html .= '</table>';
  }
  echo $html;
  die();
}
add_action('wp_ajax_external_db_search', 'my_external_db_search');
add_action('wp_ajax_nopriv_external_db_search', 'my_external_db_search');

コメント