MW WP Formで動的にプルダウンの項目を変更する

24歳、習作です。
MW WP Formを使って記事タイトルのようなことをやりたかったのですが、ググってもそれっぽい記事がなかったので自分で組んでみました。

# 概要
![hoge.png](https://qiita-image-store.s3.amazonaws.com/0/197489/364acbf2-7062-e626-bf37-551d6a5cf8ca.png)

要するにこういうやつです。
それぞれの項目はカスタム投稿で管理し、希望コース名は投稿タイトル、希望日時はカスタムフィールドで入力するとします。

なお、カスタムフィールドは自由に項目数を増減できるようにWPAlchemyのRepeating Field Groupsを使用しています。
参考：[WPAlchemy MetaBox PHP Class#Repeating Field Groups](http://www.farinspace.com/wpalchemy-metabox/#have_fields_and_multi)

※Advanced Custom FieldsのRepeater Fieldアドオンでもできると思います

# 大まかな流れ
希望コースのプルダウンを変更する
　↓
変更後の値を取得し、AjaxでAPIにリクエストして希望日時の一覧を取得する
　↓
取得した希望日時の一覧をjQueryでプルダウンにセットする

# 前提条件
<dl>
	<dt>カスタム投稿名</dt>
	<dd>course</dd>
	<dt>カスタムフィールドグループ名</dt>
	<dd>variable_date</dd>
	<dt>希望日時のカスタムフィールド名</dt>
	<dd>date</dd>
</dl>
以上の条件でカスタム投稿およびカスタムフィールドを定義しているものとします。

# コード
```html:フォーム
<dl>
	<dt><label for="course">希望コース</label></dt>
	<dd>[mwform_select name="course_name" id="course"]</dd>
	<dt><label for="date">希望日時</label></dt>
	<dd>[mwform_select name="course_date" id="date"]</dd>
</dl>
```
通常通り、MW WP Formの記法でプルダウンの項目を作成します。
なお、プルダウンの値はフィルターフックを使って挿入するのでフォーム側のコードでは入力しません。

```php:functions.php
/**
 * フォームのプルダウンの値を出力する
 * @param	array	$children	select配下のoption値
 * @return	array	$atts	フォームの要素
 */
function set_select_children($children, $atts){
	// カスタム投稿名courseの投稿を全て取得し、各投稿のタイトルを希望コースのプルダウンの値として挿入する
	if($atts['name'] == 'course_name'){
		$args = array(
			'post_type' => 'course',
			'posts_per_page' => -1,
			'post_status' => 'publish'
		);
		$posts = get_posts($args);
		foreach($posts as $post){
			$children[$post->post_title] = $post->post_title;
		}
	}
	// カスタム投稿名courseの投稿を全て取得し、かつ各投稿のカスタムフィールドを全て取得した上で
	// 希望日時のプルダウンの値として挿入する
	elseif($atts['name'] == 'course_date'){
		$args = array(
			'post_type' => 'course',
			'posts_per_page' => -1,
			'post_status' => 'publish'
		);
		$posts = get_posts($args);
		foreach($posts as $post){
			$dates = get_post_meta($post->ID, 'variable_date', true);
			foreach($dates as $date){
				$children[$date['date']] = $date['date'];
			}
		}
	}
	return $children;
}
add_filter('mwform_choices_mw-wp-form-xxx', 'set_select_children', 10, 2);
```
functions.phpに、MW WP Formのmwform_choices_mw-wp-formのフィルターフックを使用して各プルダウンに値をセットする関数を記載します。
参考：[mwform_choices_mw-wp-form-xxx | MW WP Form](https://plugins.2inc.org/mw-wp-form/filter-hook/mwform_choices/)

```api.php
require_once('../../../wp-load.php');

$args = array(
	'post_type' => 'course',
	'posts_per_page' => -1,
	'post_status' => 'publish',
	's' => $_POST['course'],
	'exact' => true
);
$post = reset(get_posts($args));

$dates = get_post_meta($post->ID, 'variable_date', true);
foreach($dates as $date){
	$return_data[] = $date['date'];
}
$return_data = json_encode($return_data);

echo $return_data;
```
テーマフォルダ直下にAjax用のAPIを作成します。
postされた値をカスタム投稿名courseの投稿一覧から検索し、該当する投稿のカスタムフィールドから値を取得して配列に格納し、JSON形式で値を返します。

※このへんはWordPressのREST APIを使用すればわざわざファイルを作る必要はないかもしれません

```js:form.js
(function($){
	$(function(){
		set_date_value();

		$('#course').change(function(){
			set_date_value();
		});
	});

	function set_date_value(){
		$.ajax({
			url: '/wp-content/themes/theme_name/api.php',
			type: 'post',
			dataType: 'json',
			data: {
				course: $('#course').val()
			}
		})
		.done(function(response){
			var date = $('#date').val(),
				selected_val = null;

			$('#date').children().remove();
			$.each(response, function(index, value){
				$('#date').append($("<option>").val(value).text(value));
				if(value == date){
					selected_val = value;
				}
			});
			if(selected_val == null){
				selected_val = $('#date option:eq(0)').val();
			}
			$('#date').val(selected_val);
		})
		.fail(function(){
			alert('エラーが発生しました。');
		});
	}
})(jQuery);
```
フォームのページで読み込むJavaScriptファイルです。
テーマフォルダ直下のapi.phpにAjaxを使用してpostを行い、値が返ってきたら希望日時のプルダウンの中身を空にした上で返ってきた値をセットします。

# 終わりに
かなり場当たり的なコードなので正直スマートなやり方ではないなあと自分でも思うのですが、参考までに。
バリデーションやプルダウンの最初の項目を「選択してください」的なものにすることはあまり考慮していませんが、そちらは別途検証したいと思います。