勉強したことのメモ

Webエンジニア / プログラマが勉強したことのメモ。

Advanced Custom Fieldsでセレクトメニューを動的に生成する方法

   2024/02/20  WordPress CMS

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

  関連記事

Advanced Custom Fieldsで設定した項目を条件に記事一覧を取得する方法

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

Advanced Custom Fieldsでチェックボックスの記事を取得

Advanced Custom Fieldsでチェックボックス設定しているカスタ ...

WordPressにてACFで設定したカスタムフィールドの値を元に記事を並べ替える方法

WordPressにてAdvanced Custom Fieldsで設定したカス ...

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

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

Advanced Custom FieldsでGoogleMapの使用する方法

Advanced Custom FieldsでGoogleMapを使用したかった ...