Skip to content

Commit

Permalink
FFWEB-3300: Redirect to PDP if there is one product in search result
Browse files Browse the repository at this point in the history
Redirect to PDP if there is only one product in search result. More info in SDK documentation.
  • Loading branch information
Rayn93 authored Feb 11, 2025
1 parent dea20c9 commit 49e1e51
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### Add
- Add feature settings so it is possible to enable/disable some of FactFinder features like campaigns or recommendations
- Support Proxy feature for Server Side Rendering
- (SSR) Redirect to PDP if there is only one product in search result

### Fix
- Remove CategoryPath filter in URL and ASN on category page
Expand Down
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,6 @@ You can find more information about what Field Roles are in (Web Components docu
**Note:**
Updating process is ran for all sales channels, no need to run it separately for each of them

#### Server Side Rendering
That option enables Server Side Rendering (SSR) for `ff-record-list` element on category and search result pages.
That means when user navigate to a page of mentioned type, the HTML output will contain the pre-rendered custom elements.
This is useful especially in terms of SEO because `ff-record-list` renders product data which could have much impact on page rating in browser.
Without SSR enabled, web crawlers could not have a chance to scan the element rendered content because it will not yet be rendered on the time of scanning.

**Note:** More information about SSR concept you can find in the article [Server Side Rendering](https://web-components.fact-finder.de/documentation/4.x/server-side-rendering) from Web Components documentation.

**Note:** If you have a problem with displaying product images or prices correctly, you probably have Field Roles set incorrectly. You can easily fix this by setting [custom fields roles](#set-custom-field-roles)

## Advanced Settings

![Advanced Settings](docs/assets/advanced-settings.png "Advanced Settings")
Expand All @@ -146,6 +136,20 @@ Note: Sending each request to FACT-Finder instance trough Shopware, you lose on
* Scenario how to count single click on "Add to cart" button
* 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.

#### Server Side Rendering
That option enables Server Side Rendering (SSR) for `ff-record-list` element on category and search result pages.
That means when user navigate to a page of mentioned type, the HTML output will contain the pre-rendered custom elements.
This is useful especially in terms of SEO because `ff-record-list` renders product data which could have much impact on page rating in browser.
Without SSR enabled, web crawlers could not have a chance to scan the element rendered content because it will not yet be rendered on the time of scanning.

**Note:** More information about SSR concept you can find in the article [Server Side Rendering](https://web-components.fact-finder.de/documentation/4.x/server-side-rendering) from Web Components documentation.

* Redirect to product detail page for single search result? - This option only works with server side rendering enabled. If SSR search result has one result it will automatically be redirected to the product detail page.
This setting also works with category pages. **Note:** Redirection only happens when search is done via Server Side Rendering. If search is done via WebComponents redirect will not happen.

**Note:** If you have a problem with displaying product images or prices correctly, you probably have Field Roles set incorrectly. You can easily fix this by setting [custom fields roles](#set-custom-field-roles)


## Features Settings

![Features Settings](docs/assets/feature-settings.png "Features Settings")
Expand Down
Binary file modified docs/assets/advanced-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/assets/main-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/Config/Communication.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ public function isProxyEnabled(): bool
return (bool) $this->config('useProxy');
}

public function isSsrPdpEnabled(): bool
{
return (bool) $this->config('useSsrPdp');
}

public function getFactFinderFeatures(): array
{
return [
Expand Down
20 changes: 14 additions & 6 deletions src/Resources/config/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@
<required>true</required>
</input-field>

<input-field type="bool">
<name>useSsr</name>
<label>Use server-side rendering?</label>
<label lang="de-DE">Serverseitiges Rendering verwenden?</label>
</input-field>

<component name="update-field-roles">
<name>fieldRoles</name>
</component>
Expand All @@ -46,6 +40,20 @@
<title>Advanced Settings</title>
<title lang="de-DE">Erweiterte Einstellungen</title>

<input-field type="bool">
<name>useSsr</name>
<label>Use server-side rendering [SSR]?</label>
<label lang="de-DE">Serverseitiges Rendering verwenden [SSR]?</label>
</input-field>

<input-field type="bool">
<name>useSsrPdp</name>
<label>[SSR] Redirect to product detail page for single search result?</label>
<label lang="de-DE">[SSR] Für einzelne Suchergebnisse zur Produktdetailseite weiterleiten?</label>
<helpText>This option only works with server side rendering [SSR] enabled. If SSR search result has one result it will automatically be redirected to the product detail page. This is also working with category pages.</helpText>
<helpText lang="de-DE">Diese Option funktioniert nur, wenn das serverseitige Rendering [SSR] aktiviert ist. Wenn das SSR-Suchergebnis ein Ergebnis enthält, wird es automatisch auf die Produktdetailseite umgeleitet [PDP].</helpText>
</input-field>

<input-field type="bool">
<name>useProxy</name>
<label>Use Proxy?</label>
Expand Down
5 changes: 3 additions & 2 deletions src/Storefront/Controller/ResultController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Omikron\FactFinder\Shopware6\Storefront\Controller;

use Omikron\FactFinder\Shopware6\Config\Communication;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\Exception\DetectRedirectCampaignException;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\Exception\DetectRedirectException;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\SearchAdapter;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\Template\Engine;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\Template\RecordList;
Expand Down Expand Up @@ -44,6 +44,7 @@ public function result(
$request,
$handlebars,
$searchAdapter,
$this->config,
$context->getSalesChannelId(),
$response->getContent(),
);
Expand All @@ -54,7 +55,7 @@ public function result(
$this->parseQueryString($request->getQueryString() ?? '', $request)
)
);
} catch (DetectRedirectCampaignException $exception) {
} catch (DetectRedirectException $exception) {
return new RedirectResponse($exception->getRedirectUrl());
}

Expand Down
5 changes: 3 additions & 2 deletions src/Subscriber/CategoryPageResponseSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Omikron\FactFinder\Shopware6\Subscriber;

use Omikron\FactFinder\Shopware6\Config\Communication;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\Exception\DetectRedirectCampaignException;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\Exception\DetectRedirectException;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\Field\CategoryPath;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\SearchAdapter;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\Template\Engine;
Expand Down Expand Up @@ -78,6 +78,7 @@ public function onPageRendered(ResponseEvent $event): void
$request,
$this->handlebars,
$this->searchAdapter,
$this->config,
$request->attributes->get('sw-sales-channel-id'),
$response->getContent(),
);
Expand All @@ -89,7 +90,7 @@ public function onPageRendered(ResponseEvent $event): void
true
)
);
} catch (DetectRedirectCampaignException $exception) {
} catch (DetectRedirectException $exception) {
$event->setResponse(new RedirectResponse($exception->getRedirectUrl()));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Omikron\FactFinder\Shopware6\Utilites\Ssr\Exception;

class DetectRedirectCampaignException extends \Exception
class DetectRedirectException extends \Exception
{
private string $redirectUrl;

Expand Down
35 changes: 28 additions & 7 deletions src/Utilites/Ssr/Template/RecordList.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

namespace Omikron\FactFinder\Shopware6\Utilites\Ssr\Template;

use Omikron\FactFinder\Shopware6\Utilites\Ssr\Exception\DetectRedirectCampaignException;
use Omikron\FactFinder\Shopware6\Config\Communication;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\Exception\DetectRedirectException;
use Omikron\FactFinder\Shopware6\Utilites\Ssr\SearchAdapter;
use Symfony\Component\HttpFoundation\Request;

Expand All @@ -19,11 +20,13 @@ class RecordList
private string $salesChannelId;
private string $content;
private string $template;
private Communication $pluginConfig;

public function __construct(
Request $request,
Engine $handlebars,
SearchAdapter $searchAdapter,
Communication $pluginConfig,
string $salesChannelId,
string $content,
) {
Expand All @@ -32,13 +35,14 @@ public function __construct(
$this->searchAdapter = $searchAdapter;
$this->salesChannelId = $salesChannelId;
$this->content = $content;
$this->pluginConfig = $pluginConfig;
$this->setTemplateString();
}

/**
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
*
* @throws DetectRedirectCampaignException
* @throws DetectRedirectException
*/
public function getContent(
string $paramString,
Expand All @@ -48,7 +52,14 @@ public function getContent(

// Support redirect campaigns for SSR
if ($this->getRedirectCampaign($results)) {
throw new DetectRedirectCampaignException($this->getRedirectCampaign($results));
throw new DetectRedirectException($this->getRedirectCampaign($results));
}

// Support redirect to PDP if found one result
if ($this->pluginConfig->isSsrPdpEnabled()) {
if ($this->shouldRedirectToPDP($results) && $this->getProductDeeplink($results)) {
throw new DetectRedirectException($this->getProductDeeplink($results));
}
}

return $this->renderResults($results, $paramString);
Expand Down Expand Up @@ -121,14 +132,24 @@ private function setTemplateString(): void
$this->template = $match[0] ?? '';
}

private function getRedirectCampaign(array $result): ?string
private function getRedirectCampaign(array $results): ?string
{
if (!empty($result['campaigns'])) {
$campaign = array_search('REDIRECT', array_column($result['campaigns'], 'flavour'));
if (!empty($results['campaigns'])) {
$campaign = array_search('REDIRECT', array_column($results['campaigns'], 'flavour'));

return $result['campaigns'][$campaign]['target']['destination'] ?? null;
return $results['campaigns'][$campaign]['target']['destination'] ?? null;
}

return null;
}

private function shouldRedirectToPDP(array $results): bool
{
return count($results['records']) === 1 && $results['totalHits'] === 1;
}

private function getProductDeeplink(array $results): ?string
{
return $results['records'][0]['record']['Deeplink'] ?? null;
}
}

0 comments on commit 49e1e51

Please sign in to comment.