勉強したことのメモ

webプログラマが勉強したことのメモ。

ACFでセレクトメニューを動的に生成

      2019/02/04

WordPressでカスタムフィールド設定用のプラグインAdvanced Custom Fieldsを使用中の環境で、記事投稿ページからセレクトメニューを選択すると、選択したものと連動したセレクトメニューが次に表示されるというシステムが欲しかった。以下に方法をメモ。

 

やりたいこと

八地方区分(関東、近畿等)をプルダウンから選ぶと区分内の都道府県プルダウンが表示され、さらに都道府県を選ぶと路線が、路線を選ぶと駅名が選択できるといった一連のセレクトメニューをWordPressの記事一覧ページに作成したかった。

都道府県等のデータ用意やセレクトメニュー自体の作成方法は以下記事を参照。

八地方区分→都道府県→路線→駅名の連携したセレクトメニュー

 

ACF側の設定

以下のような形で設定しておく。

フィールドラベル フィールド名 フィールドタイプ 選択肢
八地方区分 region セレクトメニュー 1 : 北海道
2 : 東北地方
3 : 関東地方
4 : 中部地方
5 : 近畿地方
6 : 中国地方
7 : 四国地方
8 : 九州地方
都道府県 prefecture セレクトメニュー 空でOK
路線種別 line ラジオボタン 0 : 地下鉄
1 : 私鉄
2 : JR
地下鉄 subway セレクトメニュー 空でOK
私鉄 private セレクトメニュー 空でOK
JR jr セレクトメニュー 空でOK
station セレクトメニュー 空でOK

 

 

functions.phpに追記

#js呼び出し
function search_station_js($hook) {
	if($hook == 'post.php' || $hook == 'post-new.php'){
		#JSファイル設置場所
		wp_enqueue_script('custom_admin_script', '/hogehoge/js/search_station.js', array('jquery'));
	}
}
add_action('admin_enqueue_scripts', 'search_station_js');

#ajax受信用
function search_station(){

	#DB接続
	global $wpdb;
	$mysqli = new mysqli($wpdb->dbhost, $wpdb->dbuser, $wpdb->dbpassword, $wpdb->dbname);
	$mysqli->set_charset('utf8');

	$mode = $_POST['mode'];

	$result = false;

	#エリア選択
	if( $mode == 'region' && $_POST['id'] ){
		$sql = '
			SELECT * 
			FROM cps_prefecture 
			WHERE region_id = "' . $mysqli->real_escape_string($_POST['id']) . '"
		';
		$row = $mysqli->query($sql);
		while ($rs = $row->fetch_array(MYSQLI_ASSOC)) {
			$result[] = $rs;
		}

	#都道府県選択
	}else if( $mode == 'prefecture' && $_POST['id'] ){
		$sql = '
			SELECT 
				c.company_cd, c.company_name, c.company_name_r, c.company_type, c.subway, 
				l.line_name, l.line_cd, 
				s.pref_cd 
			FROM cps_company AS c 
			LEFT JOIN cps_line AS l 
			ON c.company_cd = l.company_cd
			LEFT JOIN cps_station AS s 
			ON l.line_cd = s.line_cd 
			WHERE s.e_status = 0 
			AND l.e_status = 0 
			AND s.e_status = 0 
			AND s.pref_cd = "' . $mysqli->real_escape_string($_POST['id']) . '" 
			GROUP BY l.line_cd
		';
		$row = $mysqli->query($sql);
		while ($rs = $row->fetch_array(MYSQLI_ASSOC)) {
			$result[] = $rs;
		}

	#路線選択
	}else if( $mode == 'station' && $_POST['id'] ){
		$sql = '
			SELECT * 
			FROM cps_station 
			WHERE line_cd = "' . $mysqli->real_escape_string($_POST['id']) . '" 
			AND e_status = 0 
		';
		$row = $mysqli->query($sql);
		while ($rs = $row->fetch_array(MYSQLI_ASSOC)) {
			$result[] = $rs;
		}
	}

	#結果がある場合は返す
	if( $result ){
		echo json_encode($result);
	}

	die();
}
add_action( 'wp_ajax_select_station', 'search_station' );

wp-config.phpで設定されているMySQLのログイン情報が定数だったのでそのまま「DB_PASSWORD」とかで取得しようとしたらエラーが起きた。以下で取得できるというのを初めて知った。
global $wpdb;
$mysqli = new mysqli($wpdb->dbhost, $wpdb->dbuser, $wpdb->dbpassword, $wpdb->dbname);

 

JavaScript

