2026年9月4日

2026年9月4日

ACF(Advanced Custom Fields)のフィールドが保存されない問題を解決する方法

はじめに

ACF(Advanced Custom Fields)でカスタムフィールドの値が保存されない・保存後に消える・フロントエンドでget_field()が空を返す問題は、フィールドグループのロケーション設定・フック優先度・ACFのデータ保存タイミングが原因です。

症状・原因

  • 投稿を保存してもACFフィールドの値が消える
  • get_field('field_name', $post_id)がnullまたはfalseを返す
  • ACFフィールドは表示されるが、保存後に値がリセットされる
  • フロントエンドでは値が表示されるが管理画面では空になっている

解決手順

ステップ1:ACFの保存状態を診断する

# ACFのバージョンとライセンスを確認
wp eval "
if (class_exists('ACF')) {
    echo 'ACF version: ' . acf_get_setting('version') . PHP_EOL;
}
// ACF Proの確認
if (class_exists('acf_pro')) {
    echo 'ACF Pro: active' . PHP_EOL;
}
"

# 特定の投稿のACFフィールド値を確認
wp eval "
\$post_id = 123; // 確認したい投稿ID
\$fields = get_fields(\$post_id);
if (\$fields) {
    foreach (\$fields as \$key => \$value) {
        echo \$key . ': ' . (is_array(\$value) ? json_encode(\$value) : \$value) . PHP_EOL;
    }
} else {
    echo 'No ACF fields found for post ' . \$post_id . PHP_EOL;
}
"

# postmetaに直接保存されているか確認
wp eval "
\$post_id = 123;
global \$wpdb;
\$meta = \$wpdb->get_results(\$wpdb->prepare(
    'SELECT meta_key, meta_value FROM %i WHERE post_id = %d AND meta_key NOT LIKE %s',
    \$wpdb->postmeta,
    \$post_id,
    '\_%'
));
foreach (\$meta as \$m) {
    echo \$m->meta_key . ': ' . substr(\$m->meta_value, 0, 100) . PHP_EOL;
}
"

ステップ2:フィールドグループのロケーション設定を確認する

# フィールドグループの一覧と設定を確認
wp eval "
\$groups = acf_get_field_groups();
foreach (\$groups as \$group) {
    echo 'Group: ' . \$group['title'] . ' (key: ' . \$group['key'] . ')' . PHP_EOL;
    echo 'Location: ' . json_encode(\$group['location']) . PHP_EOL;
    echo 'Active: ' . (\$group['active'] ? 'YES' : 'NO') . PHP_EOL;
    echo '---' . PHP_EOL;
}
"

# 特定の投稿タイプに表示されるフィールドグループを確認
wp eval "
\$post_id = 123;
\$post = get_post(\$post_id);
\$groups = acf_get_field_groups(['post_id' => \$post_id, 'post_type' => \$post->post_type]);
foreach (\$groups as \$group) {
    echo 'Active group for post: ' . \$group['title'] . PHP_EOL;
}
"
// functions.php: ACFフィールドグループをコードで登録(JSON/PHPモード)

// ① フィールドグループをPHPで定義(バージョン管理しやすい)
add_action('acf/init', function(): void {
    acf_add_local_field_group([
        'key'      => 'group_product_details',
        'title'    => '商品詳細',
        'fields'   => [
            [
                'key'   => 'field_product_price',
                'label' => '価格',
                'name'  => 'product_price',
                'type'  => 'number',
                'min'   => 0,
            ],
            [
                'key'   => 'field_product_description',
                'label' => '商品説明',
                'name'  => 'product_description',
                'type'  => 'textarea',
                'rows'  => 5,
            ],
        ],
        'location' => [
            [
                [
                    'param'    => 'post_type',
                    'operator' => '==',
                    'value'    => 'product',
                ],
            ],
        ],
        'active' => true,
    ]);
});

ステップ3:ACFの保存フックを正しく使う

// functions.php: ACFフィールド保存時の処理

// ① acf/save_post フック(ACFデータ保存後に実行)
add_action('acf/save_post', function(int $post_id): void {
    // ACFデータが保存された後に実行される
    $price = get_field('product_price', $post_id);
    $category = get_field('product_category', $post_id);

    // ACFデータを元に他のpostmetaを更新
    if ($price !== null) {
        update_post_meta($post_id, '_regular_price', $price);
        update_post_meta($post_id, '_price', $price);
    }

    error_log('[ACF] Post ' . $post_id . ' saved with price: ' . $price);
}, 20); // 優先度20(ACFのデフォルトは10)でデータ保存後に確実に実行

