2026年9月10日

2026年9月10日

WooCommerce Product Add-Onsのエラーを解決する方法

はじめに

WooCommerce Product Add-Onsで商品ページでオプションを選択してもカート・注文合計金額に追加料金が反映されない・必須項目として設定したアドオンをスキップして購入できてしまう・注文確認メールにアドオンで入力した内容(名前入れ・メッセージカードなど)が記載されない・アドオンの選択内容が注文管理画面で確認できないといった問題は、プラグインのバージョン・テーマとのJavaScript競合・フックの優先度が原因です。

症状・原因

  • 商品ページでアドオン(+500円の名入れ)を選択してもカートでは元の価格のまま表示される
  • 「必須」に設定したアドオンフィールドが空のままでも「カートに追加」ができてしまう
  • 注文完了メールを確認するとアドオンで入力した内容(メッセージ文など)が含まれていない
  • WooCommerce管理画面の注文詳細でアドオン選択内容が表示されない

解決手順

ステップ1:Product Add-Onsの状態を確認する

# WooCommerce Product Add-Onsの設定確認
wp eval "
if (defined('WC_PRODUCT_ADDONS_VERSION')) {
    echo 'WC Product Add-Ons version: ' . WC_PRODUCT_ADDONS_VERSION . PHP_EOL;
}

// アドオンが設定された商品を確認
\$products = get_posts([
    'post_type'      => 'product',
    'posts_per_page' => 10,
    'meta_key'       => '_product_addons',
    'meta_compare'   => 'EXISTS',
]);

echo 'Products with add-ons: ' . count(\$products) . PHP_EOL;

foreach (\$products as \$product_post) {
    \$product = wc_get_product(\$product_post->ID);
    \$addons  = get_post_meta(\$product_post->ID, '_product_addons', true);
    printf('  Product #%d: %s | Add-ons: %d' . PHP_EOL,
        \$product_post->ID,
        \$product->get_name(),
        is_array(\$addons) ? count(\$addons) : 0
    );

    if (is_array(\$addons)) {
        foreach (array_slice(\$addons, 0, 3) as \$addon) {
            printf('    - %s | Type: %s | Required: %s | Price: %s' . PHP_EOL,
                \$addon['name'] ?? '',
                \$addon['type'] ?? '',
                (\$addon['required'] ?? 0) ? 'yes' : 'no',
                \$addon['price'] ?? '0'
            );
        }
    }
}
"

ステップ2:アドオン価格計算を修正する

// functions.php: Product Add-Ons価格計算

// ① カートアイテムにアドオンデータを追加
add_filter('woocommerce_add_cart_item_data', function(array $cart_item_data, int $product_id): array {
    if (empty($_POST['addon-'])) return $cart_item_data;

    // アドオン選択をサニタイズして保存
    $addons   = get_post_meta($product_id, '_product_addons', true);
    $selected = [];

    foreach ((array) $addons as $addon) {
        $field_name = sanitize_title($addon['name'] ?? '');
        if (!empty($_POST['addon-' . $field_name])) {
            $selected[] = [
                'name'  => $addon['name'],
                'value' => sanitize_text_field($_POST['addon-' . $field_name]),
                'price' => (float) ($addon['price'] ?? 0),
            ];
        }
    }

    if (!empty($selected)) {
        $cart_item_data['addons'] = $selected;
    }

    return $cart_item_data;
}, 10, 2);

// ② カートアイテムの価格にアドオン料金を加算
add_filter('woocommerce_add_cart_item', function(array $cart_item): array {
    if (empty($cart_item['addons'])) return $cart_item;

    $extra_price = array_sum(array_column($cart_item['addons'], 'price'));
    if ($extra_price > 0) {
        $cart_item['data']->set_price(
            $cart_item['data']->get_price() + $extra_price
        );
    }
    return $cart_item;
});

// ③ セッション復元時にもアドオン価格を反映
add_filter('woocommerce_get_cart_item_from_session', function(array $cart_item, array $values): array {
    if (empty($values['addons'])) return $cart_item;

    $cart_item['addons'] = $values['addons'];
    $extra_price = array_sum(array_column($values['addons'], 'price'));
    if ($extra_price > 0) {
        $cart_item['data']->set_price(
            $cart_item['data']->get_price() + $extra_price
        );
    }
    return $cart_item;
}, 10, 2);

ステップ3:必須アドオンのバリデーションを修正する

// functions.php: アドオンバリデーション

