From 4c0974bf84c2caff34b79645caeb69825a997506 Mon Sep 17 00:00:00 2001 From: Konstantinos Arvanitakis Date: Wed, 23 Sep 2026 09:41:21 +0300 Subject: [PATCH] Feat: Updating Product Indexer, and Product Sort --- src/Catalog/Enums/ProductSort.php | 7 +++++++ src/Catalog/Services/ProductIndexer.php | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/Catalog/Enums/ProductSort.php b/src/Catalog/Enums/ProductSort.php index 71cc99c..60336a0 100644 --- a/src/Catalog/Enums/ProductSort.php +++ b/src/Catalog/Enums/ProductSort.php @@ -14,6 +14,7 @@ enum ProductSort: string case PriceAsc = 'price_asc'; case PriceDesc = 'price_desc'; case Newest = 'newest'; + case Popularity = 'popularity'; public function toMeilisearchSort(): string { @@ -21,6 +22,12 @@ enum ProductSort: string self::PriceAsc => 'price:asc', self::PriceDesc => 'price:desc', self::Newest => 'created_at:desc', + // order_count — see Modules\Core\Catalog\Services\ + // ProductIndexer::toSearchableArray()'s own docblock: the same + // trailing-year, physical-order-line-count definition Lunar's + // own admin dashboard "Popular Products" widget already uses, + // aggregated per product rather than per variant. + self::Popularity => 'order_count:desc', }; } } diff --git a/src/Catalog/Services/ProductIndexer.php b/src/Catalog/Services/ProductIndexer.php index 7597442..b80892e 100644 --- a/src/Catalog/Services/ProductIndexer.php +++ b/src/Catalog/Services/ProductIndexer.php @@ -5,6 +5,7 @@ namespace Modules\Core\Catalog\Services; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Lunar\Models\Currency; +use Lunar\Models\OrderLine; use Lunar\Models\Price; use Lunar\Models\Product; use Lunar\Models\ProductVariant; @@ -103,6 +104,7 @@ class ProductIndexer extends BaseProductIndexer return [ ...parent::getSortableFields(), 'price', + 'order_count', ]; } @@ -161,6 +163,24 @@ class ProductIndexer extends BaseProductIndexer $data['in_stock'] = $model->variants->contains( fn (ProductVariant $variant) => $variant->canBeFulfilledAtQuantity(1) ); + // Same "popular" definition as Lunar's own admin dashboard widget + // (Lunar\Admin\Filament\Widgets\Dashboard\Orders\ + // PopularProductsTable) — order-line COUNT, not summed quantity, + // over the trailing year, physical lines only — just aggregated + // per PRODUCT here (across all its variants) rather than per + // variant/identifier, since a storefront "sort by popularity" + // ranks products, not individual variant SKUs. Necessarily as + // stale as any other reindex-time field here (in_stock, price) — + // there's no live equivalent without a query per page load. + $data['order_count'] = OrderLine::query() + ->whereIn('purchasable_id', $model->variants->pluck('id')) + ->where('purchasable_type', 'product_variant') + ->where('type', 'physical') + ->whereHas('order', fn ($query) => $query->whereBetween('placed_at', [ + now()->subYear()->startOfDay(), + now()->endOfDay(), + ])) + ->count(); $data['recommendations'] = app(RecommendationService::class) ->recommend($model) ->load(['media', 'variants.prices'])