Skip to content

Commit 3219ff2

Browse files
committed
Merge remote-tracking branch 'origin/release/6.x' into release/6.x
2 parents 936e7d3 + 14fae8d commit 3219ff2

10 files changed

Lines changed: 114 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# Changelog
22
## Unreleased
3+
### Add
4+
- Add to cart button for record list
5+
36
### Change
4-
- Add more validation informations for test connection btn
7+
- Add more validation information for test connection btn
58

69
## [v6.4.1] - 2025.06.26
710
### Fix

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ This section contains a plugin configuration, which is optional and provides add
133133
details about implementation [here](#enrich-data-received-from-fact-finder-in-proxycontroller).
134134
Note: Sending each request to FACT-Finder instance trough Shopware, you lose on performance as each request need to be handled first by HTTP server and then, by Shopware itself. This additional traffic could be easily avoided by not activating this feature if there's no clear reason to use it.
135135

136+
Add cart button - select this option if you want the Add to cart button on the product list
136137
* Scenario how to count single click on "Add to cart" button
137138
* Redirect mapping for selected queries - put each pair `query=url` in separate row. If the phrase appears twice, the first one from the top of the list will be taken. Url can be relative path `/some/page` or absolute url `https://domain.com/some/page?someParameter=1`. If provided pair has an invalid format then it will be ignored.
138139

spec/Subscriber/ConfigurationSubscriberSpec.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public function it_will_return_factfinderchannel_for_specific_sales_channel_id(
6868
$communication->getApiKey()->willReturn('abc-123');
6969
$communication->isSsrActive()->willReturn(false);
7070
$communication->isProxyEnabled()->willReturn(false);
71+
$communication->isCartBtnEnabled()->willReturn(false);
7172
$communication->getFactFinderFeatures()->willReturn([]);
7273
$communication->getChannel('main_sales_channel')->willReturn('some_ff_channel');
7374
$communication->getFieldRoles(Argument::any())->willReturn([]);
@@ -115,6 +116,7 @@ public function it_will_add_page_extension_for_storefront_render_event(
115116
$communication->getApiKey()->willReturn('abc-123');
116117
$communication->isSsrActive()->willReturn(false);
117118
$communication->isProxyEnabled()->willReturn(false);
119+
$communication->isCartBtnEnabled()->willReturn(false);
118120
$event->getRequest()->willReturn($request);
119121
$request->get('_route', Argument::any())->willReturn('factfinder');
120122
$request->getLocale()->willReturn('en');
@@ -157,6 +159,7 @@ public function it_will_throw_exception_when_event_does_not_have_page(
157159
$communication->getApiKey()->willReturn('abc-123');
158160
$communication->isSsrActive()->willReturn(false);
159161
$communication->isProxyEnabled()->willReturn(false);
162+
$communication->isCartBtnEnabled()->willReturn(false);
160163
$event->getRequest()->willReturn($request);
161164
$request->get('_route', Argument::any())->willReturn('factfinder');
162165
$request->getLocale()->willReturn('en');

src/Config/Communication.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ public function isSsrPdpEnabled(): bool
6161
return (bool) $this->config('useSsrPdp');
6262
}
6363

64+
public function isCartBtnEnabled(): bool
65+
{
66+
return (bool) $this->config('addCartBtn');
67+
}
68+
6469
public function getFactFinderFeatures(): array
6570
{
6671
return [

src/Resources/config/config.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@
6262
<helpText lang="de-DE">Mit Proxy können Sie die von FACT-Finder zurückkommenden Daten innerhalb des SDK-Codes verfeinern. Weitere Informationen finden Sie in der Dokumentation.</helpText>
6363
</input-field>
6464

65+
<input-field type="bool">
66+
<name>addCartBtn</name>
67+
<label>Add Cart button for product list</label>
68+
<label lang="de-DE">Schaltfläche „In den Warenkorb“ für die Produktliste</label>
69+
<defaultValue>false</defaultValue>
70+
</input-field>
71+
6572
<input-field type="single-select">
6673
<name>trackingAddToCartCount</name>
6774
<options>

src/Resources/config/services.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@
142142
<service id="Omikron\FactFinder\Shopware6\Api\UpdateFieldRolesController" />
143143
<service id="Omikron\FactFinder\Shopware6\Api\TestConnectionController" />
144144

145+
<service id="Omikron\FactFinder\Shopware6\Storefront\Controller\AddToCartController" public="true">
146+
<argument type="service" id="Shopware\Core\Checkout\Cart\SalesChannel\CartService"/>
147+
<argument type="service" id="product.repository"/>
148+
<tag name="controller.service_arguments"/>
149+
</service>
150+
145151
<service id="Omikron\FactFinder\Shopware6\MessageQueue\FeedExportHandler">
146152
<tag name="messenger.message_handler" />
147153
</service>

src/Resources/views/storefront/components/factfinder/record.html.twig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
data-redirect="{{ '{{masterValues.Deeplink}}' }}" data-anchor="{{ '{{masterValues.Deeplink}}' }}">
2626
{{ 'listing.boxProductDetails'|trans|sw_sanitize }}
2727
</a>
28+
29+
{% if page.extensions.factfinder.addCartBtn %}
30+
<a class="btn btn-primary"
31+
href="/fact-finder/cart/add-by-number/{{ '{{variantValues.0.ProductNumber}}' }}"
32+
title="{{ 'listing.boxAddToCart'|trans|sw_sanitize }}">
33+
{{ 'listing.boxAddProduct'|trans|sw_sanitize }}
34+
</a>
35+
{% endif %}
2836
</div>
2937
</div>
3038
</div>

src/Resources/views/storefront/layout/factfinder/suggest.html.twig

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
{% block layout_search_suggest %}
22
<div class="search-suggest js-search-result">
33
<ff-suggest layout="list" unresolved>
4+
{% block layout_search_suggest_popular_searches %}
5+
<template data-role="popularSearches">
6+
<div class="ff-popular-searches">
7+
<h3>{{ "ff.suggest.PopularSearches"|trans }}</h3>
8+
<div data-template>{{ '{{name}}' }} </div>
9+
</div>
10+
</template>
11+
{% endblock %}
12+
413
{% block layout_search_suggest_result_suggest_container %}
514
<section class="ff-suggest-container row pb-4">
6-
<template data-role="popularSearches">
7-
<div class="ff-popular-searches">
8-
<h3>{{ "ff.suggest.PopularSearches"|trans }}</h3>
9-
<div data-template>{{ '{{name}}' }} </div>
10-
</div>
11-
</template>
12-
1315
<div data-container="searchTerm" class="col">
1416
<h3 class="h5 container-caption">{{ 'ff.suggest.SearchTerms'|trans|striptags }}</h3>
1517
<ff-suggest-item type="searchTerm">
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Omikron\FactFinder\Shopware6\Storefront\Controller;
6+
7+
use Shopware\Core\Checkout\Cart\LineItem\LineItem;
8+
use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
9+
use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
10+
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
11+
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
12+
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
13+
use Shopware\Core\System\SalesChannel\SalesChannelContext;
14+
use Shopware\Storefront\Controller\StorefrontController;
15+
use Symfony\Component\HttpFoundation\RedirectResponse;
16+
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Component\Routing\Annotation\Route;
18+
19+
#[Route(defaults: ['_routeScope' => ['storefront']])]
20+
class AddToCartController extends StorefrontController
21+
{
22+
public function __construct(
23+
private readonly CartService $cartService,
24+
private readonly EntityRepository $productRepository,
25+
) {
26+
}
27+
28+
#[Route(
29+
'/fact-finder/cart/add-by-number/{productNumber}',
30+
name: 'frontend.cart.add.by.number',
31+
defaults: ['XmlHttpRequest' => true],
32+
methods: ['GET', 'POST']
33+
)]
34+
public function addToCartByNumber(string $productNumber, Request $request, SalesChannelContext $context): RedirectResponse
35+
{
36+
$referer = $request->headers->get('referer');
37+
$criteria = new Criteria();
38+
$criteria->addFilter(new EqualsFilter('productNumber', $productNumber));
39+
$criteria->setLimit(1);
40+
41+
/** @var SalesChannelProductEntity|null $product */
42+
$product = $this->productRepository->search($criteria, $context->getContext())->first();
43+
44+
if (!$product) {
45+
$this->addFlash('danger', "Invalid product number: $productNumber");
46+
47+
return $this->redirectToRoute('frontend.home.page');
48+
}
49+
50+
$lineItem = (new LineItem($product->getId(), LineItem::PRODUCT_LINE_ITEM_TYPE, $product->getId(), 1))
51+
->setStackable(true)
52+
->setRemovable(true);
53+
$cart = $this->cartService->getCart($context->getToken(), $context);
54+
$this->cartService->add($cart, $lineItem, $context);
55+
$this->addFlash('success', "Product {$product->getName()} was added to the cart successfully.");
56+
57+
return $this->redirectToRefererOrToHomePage($referer);
58+
}
59+
60+
private function redirectToRefererOrToHomePage(?string $referer): RedirectResponse
61+
{
62+
if ($referer && filter_var($referer, FILTER_VALIDATE_URL)) {
63+
return new RedirectResponse($referer);
64+
}
65+
66+
return $this->redirectToRoute('frontend.home.page');
67+
}
68+
}

src/Subscriber/ConfigurationSubscriber.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public function onPageLoaded(ShopwareSalesChannelEvent $event): void
8787
'communicationAttributes' => $this->getCommunicationAttributes($communicationConfig),
8888
'categoryPathFieldName' => $this->categoryPathFieldName,
8989
'features' => $this->config->getFactFinderFeatures(),
90+
'addCartBtn' => $this->config->isCartBtnEnabled(),
9091
]));
9192
}
9293
}
@@ -99,10 +100,7 @@ private function getPage(ShopwareSalesChannelEvent $event): Struct
99100

100101
$parameters = method_exists($event, 'getParameters') && is_array($event->getParameters()) ? $event->getParameters() : [];
101102

102-
if (
103-
isset($parameters['page'])
104-
&& $parameters['page'] instanceof Struct
105-
) {
103+
if (isset($parameters['page']) && $parameters['page'] instanceof Struct) {
106104
return $parameters['page'];
107105
}
108106

@@ -113,8 +111,7 @@ private function isSearchImmediate(ShopwareSalesChannelEvent $event): bool
113111
{
114112
$request = $event->getRequest();
115113

116-
if (
117-
$this->config->isSsrActive()
114+
if ($this->config->isSsrActive()
118115
|| $request->isXmlHttpRequest()
119116
) {
120117
return false;

0 commit comments

Comments
 (0)