【WordPress】MW WP Formで都道府県フォームを作り、対応状況と都道府県で絞り込み検索しつつ、都道府県フォームの内容によって送信先を変更

個人的な備忘録だけど、案外似たような事案を抱えてる人も多いような気がしたので。
WordPressの仕様をよくわかってる人にとっては何てこと無いことかもしれません。（筆者はプラグインが無いとまともにカスタマイズもできないレベルです）

# 要件

- MW WP Formの問い合わせで、都道府県の項目をプルダウンメニューで作る
- 管理者宛メールの送信先を、都道府県ごとに振り分ける（各都道府県の担当者に送る）
- 問い合わせデータ画面で、対応状況と都道府県でAND検索できるように
- 担当者のメールアドレスを後から変えられるように
- 振り分け条件（どの都道府県の場合に誰に送るか）も後から変えられるように

最後2つの条件が厄介でした。
そもそもメール送信先の振り分け自体が`mwform_admin_mail`のフィルターフックでしか実現できないのにそれを可変にするとかどうしろと…

結論から言うと、送信先ごとにユーザーを作り、振り分け条件判定をユーザー情報のニックネームに充てることで解決しました。


# 実装手順

1. 振り分け先のユーザーを作成
2. MW WP Formでフォームを作る
3. function.phpに必要な記述を追加

## 振り分け先のユーザーを作成

送信先のメールアドレスでユーザーを作成（ユーザー名は適当でOK）。
作成後、ユーザーの編集画面の**ニックネーム**に、送信条件となる都道府県名を入れておく。
複数の都道府県の指定もできる。区切り文字等は不要だが、フォームデータで検索することになるため、フォームの値と一致するようにすること。

今回の例の場合、

東京都大阪府
東京都,大阪府
東京都、大阪府
東京都 大阪府

などはいずれも【東京都】と【大阪府】で条件にマッチするが、

東京大阪

ではどちらにもマッチしない。



## MW WP Formでフォームを作る

特にややこしいことは不要。

```html
[mwform_select name="都道府県" children=":選択してください,北海道,青森県,岩手県,宮城県,秋田県,山形県,福島県,茨城県,栃木県,群馬県,埼玉県,千葉県,東京都,神奈川県,新潟県,富山県,石川県,福井県,山梨県,長野県,岐阜県,静岡県,愛知県,三重県,滋賀県,京都府,大阪府,兵庫県,奈良県,和歌山県,鳥取県,島根県,岡山県,広島県,山口県,徳島県,香川県,愛媛県,高知県,福岡県,佐賀県,長崎県,熊本県,大分県,宮崎県,鹿児島県,沖縄県" post_raw="true"]
```

フォームタグ作成時に「メールで送信する値」にチェックを入れ、選択肢の1行目を`:(初期テキスト)`としておくと、初期値のままの場合は選択無しと判定してくれる。

## function.phpに必要な記述を追加

### 【1】管理者宛メールの送信先を、都道府県ごとに振り分ける
これを実現するには、以下の手順で処理すればOK。

