| @@ -13,9 +13,8 @@ | ||
| 13 | 13 | use FluentCart\App\Modules\Templating\AssetLoader; |
| 14 | 14 | use FluentCart\App\Services\Renderer\RenderContext; |
| 15 | 15 | use FluentCart\App\Services\Renderer\ShopAppRenderer; |
| 16 | 16 | use FluentCart\App\Services\TemplateService; |
| 17 | -use FluentCart\App\Vite; | |
| 18 | 17 | use FluentCart\Framework\Support\Arr; |
| 19 | 18 | use FluentCart\Framework\Support\Str; |
| 20 | 19 | |
| 21 | 20 | class ShopAppHandler |
| @@ -113,8 +112,9 @@ | ||
| 113 | 112 | 'ids' => '', |
| 114 | 113 | 'exclude_ids' => '', |
| 115 | 114 | 'category' => '', |
| 116 | 115 | 'category_id' => '', |
| 116 | + 'taxonomies' => '', | |
| 117 | 117 | 'fulfillment_type' => '', |
| 118 | 118 | 'product_type' => '', |
| 119 | 119 | 'on_sale' => '', |
| 120 | 120 | 'sort_by' => '', |
| @@ -245,9 +245,9 @@ | ||
| 245 | 245 | |
| 246 | 246 | $allProducts = $this->getInitialProducts(); |
| 247 | 247 | $this->defaultViewData = [ |
| 248 | 248 | 'products' => Arr::get($allProducts, 'products', []), |
| 249 | - 'placeholder_image' => Vite::getAssetUrl('images/placeholder.svg'), | |
| 249 | + 'placeholder_image' => Helper::getProductPlaceholderUrl(), | |
| 250 | 250 | 'paginator' => $this->shortcodeAttributes['paginator'], |
| 251 | 251 | 'view_mode' => $this->shortcodeAttributes['view_mode'], |
| 252 | 252 | 'price_format' => $this->shortcodeAttributes['price_format'], |
| 253 | 253 | 'per_page' => $this->shortcodeAttributes['per_page'], |
| @@ -364,12 +364,18 @@ | ||
| 364 | 364 | $existing = Arr::get($mergedTerms, 'product-categories', []); |
| 365 | 365 | $mergedTerms['product-categories'] = array_unique(array_merge($existing, $categoryTermIds)); |
| 366 | 366 | } |
| 367 | 367 | |
| 368 | - // The former tag= / tag_id= attributes filtered on the product-tags | |
| 369 | - // taxonomy, which FluentCart does not register (won't-ship decision | |
| 370 | - // 2026-08-06). They never matched anything — worse, tag_id= filtered | |
| 371 | - // every product out. Unknown attributes are now simply ignored. | |
| 368 | + // --- Shortcode attribute: taxonomies="product-tags:1,2|product-brands:67" --- | |
| 369 | + // Any taxonomy registered on products, including store-registered ones. | |
| 370 | + foreach (Taxonomy::parseShortcodeTaxonomies($this->shortcodeAttributes['taxonomies']) as $taxonomy => $termIds) { | |
| 371 | + // A segment that resolved to nothing (unknown taxonomy, foreign or | |
| 372 | + // missing term) must match nothing — dropping it would widen the | |
| 373 | + // list to products the shortcode never asked for. | |
| 374 | + $termIds = $termIds ?: [0]; | |
| 375 | + $existing = Arr::get($mergedTerms, $taxonomy, []); | |
| 376 | + $mergedTerms[$taxonomy] = array_values(array_unique(array_merge($existing, $termIds))); | |
| 377 | + } | |
| 372 | 378 | |
| 373 | 379 | // --- Shortcode attribute: sort_by --- |
| 374 | 380 | if (!empty($this->shortcodeAttributes['sort_by'])) { |
| 375 | 381 | $filters['sort_by'] = sanitize_text_field($this->shortcodeAttributes['sort_by']); |