2026年6月20日

2026年6月20日

WooCommerceのバリエーション商品が正しく動かない問題を解決する方法

はじめに

WooCommerceのバリエーション商品(サイズ・カラー選択など)で「選択できない」「価格が変わらない」「在庫ありなのに選択不可になる」問題は、バリエーション数の上限・属性設定・JavaScriptエラーが原因です。

症状・原因

  • バリエーションのドロップダウンが空のまま
  • サイズ・カラーを選択しても価格・在庫が更新されない
  • 50個以上のバリエーションがある商品でAjaxが失敗する
  • 特定の組み合わせだけ選択できない

解決手順

ステップ1:バリエーション設定の現状を確認する

# バリエーション商品の状態を確認
wp eval "
\$product = wc_get_product(123);
if (!\$product || \$product->get_type() !== 'variable') {
    echo '可変商品ではありません';
    exit;
}
printf('Variations: %d, Attributes: %d' . PHP_EOL,
    count(\$product->get_children()),
    count(\$product->get_attributes())
);
foreach (\$product->get_children() as \$variation_id) {
    \$v = wc_get_product_object('variation', \$variation_id);
    printf('  #%d: %s - 在庫:%s 価格:%s' . PHP_EOL,
        \$variation_id,
        implode('/', \$v->get_variation_attributes()),
        \$v->get_stock_status(),
        \$v->get_price()
    );
}
"

# バリエーション上限を確認
wp option get woocommerce_ajax_variation_threshold  # デフォルト30

ステップ2:バリエーションのAjax上限を引き上げる

// functions.php: バリエーション数の上限を引き上げる
// デフォルト30個を超えるとAjaxで動的取得になる

// ① Ajax 取得のしきい値を変更(ページ読み込みに含めるバリエーション数)
add_filter('woocommerce_ajax_variation_threshold', fn() => 100);

// ② 非常に多いバリエーション(100個以上)の場合はAjax取得を最適化
add_filter('woocommerce_available_variation', function(array $variation_data, WC_Product $product, WC_Product_Variation $variation): array {
    // 不要なデータを削除して転送量を削減
    unset($variation_data['description']);
    unset($variation_data['dimensions_html']);
    return $variation_data;
}, 10, 3);

// ③ バリエーションのAjaxエンドポイントをデバッグ
add_action('wp_ajax_woocommerce_get_variation', function(): void {
    error_log('[WC Variation Ajax] ' . json_encode($_POST));
}, 1);
# バリエーション数の多い商品を確認
wp eval "
\$products = wc_get_products(['type' => 'variable', 'limit' => -1]);
foreach (\$products as \$p) {
    \$count = count(\$p->get_children());
    if (\$count > 50) {
        printf('#%d %s: %d variations' . PHP_EOL, \$p->get_id(), \$p->get_name(), \$count);
    }
}
"

ステップ3:バリエーション属性を正しく設定する

// functions.php: バリエーション属性をプログラムで管理

// ① グローバル属性を登録
function register_product_attributes(): void {
    $attributes = [
        ['name' => 'サイズ', 'slug' => 'size', 'terms' => ['S', 'M', 'L', 'XL']],
        ['name' => 'カラー', 'slug' => 'color', 'terms' => ['レッド', 'ブルー', 'グリーン', 'ブラック']],
    ];

    foreach ($attributes as $attr) {
        $taxonomy = 'pa_' . $attr['slug'];
        if (!taxonomy_exists($taxonomy)) {
            wc_create_attribute([
                'name'         => $attr['name'],
                'slug'         => $attr['slug'],
                'type'         => 'select',
                'order_by'     => 'menu_order',
                'has_archives' => false,
            ]);
        }

        foreach ($attr['terms'] as $term) {
            if (!term_exists($term, $taxonomy)) {
                wp_insert_term($term, $taxonomy);
            }
        }
    }
}
add_action('init', 'register_product_attributes');

// ② 可変商品にバリエーションをプログラムで追加
function add_product_variation(int $product_id, array $attributes, array $data): int {
    $variation = new WC_Product_Variation();
    $variation->set_parent_id($product_id);
    $variation->set_attributes($attributes); // ['pa_size' => 'M', 'pa_color' => 'ブルー']
    $variation->set_regular_price($data['price']);
    $variation->set_stock_quantity($data['stock'] ?? null);
    $variation->set_manage_stock(!empty($data['stock']));
    $variation->set_status('publish');
    return $variation->save();
}

