Product list: success stories on the all-products element
The big product list on /products (all products, no category context) deliberately delivered the empty successStories envelope; the front end now renders story cards there too and filters them client-side, so the element aggregates over the WHOLE product category tree instead: - new allProductCategoryUids(): root category 'Product' (same detection as ProductFinderJsonRenderer), children plus descendants depth-first, fed through the existing successStoriesFor() - per-category elements are untouched; forCategories keeps carrying the category uids a story is attached to, so the ?cat=/?subcat= filter behaves identically on both element kinds - layout rule unchanged: first contributing category in tree order Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
55f7f82a42
commit
4a7ea387a0
1 file changed
+34
-2
@@ -207,9 +207,13 @@ class ProductListJsonRenderer
|
|||||||
// Success stories the editor attached to these categories
|
// Success stories the editor attached to these categories
|
||||||
// (sys_category, Options tab). They ride along with the list
|
// (sys_category, Options tab). They ride along with the list
|
||||||
// so the front end can hide them with the same category
|
// so the front end can hide them with the same category
|
||||||
// filter it applies to the products.
|
// filter it applies to the products. An all-products element
|
||||||
|
// aggregates over the WHOLE product category tree (change
|
||||||
|
// 2026-09-16 on front-end request - it used to deliver the
|
||||||
|
// empty envelope), so forCategories keeps driving the
|
||||||
|
// ?cat=/?subcat= filter exactly like on per-category lists.
|
||||||
'successStories' => $this->successStoriesFor(
|
'successStories' => $this->successStoriesFor(
|
||||||
$allProducts ? [] : $categoryUids,
|
($allProducts || $categoryUids === []) ? $this->allProductCategoryUids() : $categoryUids,
|
||||||
(int)($settings['storysinglepid'] ?? 0)
|
(int)($settings['storysinglepid'] ?? 0)
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -375,6 +379,34 @@ class ProductListJsonRenderer
|
|||||||
* @param int[] $categoryUids
|
* @param int[] $categoryUids
|
||||||
* @return int[]
|
* @return int[]
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* The whole product category tree - the root's children plus all
|
||||||
|
* descendants in depth-first backend order. Story source for elements
|
||||||
|
* that render all products. Root detection mirrors
|
||||||
|
* ProductFinderJsonRenderer: the root-level sys_category named 'Product'.
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
private function allProductCategoryUids(): array
|
||||||
|
{
|
||||||
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
->getQueryBuilderForTable('sys_category');
|
||||||
|
$rootUid = (int)($queryBuilder->select('uid')->from('sys_category')
|
||||||
|
->where(
|
||||||
|
$queryBuilder->expr()->eq('parent', 0),
|
||||||
|
$queryBuilder->expr()->eq('deleted', 0),
|
||||||
|
$queryBuilder->expr()->eq('title', $queryBuilder->createNamedParameter('Product', ParameterType::STRING))
|
||||||
|
)
|
||||||
|
->setMaxResults(1)
|
||||||
|
->executeQuery()->fetchOne() ?: 0);
|
||||||
|
if ($rootUid <= 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop the root itself - stories hang on the categories below it.
|
||||||
|
return array_values(array_diff($this->expandWithDescendants([$rootUid]), [$rootUid]));
|
||||||
|
}
|
||||||
|
|
||||||
private function expandWithDescendants(array $categoryUids): array
|
private function expandWithDescendants(array $categoryUids): array
|
||||||
{
|
{
|
||||||
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
$queryBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class)
|
||||||
|
|||||||
Reference in new issue
Block a user