From 5869268c94ed91d86ccbe46e5eb37b8565e04c91 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Sun, 21 Jun 2026 18:25:09 +0100 Subject: [PATCH] Ensure variants are site specific, and use fallback values --- .../Controllers/CP/VariantsController.php | 18 ++- tests/Unit/VariantsControllerTest.php | 120 ++++++++++++++++++ 2 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 tests/Unit/VariantsControllerTest.php diff --git a/src/Http/Controllers/CP/VariantsController.php b/src/Http/Controllers/CP/VariantsController.php index 05dd2aa..f01faa2 100644 --- a/src/Http/Controllers/CP/VariantsController.php +++ b/src/Http/Controllers/CP/VariantsController.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Statamic\Facades\Entry; +use Statamic\Facades\Site; use Statamic\Http\Controllers\CP\CpController; use StatamicRadPack\Shopify\Blueprints\VariantBlueprint; @@ -11,21 +12,18 @@ class VariantsController extends CpController { public function fetch($product) { + $site = Site::selected()->handle(); + return Entry::query() ->where('collection', 'variants') ->where('product_slug', $product) + ->where('site', $site) ->get() ->map(function ($variant) { - $values = []; - $values['id'] = $variant->id(); - $values['slug'] = $variant->slug(); - - // Map all variant values to data to ensure we are getting everything. - foreach ($variant->data() as $key => $value) { - $values[$key] = $value; - } - - return $values; + return $variant->values()->merge([ + 'id' => $variant->id(), + 'slug' => $variant->slug(), + ]); }); } diff --git a/tests/Unit/VariantsControllerTest.php b/tests/Unit/VariantsControllerTest.php new file mode 100644 index 0000000..a7bfe65 --- /dev/null +++ b/tests/Unit/VariantsControllerTest.php @@ -0,0 +1,120 @@ +email('admin@example.com')->makeSuper()->save(); + + return $this->actingAs($user); + } + + private function setupMultisite(): void + { + Facades\Site::setSites([ + 'en' => ['url' => '/', 'locale' => 'en_US'], + 'de' => ['url' => '/de/', 'locale' => 'de_DE'], + ]); + + Facades\Collection::make(config('shopify.collection_handle', 'products'))->sites(['en', 'de'])->save(); + Facades\Collection::make('variants')->sites(['en', 'de'])->save(); + } + + private function makeVariant(string $slug, array $data = []) + { + $variant = Facades\Entry::make() + ->collection('variants') + ->slug($slug) + ->data(array_merge(['product_slug' => 'test-product'], $data)); + + $variant->save(); + + return $variant; + } + + #[Test] + public function returns_variants_for_default_site() + { + $this->makeVariant('variant-en', ['title' => 'English Variant', 'price' => '10.00', 'sku' => 'EN-1']); + + $response = $this->actingAsSuperUser() + ->getJson(cp_route('shopify.variants.index', 'test-product')); + + $response->assertOk(); + $response->assertJsonCount(1); + $response->assertJsonPath('0.title', 'English Variant'); + } + + #[Test] + public function filters_variants_by_selected_site() + { + $this->setupMultisite(); + + $enVariant = $this->makeVariant('variant-en', ['title' => 'English Variant', 'price' => '10.00', 'sku' => 'EN-1']); + $enVariant->makeLocalization('de')->data(['title' => 'German Variant', 'price' => '12.00', 'sku' => 'DE-1'])->save(); + + Facades\Site::setSelected('en'); + + $response = $this->actingAsSuperUser() + ->getJson(cp_route('shopify.variants.index', 'test-product')); + + $response->assertOk(); + $response->assertJsonCount(1); + $response->assertJsonPath('0.title', 'English Variant'); + + Facades\Site::setSelected('de'); + + $response = $this->actingAsSuperUser() + ->getJson(cp_route('shopify.variants.index', 'test-product')); + + $response->assertOk(); + $response->assertJsonCount(1); + $response->assertJsonPath('0.title', 'German Variant'); + } + + #[Test] + public function localized_variant_inherits_title_price_and_sku_from_origin() + { + $this->setupMultisite(); + + $enVariant = $this->makeVariant('variant-en', ['title' => 'Origin Title', 'price' => '9.99', 'sku' => 'ORIGIN-1']); + $enVariant->makeLocalization('de')->data([])->save(); + + Facades\Site::setSelected('de'); + + $response = $this->actingAsSuperUser() + ->getJson(cp_route('shopify.variants.index', 'test-product')); + + $response->assertOk(); + $response->assertJsonCount(1); + $response->assertJsonPath('0.title', 'Origin Title'); + $response->assertJsonPath('0.price', '9.99'); + $response->assertJsonPath('0.sku', 'ORIGIN-1'); + } + + #[Test] + public function localized_variant_values_take_precedence_over_origin() + { + $this->setupMultisite(); + + $enVariant = $this->makeVariant('variant-en', ['title' => 'Origin Title', 'price' => '9.99', 'sku' => 'ORIGIN-1']); + $enVariant->makeLocalization('de')->data(['title' => 'DE Title', 'price' => '12.00', 'sku' => 'DE-1'])->save(); + + Facades\Site::setSelected('de'); + + $response = $this->actingAsSuperUser() + ->getJson(cp_route('shopify.variants.index', 'test-product')); + + $response->assertOk(); + $response->assertJsonPath('0.title', 'DE Title'); + $response->assertJsonPath('0.price', '12.00'); + $response->assertJsonPath('0.sku', 'DE-1'); + } +}