ACF Quick Edit Fields でプルダウン(select2)にデフォルト値を設定する方法

### ACF Quick Edit Fields とは？

https://ja.wordpress.org/plugins/acf-quickedit-fields/

WordpressのACF(Advanced Custom Field)で作成したカスタムフィールドを、
記事一覧画面のクイック編集で編集できるようになる神プラグインです。

### 何が問題か

このプラグイン、投稿オブジェクト型だとプルダウンのデフォルト値が設定されないようです。

これの何が問題かというと、すでに編集画面で何らかの値を選択していたとしても、
クイック編集画面に表示していた場合、更新ボタンを押すと、それらの値がクリアされてしまうことです。

軽く調べてもデフォルト値を設定する方法がわからなかったので自分で実装することにしました。

もっと簡単なやり方をご存知の方がいたら、ぜひコメントをお願いいたします。

### 実装

```php:/wp-content/themes/{theme_name}/functions.php
/**
 * ACFクイック編集でAJAX処理をするのに必要なライブラリを読み込む
 * @return void
 */
function get_acf_qed_values_ajax_preload()
{
    // スクリプトファイルのパス
    $script_path = get_stylesheet_directory_uri() . '/js/acf-quick-edit-fix.js';

    // ハンドル名
    $handle = 'acf-quick-edit-fix';

    // スクリプトを登録して読み込む
    wp_register_script($handle, $script_path, array('jquery'), '1.0.0', true);
    wp_enqueue_script($handle);

    // nonce値を生成
    $nonce = wp_create_nonce('_acf_my_qed_nonce');

    $params = [
        'ajax_url' => admin_url('admin-ajax.php'),
        'nonce' => $nonce
    ];

    $js_variable_name = "acf_my_qed_ajax_params";
    wp_localize_script($handle, $js_variable_name, $params);
}
add_action('admin_enqueue_scripts', 'get_acf_qed_values_ajax_preload');

/**
 * ACFクイック編集のAJAX処理ハンドラ
 * @return void
 */
function get_acf_qed_values_ajax_handler()
{
    // セキュリティチェック
    check_ajax_referer('_acf_my_qed_nonce', 'nonce');

    $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;

    if (! $post_id) {
        wp_send_json_error('Invalid request');
        return;
    }

    // ACFフィールドの値を取得
    $custom_fields = get_fields($post_id);
    $field_data = [];

    if ($custom_fields) {
        foreach ($custom_fields as $field_name => $value) {
            $field = acf_get_field($field_name); // フィールド情報を取得
            if ($field) {
                $field_data[$field_name] = process_acf_qed_field($field, $value);
            } else {
                $field_data[$field_name] = [
                    'field_key' => null,
                    'label' => null,
                    'value' => $value,
                ];
            }
        }

        wp_send_json_success([
            'post_id' => $post_id,
            'custom_fields' => $field_data
        ]);
    } else {
        wp_send_json_error('Field value not found');
    }

    wp_die();
}
add_action('wp_ajax_get_acf_qed_values', 'get_acf_qed_values_ajax_handler');

/**
 * 再帰的にACFのフィールドデータを処理
 */
function process_acf_qed_field($field, $value)
{
    $field_data = [
        'field_key' => $field['key'],
        'label' => $field['label'],
        'value' => $value,
    ];

    // グループフィールドやリピーターフィールドの処理
    if (!empty($field['type']) && in_array($field['type'], ['group', 'repeater', 'flexible_content'])) {
        if (is_array($value)) {
            $field_data['sub_fields'] = [];
            foreach ($value as $sub_key => $sub_value) {
                if ($field['type'] === 'group') {
                    // グループフィールドの場合、サブフィールドの情報を取得
                    if (isset($field['sub_fields'])) {
                        foreach ($field['sub_fields'] as $sub_field) {
                            if ($sub_field['name'] === $sub_key) {
                                $field_data['sub_fields'][$sub_key] = process_acf_qed_field($sub_field, $sub_value);
                            }
                        }
                    }
                } elseif ($field['type'] === 'repeater' || $field['type'] === 'flexible_content') {
                    // リピーター・フレキシブルコンテンツの場合、各行を処理
                    if (isset($field['sub_fields'])) {
                        foreach ($value as $index => $row) {
                            $field_data['sub_fields'][$index] = [];
                            foreach ($field['sub_fields'] as $sub_field) {
                                if (isset($row[$sub_field['name']])) {
                                    $field_data['sub_fields'][$index][$sub_field['name']] = process_acf_qed_field($sub_field, $row[$sub_field['name']]);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return $field_data;
}
```

```javascript:/wp-content/themes/{theme_name}/js/acf-quick-edit-fix.js
jQuery(document).ready(function ($) {
  // クイック編集ボタンがクリックされたときの処理
  $("table.wp-list-table.posts").on("click", "button.editinline", function () {
    // 記事IDを取得（親のtrタグのid属性から）
    const $tr = $(this).closest("tr");
    const postID = $tr.attr("id").replace("post-", "").replace("edit-", "");
    const nonceValue = acf_my_qed_ajax_params.nonce; // functions.php get_acf_qed_values_ajax_preload で定義($js_variable_name)

    console.log("Quick Edit Current postID:", postID);
    console.log("Nonce Value:", nonceValue);

    // WordPressのajaxurl変数が定義されているか確認
    if (typeof ajaxurl === "undefined") {
      console.error("ajaxurl is not defined");
      return;
    }

    // AJAXで現在の値を取得
    $.ajax({
      url: ajaxurl, // e.g. "/wp-admin/wp-ajax.php"
      type: "POST",
      data: {
        action: "get_acf_qed_values", // functions.php get_acf_qed_values_ajax_handler の action名
        post_id: postID,
        nonce: nonceValue,
      },
    })
      .done(function (response) {
        console.log(response);

        if (!response.success) return false;

        const custom_fields = response.data.custom_fields;
        setQuickEditOptions(custom_fields);
      })
      .fail(function (XMLHttpRequest, status, e) {
        console.error(status);
        console.error(XMLHttpRequest);
        console.error(e);
      });
  });

  function setQuickEditOptions(custom_fields) {
    const fieldGroupName = "group_name";
    const subFields = custom_fields[fieldGroupName].sub_fields;
    console.log("subFields:", subFields);
    for (let i in subFields) {
      const subField = subFields[i];
      const field_key = subField.field_key;
      const value = subField.value;
      const select2 = "select#acf_qed_" + field_key; // e.g. "select#acf_qed_field_67344dc275967"

      if (! value) {
        // 値がない場合、既存のoptionをクリア
        $(select2).empty().trigger("change");
        continue;
      }

      console.log(value);

      const post_title = value.post_title;
      const related_post_id = value.ID;

      setQuickEditOption(select2, post_title, related_post_id);
    }
  }

  /**
   * クイック編集の投稿オブジェクト型プルダウン(select2)にデフォルト値をセットする
   */
  function setQuickEditOption(select2, field_label, field_value) {
    console.log("set Quick Edit Option");
    console.log(select2, field_label, field_value);
    const label = field_label; // e.g. "プルダウンの表示値"
    const value = field_value; // e.g. "プルダウンの値"
    const newOption = new Option(label, value, true, true);
    $(select2).append(newOption).trigger("change");
  }
});
```