1. 管理者宛メールの設定を変更する`mwform_admin_mail`フィルターフックが[用意されている](https://plugins.2inc.org/mw-wp-form/filter-hook/mwform_admin_mail_raw/)ので、それを使う
2. フック内で都道府県のフォームデータを受け取り、データベースへアクセス
3. ユーザー情報のニックネームを部分一致で検索し、都道府県にマッチするユーザーのメールアドレスを取得
4. メールの送信先を書き換える

実現にはデータベースへのアクセスが必要。あまり使ったことがないので、特にSQL実行文で四苦八苦しました。




*--- 2020年3月18日追記 ---*

**`get_users()`使えよ！！**
…これを書いた当時はまだWordPressに触れて1年も経っていなかったため、WordPress関数の存在をまともに知らなかったが故の過ち。
しかしget_usersより$wpdb使うほうが遥かにややこしいと思うんだけど、当時の筆者はどうやって調べた結果このコードにたどり着いたんだろうか…

*--- 追記ここまで ---*

```php:function.php
// メール送信先を都道府県でフリワケ
function my_change_admin_mailto( $Mail, $Data ) { //$Mailが管理者宛メールの情報、$Data['hoge']がフォームデータ

/* --- ここから追記 --- */

	$terms = $Data['都道府県'];
	$args = array(
		'fields' => array( 'user_email' ),
		'search' => '*'.$terms.'*' // 検索文字の前後に'*'を付ければワイルドカードで検索できる
	);

	/*
	// なお、振分条件専用のカスタムフィールドを検索に使う場合はmeta_queryを使えば良い。
	$args = array(
		'fields' => array( 'user_email' ),
		'meta_query' => array( array(
			'key' => 'カスタムフィールドのスラッグ',
			'value' => $terms,
			'compare' => 'LIKE'
		) ) );
	*/

	$targets = get_users( $args );

/* --- 追記ここまで --- */



/* --- 以下は以前のやり方 --- */

	global $wpdb;
	$terms = $Data['都道府県'];
	$targets = $wpdb->get_results(
		// データベースからユーザー情報へアクセス
		// ニックネームはusermetaにあるのでuser_idと合わせて副問合せする
		// meta_key = nickname な行の meta_value の値がニックネーム情報
		// 都道府県のフォームデータと部分一致する場合はメールアドレスを取得する
		$wpdb->prepare("
			SELECT user_email
				FROM {$wpdb->users}
				WHERE EXISTS (
					SELECT *
						FROM {$wpdb->usermeta} as m
						WHERE m.user_id = {$wpdb->users}.ID
						AND m.meta_key = 'nickname'
						AND m.meta_value LIKE '%%%s%%'
				)
		", $terms));

/* --- 以前のやり方ここまで --- */




	if( !empty($targets) ){
		// 返り値は中身がオブジェクトの連想配列なので、それをカンマ区切りの文字列に変換
		$mailList = array();
		foreach($targets as $email){
			$mailList[] = $email->user_email;
		}
		$mailTo = implode( ",", $mailList );
		// 送信先を上書き
		$Mail->to = $mailTo;
	}

	return $Mail;
}
add_filter( 'mwform_admin_mail_mw-wp-form-***', 'my_change_admin_mailto', 10, 2 ); // ***の部分は、フォームIDに合わせて変更する

```


### 【2】問い合わせデータ画面で、対応状況と都道府県で絞り込み検索できるように

カスタムフィールドの値で絞り込み検索する要領で実装。
アクションフックに検索用の`<select>`タグを突っ込む。
もっと頭のいいやり方がありそうだけど、筆者のスキルではこれが限界だった。


*--- 2019年3月29日追記 ---*

絞り込み結果の表示は、これまで全件データ取得→データベースに別途アクセスして絞り込み条件に合うもののみ残す、というやり方でやっていましたが、
公式に[レコード取得条件を操作できるフィルターフック](https://plugins.2inc.org/mw-wp-form/filter-hook/mwform_get_inquiry_data_args-mwf_xxx/)がちゃんと用意されていました。
さらにCSVダウンロード時にも絞り込み結果が反映されるように変更。
ちなみに、上記フィルターフックで取得したパラメータを、そのまま[get_posts()](https://wpdocs.osdn.jp/%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%BF%E3%82%B0/get_posts)に渡している模様。
→https://github.com/inc2734/mw-wp-form/blob/master/classes/controllers/class.contact-data.php#L25-L35

結果的に不要なデータを読み込まなくても良くなったので、動作も多少軽くなるかも？

*--- 追記ここまで ---*


```php:function.php

// URLクエリ変数を追加する
function add_subtitle( $vars ) {
	$vars[] = 'response_status';
	$vars[] = '都道府県';
	return $vars;
}
add_filter('query_vars', 'add_subtitle');


// 問い合わせ一覧画面に対応状況・都道府県の絞り込み検索プルダウンメニューを表示
function add_subtitle_filter(){
	global $post_type;
	// MW WP Form以外では実行しないようにする。***の部分は、フォームIDに合わせて変更する
	if ( $post_type == 'mwf_***' ) {
		// 対応状況の絞り込み検索
		echo '<select name="response_status">';
		echo '<option value="">すべての対応状況</option>';
		$status = array(
			'not-supported' => '未対応',
			'supported' => '対応済み',
			'reservation' => '保留'
		);
		foreach ($status as $key => $value) {
			$selected = "";
			if(get_query_var('response_status') == $key) {
				// URLクエリと一致する場合はselectedに
				$selected = ' selected="selected"';
			}
			echo '<option value="'. $key . '"'. $selected . '>'. $value . '</option>';
		}
		echo '</select>';

		// 都道府県の絞り込み検索
		echo '<select name="都道府県">';
		echo '<option value="">すべての都道府県</option>';
		$todofuken = array('北海道','青森県','岩手県','宮城県','秋田県','山形県','福島県','茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県','新潟県','富山県','石川県','福井県','山梨県','長野県','岐阜県','静岡県','愛知県','三重県','滋賀県','京都府','大阪府','兵庫県','奈良県','和歌山県','鳥取県','島根県','岡山県','広島県','山口県','徳島県','香川県','愛媛県','高知県','福岡県','佐賀県','長崎県','熊本県','大分県','宮崎県','鹿児島県','沖縄県');
		foreach ($todofuken as $value) {
			$selected = "";
			if(get_query_var('都道府県') == $value) {
				// URLクエリと一致する場合はselectedに
				$selected = ' selected="selected"';
			}
			echo '<option value="'. $value . '"'. $selected . '>'. $value . '</option>';
		}
		echo '</select>';
	}
};
add_action('restrict_manage_posts', 'add_subtitle_filter');



// 絞り込み検索実行時の処理

/* --- 2019年3月29日追記分 --- */
function get_inquiry_data_subtitle($args) {
	$value1 = get_query_var('response_status');
	$value2 = get_query_var('都道府県');

	$querys = array();

	// 以下は、CSVダウンロードボタンを押した時用の処理（get_query_varで何も返ってこないため、URLパラメータを直接参照する）
	if(empty($value1)){
		if(isset($_GET['response_status'])){
			$value1 = $_GET['response_status'];
		}
	}
	if(empty($value2)){
		if(isset($_GET['都道府県'])){
			$value2 = $_GET['都道府県'];
		}
	}

	if(!empty($value1)) {
		$querys = array_merge( $querys, array( array( 
			'key'   => '_mw-wp-form_data',
			'value' => $value1,
			'compare' => 'LIKE'			// 対応状況のみレコード内にmemoのデータも一緒に入っているため、部分一致で検索する
		) ) );
	}
	if(!empty($value2)) {
		$querys = array_merge( $querys, array( array(
			'key'   => '都道府県',
			'value' => $value2
		) ) );
	}

	$args = array_merge( $args, array(
		'meta_query' => $querys
	) );
	return $args;
};
add_filter( 'mwform_get_inquiry_data_args-mwf_***', 'get_inquiry_data_subtitle' ); // ***の部分は、フォームIDに合わせて変更する

/* --- 追記ここまで --- */

/* --- 以下は以前のやり方 --- */
function posts_where_subtitle( $where ) {
	global $wpdb;
	if(is_admin()) {
		$value1 = get_query_var('response_status');
		$value2 = get_query_var('都道府県');
		if(!empty($value1)) {
			// SQLクエリ文に条件を追記
			// response_statusは postmeta テーブルの _mw-wp-form_data というキーに、memo情報と一緒に格納されているので、LIKEで検索する
			$where .= $wpdb->prepare(" AND EXISTS ( SELECT * FROM {$wpdb->postmeta} as m
									WHERE m.post_id = {$wpdb->posts}.ID
									AND m.meta_key = '_mw-wp-form_data' AND
									m.meta_value like %s )",
									 "%{$value1}%" );
		}
		if(!empty($value2)) {
			// フォームのデータは、postmeta テーブルの中にフォームのname属性がそのまま登録されているので、今回は「都道府県」でOK
			$where .= $wpdb->prepare(" AND EXISTS ( SELECT * FROM {$wpdb->postmeta} as m
									WHERE m.post_id = {$wpdb->posts}.ID
									AND m.meta_key = '都道府県'
									AND m.meta_value %s )",
									 "%{$value2}%" );
		}
	}
	return $where;
};
add_filter('posts_where', 'posts_where_subtitle');

```


これでOK…かと思いきや、なぜか対応済みで検索したら未対応も出てくる。
未対応で検索しても対応済みは出てこないのでなぜだ…と思ったが、
MW WP Form側で用意されている`response_status`の初期値の「対応済み」は`supported`で、「未対応」は`not-supported`になっており、【supported】の文字が被っているのが原因。
memo情報も同じ場所に格納されている都合上、LIKEで部分一致するしかないので、「対応済み」で絞り込めば当然「未対応」も引っ掛かる。

コレに関しては、フィルターフックが用意されていたのでそれを使うことにした。

[フィルターフック＞mwform_response_statuses_mwf_xxx](https://plugins.2inc.org/mw-wp-form/filter-hook/mwform_response_statuses_mwf_xxx/)

上記のページのコード例では`array_merge`しているけど、元のコードを見てみるとそのまま上書きでも問題なさそう。

[mw-wp-form/classes/models/class.contact-data-setting.php](https://github.com/inc2734/mw-wp-form/blob/master/classes/models/class.contact-data-setting.php#L73-L83)

`$response_statuses`を上書きし、未対応はそのままで、対応済みに接頭語をつけることで解決した。
（保留にも接頭語をつけているけど、あまり意味はない）
ついでにいくつか項目も追加。

```php:function.php

// 対応状況のスラッグ変更
function my_mwform_response_statuses( $response_statuses ) {
	$response_statuses = array(
		'not-supported' => esc_html__( 'Not supported', 'mw-wp-form' ),
		'r_s_supported' => esc_html__( 'Supported', 'mw-wp-form' ),
		'r_s_reservation' => esc_html__( 'Reservation', 'mw-wp-form' ),
		'r_s_now_supporting' => '現在対応中',
		'r_s_non_supporting' => '対応不要'
	);
	return $response_statuses;
}
add_filter( 'mwform_response_statuses_mwf_***', 'my_mwform_response_statuses' ); // ***の部分は、フォームIDに合わせて変更する



// スラッグ変更に合わせて、先程のコードを一部変更する
function add_subtitle_filter(){
		// （前略）
		echo '<option value="">すべての対応状況</option>';
		$status = array(
			'not-supported' => '未対応',
			'r_s_supported' => '対応済み',
			'r_s_reservation' => '保留',
			'r_s_now_supporting' => '現在対応中',
			'r_s_non_supporting' => '対応不要'
		);
		// （後略）
};
add_action('restrict_manage_posts', 'add_subtitle_filter');

```


これでOK。
あとはクライアント側でメールアドレス・ニックネームを変更すれば、メールの送信先や振り分け条件をそのまま変更できる。

今回はニックネームが不要だったのでニックネームを使用したが、カスタムフィールドを用意してそちらを使ってもいい。
データベースの`meta_key`の部分が変わるだけなので、上記とほぼ同じやり方でできるはず。
カスタムフィールドを複数用意し、ANDやNOTを使い分ければ、複雑な条件にも対応できる。