// ② フィールド値が変更された時のフック
add_action('acf/update_value/name=product_price', function($value, int $post_id, array $field): void {
    // 価格が変更されたときに税込価格を自動計算
    $tax_included = $value * 1.1;
    update_post_meta($post_id, 'product_price_with_tax', $tax_included);
}, 10, 3);

// ③ フィールド値の保存前にバリデーション
add_filter('acf/validate_value/name=product_price', function($valid, $value, array $field, string $input): mixed {
    if (!$valid) return $valid;

    if ((float)$value < 0) {
        return '価格は0以上で入力してください';
    }
    if ((float)$value > 9999999) {
        return '価格は9,999,999円以下で入力してください';
    }
    return $valid;
}, 10, 4);

ステップ4:プログラムでACFフィールドを操作する

// functions.php: ACFフィールドをコードで読み書き

// ① フィールド値を取得(推奨方法)
function get_product_details(int $post_id): array {
    return [
        'price'       => (float) get_field('product_price', $post_id),
        'description' => get_field('product_description', $post_id) ?: '',
        'images'      => get_field('product_images', $post_id) ?: [],
        'category'    => get_field('product_category', $post_id),
    ];
}

// ② フィールド値を更新(update_field はフィールドキーが必要)
function update_product_price(int $post_id, float $price): void {
    // フィールド名で更新
    update_field('product_price', $price, $post_id);

    // フィールドキーで更新(より確実)
    // update_field('field_product_price', $price, $post_id);
}

// ③ リピーターフィールドを操作
function add_product_specification(int $post_id, string $name, string $value): void {
    $specs = get_field('specifications', $post_id) ?: [];
    $specs[] = ['spec_name' => $name, 'spec_value' => $value];
    update_field('specifications', $specs, $post_id);
}
# WP-CLIでACFフィールドを直接更新
wp eval "
\$post_id = 123;
// フィールド値を設定
update_field('product_price', 9800, \$post_id);

// フィールドキーも保存(ACFがフィールドを認識するために必要)
update_post_meta(\$post_id, '_product_price', 'field_product_price');

// 確認
\$saved = get_field('product_price', \$post_id);
echo 'Saved price: ' . \$saved . PHP_EOL;
"

ステップ5:ACF JSONとバージョン管理を設定する

// functions.php: ACF JSONの保存先を設定(チーム開発向け)

// ① ACF JSONの保存先をテーマフォルダに変更
add_filter('acf/settings/save_json', function(string $path): string {
    return get_stylesheet_directory() . '/acf-json';
});

// ② ACF JSONの読み込み先を追加
add_filter('acf/settings/load_json', function(array $paths): array {
    $paths[] = get_stylesheet_directory() . '/acf-json';
    return $paths;
});
# ACF JSONからフィールドグループを同期
wp eval "
// acf-json/ ディレクトリのJSONファイルを確認
\$json_dir = get_stylesheet_directory() . '/acf-json/';
if (is_dir(\$json_dir)) {
    \$files = glob(\$json_dir . '*.json');
    echo count(\$files) . ' JSON files found' . PHP_EOL;
    foreach (\$files as \$f) {
        echo basename(\$f) . PHP_EOL;
    }
}
"

# ACFフィールドグループを全て再保存(DB→JSON同期)
wp eval "
\$groups = acf_get_field_groups();
foreach (\$groups as \$group) {
    acf_update_field_group(\$group);
    echo 'Saved: ' . \$group['title'] . PHP_EOL;
}
"

注意事項

  • update_field()でフィールド値を更新する際は、フィールド名だけでなく_フィールド名というメタキーにフィールドキー(field_xxxxxxxx形式)も同時に保存する必要があります。これがないとACFはフィールドを認識できません
  • acf/save_postフックは優先度10でACFのデータ保存が行われるため、保存後に処理したい場合は優先度20以上を使ってください(優先度10では保存前に実行される)
  • ACF Proのオプションページ(acf_add_options_page())のデータはget_field('field_name', 'option')のようにpost_idに'option'を指定して取得します

まとめ

ACFフィールド保存問題の解決は①get_fields($post_id)と直接postmetaクエリで保存状態を診断、②フィールドグループのロケーション設定をacf_add_local_field_group()でPHP定義に移行、③acf/save_postフックの優先度を20に設定してACFデータ保存後に後処理、④update_field()と同時に_フィールド名メタキーにフィールドキーを保存、⑤acf/settings/save_jsonフィルターでACF JSONをテーマフォルダに保存してGit管理する手順で解決します。

お気軽にご相談ください

お見積りへ お問い合わせへ