// ① カート追加前に必須アドオンを検証
add_filter('woocommerce_add_to_cart_validation', function(bool $passed, int $product_id): bool {
    $addons = get_post_meta($product_id, '_product_addons', true);
    if (!is_array($addons)) return $passed;

    foreach ($addons as $addon) {
        if (empty($addon['required'])) continue;

        $field_name = sanitize_title($addon['name'] ?? '');
        $posted_value = $_POST['addon-' . $field_name] ?? '';

        if (empty($posted_value)) {
            wc_add_notice(
                sprintf('「%s」は必須項目です。', esc_html($addon['name'])),
                'error'
            );
            $passed = false;
        }
    }

    return $passed;
}, 10, 2);

ステップ4:注文メタにアドオン情報を保存する

// functions.php: 注文メタ保存

// ① カートアイテムのアドオンを注文アイテムメタに保存
add_action('woocommerce_checkout_create_order_line_item', function(
    WC_Order_Item_Product $item,
    string $cart_item_key,
    array $values,
    WC_Order $order
): void {
    if (empty($values['addons'])) return;

    foreach ($values['addons'] as $addon) {
        $item->add_meta_data(
            esc_html($addon['name']),
            esc_html($addon['value']),
            true
        );
    }

    // 合計アドオン料金を記録
    $total_addon_price = array_sum(array_column($values['addons'], 'price'));
    if ($total_addon_price > 0) {
        $item->add_meta_data('_addon_total', $total_addon_price, true);
    }
}, 10, 4);

// ② 注文メールにアドオン情報を表示
add_filter('woocommerce_order_item_get_formatted_meta_data', function(array $meta_data, WC_Order_Item $item): array {
    foreach ($meta_data as $meta) {
        // 内部メタキー(_addon_total等)は非表示
        if (str_starts_with($meta->key, '_')) {
            $meta->display_key   = '';
            $meta->display_value = '';
        }
    }
    return $meta_data;
}, 10, 2);

ステップ5:アドオンのデバッグと修正

# 注文アイテムのアドオンメタを確認
wp eval "
\$order_id = 100; // 確認する注文ID
\$order = wc_get_order(\$order_id);

if (!\$order) {
    echo 'Order not found' . PHP_EOL;
    exit;
}

echo '=== Order #' . \$order_id . ' ===' . PHP_EOL;

foreach (\$order->get_items() as \$item_id => \$item) {
    echo 'Item: ' . \$item->get_name() . PHP_EOL;
    echo 'Total: ' . wc_price(\$item->get_total()) . PHP_EOL;

    \$meta_data = \$item->get_formatted_meta_data('_', true);
    if (empty(\$meta_data)) {
        echo '  No meta data (add-ons may not be saved)' . PHP_EOL;
    } else {
        foreach (\$meta_data as \$meta) {
            printf('  %s: %s' . PHP_EOL,
                strip_tags(\$meta->display_key),
                strip_tags(\$meta->display_value)
            );
        }
    }
}
"

注意事項

  • WooCommerce Product Add-Onsのバージョンと現在のWooCommerceバージョンの互換性を必ず確認してください。WooCommerce 8.0以降では旧バージョンのAdd-Onsでアドオン価格が正しく計算されないバグが報告されています
  • カスタムコードでアドオン価格を計算する場合、woocommerce_cart_item_priceフィルターとwoocommerce_get_cart_item_from_sessionフックの両方で価格を設定しないと、ページリロード後に価格がリセットされます
  • 多言語サイト(WPMLやPolylang使用)では商品のアドオン設定が各言語バージョンに個別に設定されている必要があります。元の言語でのみ設定して翻訳版で設定しないと翻訳ページでアドオンが表示されません

まとめ

WooCommerce Product Add-Ons修復は①_product_addonsメタで設定済みアドオン一覧・必須/価格設定を確認、②woocommerce_add_cart_item_dataフィルターでアドオン選択をサニタイズ保存・woocommerce_add_cart_itemフィルターでset_price()にアドオン料金加算・get_cart_item_from_sessionでセッション復元時にも価格反映、③woocommerce_add_to_cart_validationフィルターで必須アドオンが空の場合wc_add_notice()でエラー表示、④woocommerce_checkout_create_order_line_itemフックで注文アイテムメタにアドオン情報保存・get_formatted_meta_dataフィルターで内部キーを非表示、⑤注文アイテムのメタデータで保存状態を確認する手順で解決します。

お気軽にご相談ください

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