@extends('front.layout.master') @php if(request()->keyword){ $title = __('Showing all results for :keyword', ['keyword' => request()->keyword]); $seodes = $title; } elseif(request()->chid){ $findchid = App\Grandcategory::find(request()->chid); $title = __(':title - All products', ['title' => $findchid->title ?? '']); $seodes = strip_tags($findchid->description ?? ''); $seoimage = $findchid && $findchid->image ? url('images/grandcategory/'.$findchid->image) : ''; } elseif(request()->sid){ $findsubcat = App\Subcategory::find(request()->sid); $title = __(':title - All products', ['title' => $findsubcat->title ?? '']); $seodes = strip_tags($findsubcat->description ?? ''); $seoimage = $findsubcat && $findsubcat->image ? url('images/subcategory/'.$findsubcat->image) : ''; } else { $findcat = App\Category::find(request()->category); $title = __(':title - All products', ['title' => $findcat->title ?? __('Shop')]); $seodes = strip_tags($findcat->description ?? ''); $seoimage = $findcat && $findcat->image ? url('images/category/'.$findcat->image) : ''; } @endphp @section('meta_tags') @endsection @section('title', $title) @section('body') @php // Build a unified product array for display (variants + simple) $displayProducts = collect(); $catName = ''; if (request()->keyword) { $catName = __('Search results for') . ' "' . e(request()->keyword) . '"'; } elseif (request()->_featured_page || (request()->featured == 1 && empty(request()->category))) { $catName = __('Featured Products'); } elseif (isset($findchid) && $findchid) { $catName = $findchid->title ?? ''; } elseif (isset($findsubcat) && $findsubcat) { $catName = $findsubcat->title ?? ''; } elseif (isset($findcat) && $findcat) { $catName = $findcat->title ?? ''; } else { $catName = __('Shop'); } // Brand list for filter sidebar — only brands that have products in the current category $brandsAll = collect(); $currentCatId = request('category') ?: $catid ?? null; if ($currentCatId) { // Brands referencing this category in their JSON category_id field $brandsAll = App\Brand::where('status', '1')->orderBy('name')->get()->filter(function($b) use ($currentCatId) { $cats = $b->category_id; if (is_string($cats)) $cats = json_decode($cats, true); return is_array($cats) && in_array((string)$currentCatId, array_map('strval', $cats)); })->values(); // Plus any brands whose products actually live in this category $brandIdsFromProducts = App\Product::where('status', 1)->where('category_id', $currentCatId)->pluck('brand_id')->unique()->filter(); $brandIdsFromSimple = App\SimpleProduct::where('status', 1)->where('category_id', $currentCatId)->pluck('brand_id')->unique()->filter(); $allBrandIds = $brandIdsFromProducts->merge($brandIdsFromSimple)->unique(); if ($allBrandIds->count()) { $extraBrands = App\Brand::whereIn('id', $allBrandIds)->where('status', '1')->orderBy('name')->get(); $brandsAll = $brandsAll->merge($extraBrands)->unique('id')->values(); } } else { $brandsAll = App\Brand::where('status', '1')->orderBy('name')->get(); } // Cache base URL strings to avoid url() calls in tight loops $baseImg = url('variantimages/thumbnails/'); $baseHover = url('variantimages/hoverthumbnail/'); $baseSimpleImg = url('images/simple_products/'); $noImg = url('images/no-image.png'); $isAuth = auth()->check(); // Pre-fetch wishlist ids in one query (huge win vs per-row queries) $wishVariantIds = collect(); $wishSimpleIds = collect(); if ($isAuth) { $wishRows = App\Wishlist::where('user_id', auth()->id())->get(['pro_id','simple_pro_id']); $wishVariantIds = $wishRows->pluck('pro_id')->filter()->flip(); $wishSimpleIds = $wishRows->pluck('simple_pro_id')->filter()->flip(); } // Pre-fetch ratings for all visible products (one query each for variant/simple) $variantIds = isset($products) ? collect($products)->pluck('id')->filter() : collect(); $simpleIds = isset($simple_products) ? collect($simple_products)->pluck('id')->filter() : collect(); $ratingsByVariantPro = collect(); $ratingsBySimplePro = collect(); if ($variantIds->count() || $simpleIds->count()) { $allIds = $variantIds->merge($simpleIds)->unique(); $ratingsRows = App\UserReview::whereIn('pro_id', $allIds)->where('status', '1')->select('pro_id', \DB::raw('AVG((price + value)/2) as avg_r'))->groupBy('pro_id')->get(); foreach ($ratingsRows as $rr) { $val = round((float) $rr->avg_r, 1); // map to 0-5 scale (price/value are already 0-5, so AVG is already 0-5) $ratingsByVariantPro[$rr->pro_id] = $val; $ratingsBySimplePro[$rr->pro_id] = $val; } } // Helper: variant -> normalized array (no per-row DB queries) $normalizeVariant = function($p, $orivar) use ($conversion_rate, $baseImg, $baseHover, $wishVariantIds, $ratingsByVariantPro) { if (!$orivar || !isset($orivar->variantimages)) return null; // Use the same helper as the homepage cards so all surfaces agree on the number. // (mainprice = vender_price + variant.price + commission; offerprice mirrors with vender_offer_price.) $priceData = ProductPrice::getprice($p, $orivar)->getData(); $price = (float) ($priceData->mainprice ?? 0); $offerCandidate = (float) ($priceData->offerprice ?? 0); $offer = ($offerCandidate > 0 && $offerCandidate < $price) ? $offerCandidate : 0; $minQty = (int) ($orivar->min_order_qty ?? 1) ?: 1; $simpleUrl = url('details/' . \Illuminate\Support\Str::slug($p->name, '-') . '/' . $p->id); return (object) [ 'productid' => $p->id, 'variantid' => $orivar->id, 'product_type' => 'variant', 'productname' => $p->name, 'brand_id' => $p->brand_id ?? null, 'thumbnail' => $baseImg . '/' . ($orivar->variantimages->main_image ?? ''), 'hover_thumbnail' => $baseHover . '/' . ($orivar->variantimages->image2 ?? $orivar->variantimages->main_image ?? ''), 'mainprice' => price_format($price * $conversion_rate), 'offerprice' => $offer > 0 ? price_format($offer * $conversion_rate) : price_format($price * $conversion_rate), '_priceval_raw' => $offer > 0 ? $offer : $price, '_compareval_raw' => $offer > 0 ? $price : null, 'rating' => $ratingsByVariantPro->get($p->id, 0), 'stock' => $orivar->stock ?? 0, 'cartURL' => route('add.cart', ['id' => $p->id, 'variantid' => $orivar->id, 'varprice' => $price, 'varofferprice' => $offer, 'qty' => $minQty]), 'producturl' => $simpleUrl, 'is_in_wishlist' => $wishVariantIds->has($orivar->id) ? 1 : 0, 'sale_tag' => $p->sale_tag ?? null, 'sale_tag_color' => $p->sale_tag_color ?? null, 'sale_tag_text_color' => $p->sale_tag_text_color ?? null, ]; }; // Helper: simple product -> normalized (no per-row DB queries) $normalizeSimple = function($sp) use ($conversion_rate, $baseSimpleImg, $noImg, $wishSimpleIds, $ratingsBySimplePro) { $offer = $sp->offer_price > 0 ? (float) $sp->offer_price : 0; $price = (float) ($sp->price ?? 0); return (object) [ 'productid' => $sp->id, 'product_type' => 'simple', 'productname' => $sp->product_name, 'brand_id' => $sp->brand_id ?? null, 'thumbnail' => $sp->thumbnail ? $baseSimpleImg . '/' . $sp->thumbnail : $noImg, 'hover_thumbnail' => $sp->hover_thumbnail ? $baseSimpleImg . '/' . $sp->hover_thumbnail : ($sp->thumbnail ? $baseSimpleImg . '/' . $sp->thumbnail : $noImg), 'mainprice' => price_format($price * $conversion_rate), 'offerprice' => $offer > 0 ? price_format($offer * $conversion_rate) : price_format($price * $conversion_rate), '_priceval_raw' => $offer > 0 ? $offer : $price, '_compareval_raw' => $offer > 0 ? $price : null, 'rating' => $ratingsBySimplePro->get($sp->id, 0), 'stock' => $sp->stock ?? 0, 'cartURL' => route('add.cart.simple', ['pro_id' => $sp->id, 'price' => $price, 'offerprice' => $offer]), 'producturl' => route('show.product', ['id' => $sp->id, 'slug' => $sp->slug]), 'is_in_wishlist' => $wishSimpleIds->has($sp->id) ? 1 : 0, 'sale_tag' => $sp->sale_tag ?? null, 'sale_tag_color' => $sp->sale_tag_color ?? null, 'sale_tag_text_color' => $sp->sale_tag_text_color ?? null, ]; }; if (isset($products) && count($products)) { foreach ($products as $p) { $orivar = $p->subvariants[0] ?? null; $norm = $normalizeVariant($p, $orivar); if ($norm) { $norm->_created_at = $p->created_at ?? null; $norm->_priceval = (float) preg_replace('/[^0-9.]/', '', (string) $norm->offerprice); $displayProducts->push($norm); } } } if (isset($simple_products) && count($simple_products)) { foreach ($simple_products as $sp) { $norm = $normalizeSimple($sp); $norm->_created_at = $sp->created_at ?? null; $norm->_priceval = (float) preg_replace('/[^0-9.]/', '', (string) $norm->offerprice); $displayProducts->push($norm); } } // Back-stop filters: the legacy categoryf() controller has many branches and several of // them never apply price-range / brand / out-of-stock to the SQL query. Re-apply the same // filters here against the already-normalised collection so "Apply Filters" reliably // narrows the result set regardless of which controller branch ran. // The MIN/MAX the shopper types are in the *displayed* currency (same as the // prices on the cards, which are raw * conversion_rate). But _priceval_raw is // the base-currency price, so convert it up before comparing — otherwise the // filter silently works in the base currency and mismatches the card prices // whenever a non-default currency (conversion_rate != 1) is active. $curRate = (float) ($conversion_rate ?? 1) ?: 1; $priceLow = (float) request('start', 0); $priceHigh = (float) request('end', 0); if ($priceLow > 0 || $priceHigh > 0) { $hi = $priceHigh > 0 ? $priceHigh : INF; $displayProducts = $displayProducts->filter(function($p) use ($priceLow, $hi, $curRate) { $v = (float) ($p->_priceval_raw ?? 0) * $curRate; return $v >= $priceLow && $v <= $hi; })->values(); } $brandFilter = request('brands'); if (!empty($brandFilter)) { $brandIds = array_filter(array_map('trim', explode(',', $brandFilter))); if (count($brandIds)) { $displayProducts = $displayProducts->filter(function($p) use ($brandIds) { return in_array((string) ($p->brand_id ?? ''), $brandIds, true); })->values(); } } if (!request('outofstock')) { $displayProducts = $displayProducts->filter(function($p) { return (int) ($p->stock ?? 0) > 0; })->values(); } // Rating filter (server-side) $ratingFilter = (int) request('ratings', 0); if ($ratingFilter > 0) { $displayProducts = $displayProducts->filter(function($p) use ($ratingFilter) { return ((float) $p->rating) >= $ratingFilter; })->values(); } // Sorting $sortKey = request('sort'); if ($sortKey === 'price_asc') { $displayProducts = $displayProducts->sortBy('_priceval')->values(); } elseif ($sortKey === 'price_desc') { $displayProducts = $displayProducts->sortByDesc('_priceval')->values(); } elseif ($sortKey === 'newest') { $displayProducts = $displayProducts->sortByDesc('_created_at')->values(); } elseif ($sortKey === 'rating') { $displayProducts = $displayProducts->sortByDesc('rating')->values(); } // Load-more pagination: 20 per page (cumulative) $pageSize = 20; $loadedPages = max(1, (int) request('lp', 1)); $totalProducts = $displayProducts->count(); $shownCount = min($pageSize * $loadedPages, $totalProducts); $hasMore = $shownCount < $totalProducts; $displayProducts = $displayProducts->take($shownCount)->values(); // Discount % per item — calculated once here for both grid and list foreach ($displayProducts as $p) { $p->discount_pct = ($p->_compareval_raw && $p->_priceval_raw && $p->_compareval_raw > $p->_priceval_raw) ? round((1 - $p->_priceval_raw / $p->_compareval_raw) * 100) : 0; } @endphp
{{ $totalProducts }} {{ __('products found') }}
{{ __('Showing') }} {{ $shownCount }} {{ __('of') }} {{ $totalProducts }} {{ __('products') }}
{{ __('Load more') }}{{ __('Try adjusting your filters or search terms.') }}
{{ __('Browse all products') }}