勉強したことのメモ

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

  関連記事

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

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

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

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

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

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

WordPressでカスタムフィールドとCSVファイル投稿する方法

WordPressでカスタムフィールド設定している環境に、CSVファイルアップロ ...

WordPressにてAdvanced Custom Fieldsを用いて連載(シリーズ)記事機能を実装する方法

先日「Series」プラグインで連載(シリーズ)記事機能の実装方法をメモしたが、 ...