diff --git a/config/rapidez/models.php b/config/rapidez/models.php index 4782a6300..dd622536f 100644 --- a/config/rapidez/models.php +++ b/config/rapidez/models.php @@ -14,6 +14,7 @@ 'option_value' => Rapidez\Core\Models\OptionValue::class, 'product_image' => Rapidez\Core\Models\ProductImage::class, 'product_image_value' => Rapidez\Core\Models\ProductImageValue::class, + 'product_video_value' => Rapidez\Core\Models\ProductVideoValue::class, 'product_link' => Rapidez\Core\Models\ProductLink::class, 'product_view' => Rapidez\Core\Models\ProductView::class, 'product_option' => Rapidez\Core\Models\ProductOption::class, diff --git a/resources/js/components/Product/Images.vue b/resources/js/components/Product/Images.vue index 969ee0e6d..c6480e30f 100644 --- a/resources/js/components/Product/Images.vue +++ b/resources/js/components/Product/Images.vue @@ -4,6 +4,7 @@ import { useEventListener } from '@vueuse/core' export default { data: () => ({ images: config.product.images, + media: config.product.product_gallery, active: 0, zoomed: false, stopKeyUpListener: () => {}, @@ -22,7 +23,8 @@ export default { Object.values(window.config.product.super_attributes).filter((attribute) => attribute.update_image).length ) { self.images = simpleProduct.images - self.active = Math.min(self.active, self.images.length - 1) + self.media = simpleProduct.product_gallery + self.active = Math.min(self.active, self.media.length - 1) } }) }) @@ -44,7 +46,7 @@ export default { if (e.key == 'ArrowLeft' && this.active > 0) { // left this.active-- - } else if (e.key == 'ArrowRight' && this.active < this.images.length - 1) { + } else if (e.key == 'ArrowRight' && this.active < this.media.length - 1) { // right this.active++ } else if (e.key == 'Escape') { diff --git a/resources/views/product/partials/images.blade.php b/resources/views/product/partials/images.blade.php index c68cea708..9a18edb33 100644 --- a/resources/views/product/partials/images.blade.php +++ b/resources/views/product/partials/images.blade.php @@ -4,11 +4,15 @@ @include('rapidez::wishlist.button') @endif - @if (count($product->images)) + @if (count($product->product_gallery))
product_gallery[0]['media_type'] === 'external-video') + src="{{ config('rapidez.media_url').'/catalog/product'.$product->product_gallery[0]['image'] }}" + @else + src="/storage/{{ config('rapidez.store') }}/resizes/400/magento/catalog/product{{ $product->product_gallery[0]['image'] }}.webp" + @endif alt="{{ $product->name }}" width="400" height="400" @@ -17,54 +21,82 @@ class="m-auto max-h-[400px] w-full object-contain" @endif -
-
+
+ -
+
diff --git a/src/Http/Controllers/ProductController.php b/src/Http/Controllers/ProductController.php index af5c0c568..3a418ceb8 100644 --- a/src/Http/Controllers/ProductController.php +++ b/src/Http/Controllers/ProductController.php @@ -26,6 +26,7 @@ public function show(int $productId) 'price', 'special_price', 'images', + 'product_gallery', 'url', 'min_sale_qty', 'qty_increments', diff --git a/src/Models/Product.php b/src/Models/Product.php index 8718f1feb..619d8656f 100644 --- a/src/Models/Product.php +++ b/src/Models/Product.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasOneThrough; +use Illuminate\Support\Str; use Rapidez\Core\Casts\Children; use Rapidez\Core\Casts\CommaSeparatedToArray; use Rapidez\Core\Casts\CommaSeparatedToIntegerArray; @@ -210,6 +211,17 @@ public function getImagesAttribute(): array return $this->gallery->sortBy('productImageValue.position')->pluck('value')->toArray(); } + public function getProductGalleryAttribute(): array + { + return $this->gallery->sortBy('productImageValue.position')->map(function (ProductImage $value) { + return [ + 'media_type' => $value->media_type, + 'image' => $value->value, + 'video_url' => isset($value->video) ? Str::embedUrl($value->video->url) : null, + ]; + })->values()->toArray(); + } + public function getImageAttribute($image): ?string { return $image !== 'no_selection' ? $image : null; diff --git a/src/Models/ProductImage.php b/src/Models/ProductImage.php index 0443c0573..9459af100 100644 --- a/src/Models/ProductImage.php +++ b/src/Models/ProductImage.php @@ -10,7 +10,7 @@ class ProductImage extends Model protected $primaryKey = 'value_id'; - protected $with = ['productImageValue']; + protected $with = ['productImageValue', 'video']; protected static function booted(): void { @@ -30,4 +30,9 @@ public function productImageValue() { return $this->belongsTo(config('rapidez.models.product_image_value'), 'value_id', 'value_id'); } + + public function video() + { + return $this->belongsTo(config('rapidez.models.product_video_value'), 'value_id', 'value_id'); + } } diff --git a/src/Models/ProductVideoValue.php b/src/Models/ProductVideoValue.php new file mode 100644 index 000000000..66bf8cae5 --- /dev/null +++ b/src/Models/ProductVideoValue.php @@ -0,0 +1,10 @@ +render()); }); + Str::macro( + 'embedUrl', + function ($url) { + if (Str::contains($url, 'vimeo')) { + $url = str_replace('/vimeo.com', '/player.vimeo.com/video', $url); + + // Handle private vimeo urls. + $hash = null; + if (! Str::contains($url, 'progressive_redirect') && Str::substrCount($url, '/') > 4) { + $hash = Str::afterLast($url, '/'); + $url = Str::beforeLast($url, '/'); + + if (Str::contains($hash, '?')) { + $url .= '?' . Str::after($hash, '?'); + $hash = Str::before($hash, '?'); + } + } + + $paramsToAdd = '?dnt=1&watch_full_video=false&vimeo_logo=false&speed=false&chromecast=false&byline=false&badge=false&ask_ai=false&airplay=false'; + if ($hash) { + $paramsToAdd .= '&h=' . $hash; + } + + if (Str::contains($url, '?')) { + $url = str_replace('?', $paramsToAdd . '&', $url); + } else { + $url .= $paramsToAdd; + } + + return $url; + } + + if (Str::contains($url, 'youtu.be')) { + $url = str_replace('youtu.be', 'www.youtube.com/embed', $url); + + // Check for start at point and replace it with correct parameter. + if (Str::contains($url, '?t=')) { + $url = str_replace('?t=', '?start=', $url); + } + } + + if (Str::contains($url, 'youtube.com/watch?v=')) { + $url = str_replace('watch?v=', 'embed/', $url); + + if (Str::contains($url, '&t=')) { + $url = str_replace('&t=', '?start=', $url); + } + } + + if (Str::contains($url, 'youtube.com/shorts/')) { + $url = str_replace('shorts/', 'embed/', $url); + } + + if (Str::contains($url, 'youtube.com')) { + $url = str_replace('youtube.com', 'youtube-nocookie.com', $url); + } + + // This avoids SSL issues when using the non-www version + if (Str::contains($url, '//youtube-nocookie.com')) { + $url = str_replace('//youtube-nocookie.com', '//www.youtube-nocookie.com', $url); + } + + $url .= '&fs=0'; + + if (Str::contains($url, '&') && ! Str::contains($url, '?')) { + $url = Str::replaceFirst('&', '?', $url); + } + + return $url; + } + ); + return $this; }