ステップ4:バリエーション選択時の価格・在庫更新を修正する

// functions.php: バリエーション選択時の動作をカスタマイズ

// ① バリエーションデータにカスタム情報を追加
add_filter('woocommerce_available_variation', function(array $data, WC_Product $product, WC_Product_Variation $variation): array {
    // 配送日数をバリエーションデータに追加
    $shipping_days = $variation->get_meta('_shipping_days');
    $data['shipping_days'] = $shipping_days ?: '3〜5';

    // 在庫数を表示
    if ($variation->managing_stock()) {
        $data['stock_quantity_display'] = $variation->get_stock_quantity() . '個在庫あり';
    }

    return $data;
}, 10, 3);

// ② バリエーション選択後にカスタムJSでUIを更新
add_action('woocommerce_after_variations_form', function(): void {
    ?>
    <script>
    jQuery(document).on('found_variation', function(event, variation) {
        // カスタムデータをUIに反映
        if (variation.shipping_days) {
            jQuery('.shipping-info').text('配送目安:' + variation.shipping_days + '営業日');
        }
        if (variation.stock_quantity_display) {
            jQuery('.stock-info').text(variation.stock_quantity_display);
        }
    });

    jQuery(document).on('reset_data', function() {
        jQuery('.shipping-info, .stock-info').text('');
    });
    </script>
    <?php
});

ステップ5:バリエーションの一括操作と最適化

# 全バリエーションの価格を一括更新
wp eval "
\$product = wc_get_product(123);
foreach (\$product->get_children() as \$variation_id) {
    \$variation = wc_get_product(\$variation_id);
    // 現在価格の10%引きにセール価格を設定
    \$price = \$variation->get_regular_price();
    if (\$price) {
        \$variation->set_sale_price(\$price * 0.9);
        \$variation->save();
    }
}
echo '全バリエーションにセール価格を設定しました';
"

# 在庫0のバリエーションを非表示に
wp eval "
global \$wpdb;
\$zero_stock = \$wpdb->get_col(
    \"SELECT post_id FROM {$wpdb->postmeta}
     WHERE meta_key = '_stock' AND meta_value = '0'
     AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product_variation')\"
);
foreach (\$zero_stock as \$id) {
    update_post_meta(\$id, '_stock_status', 'outofstock');
}
echo count(\$zero_stock) . '件の在庫0バリエーションを更新しました';
"
// functions.php: 使われていないバリエーションを削除
function cleanup_unused_variations(int $product_id): int {
    $product = wc_get_product($product_id);
    if (!$product || $product->get_type() !== 'variable') {
        return 0;
    }

    $deleted = 0;
    foreach ($product->get_children() as $variation_id) {
        $variation = wc_get_product($variation_id);
        if (!$variation) {
            continue;
        }
        // 在庫0かつ販売実績なしのバリエーションを削除
        if ($variation->get_stock_quantity() === 0 &&
            $variation->get_total_sales() === 0) {
            $variation->delete(true);
            $deleted++;
        }
    }
    return $deleted;
}

注意事項

  • woocommerce_ajax_variation_thresholdの値を大きくすると初期ページ読み込みのJSONデータが増え、ページが重くなります。バリエーションが100個を超える場合はAjax取得(しきい値を超えた場合のデフォルト動作)に任せる方が良いです
  • バリエーション属性のスラッグはpa_プレフィックスが付きます。size属性のタクソノミー名はpa_sizeです。get_attributes()で確認できます
  • WooCommerceのバリエーション上限は技術的には無制限ですが、50個を超えるとパフォーマンスが低下します。50個以上の場合はカスタムフィールド+Ajax検索などの代替手段を検討してください

まとめ

WooCommerceバリエーションエラーの解決は①get_children()でバリエーション数と設定状態を確認、②woocommerce_ajax_variation_thresholdフィルターでAjaxしきい値を調整(デフォルト30→100)、③wc_create_attribute()wp_insert_term()でグローバル属性・タームをプログラム登録、④woocommerce_available_variationフィルターでバリエーション選択時のデータをカスタマイズしJSでUI更新、⑤get_sale_price()set_sale_price()でバリエーション価格を一括管理します。

お気軽にご相談ください

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