勉強したことのメモ

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

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

   

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でメモリを節約しつつ高速化する設定方法

メモリ1GのVPSを借りてWordpress以外にも、ちょいちょいものを置いてい ...

さくらvpsにワードプレスを導入

さくらvpsで立ち上げたサーバーにWordPressを導入した際のメモ。 ①ダウ ...

WordPressのサーバー移行で気付いた点

あるWordPressを置いているサーバーのリソースが苦しくなってきたので、新た ...

WordPressでテーマの作成

CSSとHTMLコーディングデータがあり、それをWordPressのテーマに反映 ...

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

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

WordPressでSNSボタンが表示されない

WordPressでWordPress WP Social Bookmarkin ...

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

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

contact form7で500エラー

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

Advanced Custom Fieldsで記事取得

WordPressでAdvanced Custom Fieldsにて設定した項目 ...

WordPressのウィジェットをTOPのみ等、特定のページだけ表示する方法

■やりたかった事 TOPページのみ任意のウィジェットを表示させ、記事ページやアー ...