今回だと「/hogehoge/js/search_station.js」のファイルを以下内容でアップロードする。

//ACF設定画面のKeyをここに書く
var region_id = 'acf-field_xxxxxxxxxxxxxx';
var prefecture_id = 'acf-field_xxxxxxxxxxxxxx';
var subway_id = 'acf-field_xxxxxxxxxxxxxx';
var private_id = 'acf-field_xxxxxxxxxxxxxx';
var jr_id = 'acf-field_xxxxxxxxxxxxxx';
var station_id = 'acf-field_xxxxxxxxxxxxxx';

(function($) {
	$(document).ready(function(){

		$(document).on( 'change blur', `#${region_id}, #${prefecture_id}, #${subway_id}, #${private_id}, #${jr_id}`, function(){

			var selecter_id = $(this).attr("id");

			//エリア選択
			if( selecter_id == region_id ){
				var mode = 'region';

			//都道府県選択
			}else if( selecter_id == prefecture_id ){
				var mode = 'prefecture';

			//路線選択
			}else{
				var mode = 'station';
			}

			$.ajax({
				type: 'POST',
				url: ajaxurl,
				data: {
					'action' : 'select_station', 
					'id' : $(this).val(), 
					'mode' : mode
				},
				success: function( result ){

					//エリア選択
					if( selecter_id == region_id ){
						var prefecture = $.parseJSON(result);
						var html = '';
						for(var key in prefecture){
							html += '<option value="' + prefecture[key]['id'] + '">' + prefecture[key]['name'] + '</option>';
						}
						$('#' + prefecture_id).html(html);

					//都道府県選択
					}else if( selecter_id == prefecture_id ){
						var line = $.parseJSON(result);
						var subway = '';
						var private = '';
						var jr = '';

						for(var key in line){
							if( line[key]['subway'] == 1 ){
								subway += '<option value="' + line[key]['line_cd'] + '">' + line[key]['line_name'] + '</option>';
							}else if( line[key]['company_type'] == 1 ){
								jr += '<option value="' + line[key]['line_cd'] + '">' + line[key]['line_name'] + '</option>';
							}else{
								private += '<option value="' + line[key]['line_cd'] + '">' + line[key]['line_name'] + '</option>';
							}
						}

						$('#' + subway_id).html(subway);
						$('#' + private_id).html(private);
						$('#' + jr_id).html(jr);

					//路線選択
					}else{
						var station = $.parseJSON(result);
						var html = '';
						for(var key in station){
							html += '<option value="' + station[key]['station_cd'] + '">' + station[key]['station_name'] + '</option>';
						}
						$('#' + station_id).html(html);
					}

				}
			});
			return false;
		});
	});
})(jQuery);

WordPressでajax通信をする際はajaxurl(/wp-admin/admin-ajax.php)にリクエストしないといけないらしい。最初適当なディレクトリに突っ込んで呼び出そうとしたがエラーが起きた。

あとACFを使っているとjQuery等で各カスタムフィールドが後から追加されるので、4行目の部分は以下の通り注意する。

#後から追加される要素はこれだと動かない
$('セレクタ').change(function()){

#これだと動く
$(document).on( 'change blur', `セレクタ`, function(){

 - WordPress, CMS

  関連記事

WordPressを停止しないままサーバ移設する方法

WordPressを設置しているサーバのリソースがそろそろ危ういので移設を検討す ...

WordPressで記事毎に設定した広告を表示させる方法

WordPressでGoogleアドセンスのようなクリック広告ではなく、商品を指 ...

WordPressで任意のクエリをページに出力するプラグイン

先日、「WordPressで任意のクエリをページ内で出力する方法 」という記事で ...

WordPressのxmlrpc.phpへの攻撃

サーバーの死活監視をしているシステムから、1つのサイトが落ちているとアラートがき ...

WordPress5のエディタを元に戻す方法

WordPress5にアップデートしたところ記事投稿ページのエディタが非常に使い ...

WordPressで固定ページに記事一覧を表示させるプラグイン

WordPressで固定ページ編集時にショートコードを書くことで、記事一覧を表示 ...

Polylangのスイッチャーでクエリを引き継ぐ

WordPressで多言語サイトを作成するにあたりPolylangというプラグイ ...

contact form7で500エラー

WordPressプラグインのcontact form7で送信ボタンを押し、ロー ...

WordPressで「データベース接続確立のエラー」

WordPressで設定ファイル(wp-config.php)は触っていないのに ...

WordPressでNo URL was~というエラー

WordPressでmp4ファイルをアップロードして記事に埋め込んだものの、記事 ...