Repository: shopware/shopware (PHP)

Issue:
Apply search score as fallback sort criteria on searching
### Technical TODO

Currently when searching, the `_score` (search rank) is the default sort criteria applies. They can change this criteria to something else like Topseller or price.

However, if products have equal values for these sort conditions, the ID is then used for the fallback sort, bring less relevant search results.

So the idea is to apply the _score order as fallback when searching even though they select any sort criteria



Fix (patch):
diff --git a/changelog/_unreleased/2025-08-26-apply-search-score-as-fallback-sort-criteria-on-searching.md b/changelog/_unreleased/2025-08-26-apply-search-score-as-fallback-sort-criteria-on-searching.md
new file mode 100644
index 00000000000..fa826185123
--- /dev/null
+++ b/changelog/_unreleased/2025-08-26-apply-search-score-as-fallback-sort-criteria-on-searching.md
@@ -0,0 +1,7 @@
+---
+title: Apply search score as fallback sort criteria on searching
+issue: 12074
+---
+# Core
+* Changed `createDalSorting` method in `Shopware\Core\Content\Product\SalesChannel\Sorting\ProductSortingEntity` to apply _score sorting as fallback sort criteria on searching.
+* Changed `prepare` method in `Shopware\Core\Content\Product\SalesChannel\Listing\Processor\SortingListingProcessor` to check if search criteria has a _score calculation and selection, then apply _score sorting as fallback sort criteria.
diff --git a/src/Core/Content/Product/SalesChannel/Listing/Processor/SortingListingProcessor.php b/src/Core/Content/Product/SalesChannel/Listing/Processor/SortingListingProcessor.php
index a23fb6d60b5..8585a8daa1f 100644
--- a/src/Core/Content/Product/SalesChannel/Listing/Processor/SortingListingProcessor.php
+++ b/src/Core/Content/Product/SalesChannel/Listing/Processor/SortingListingProcessor.php
@@ -52,8 +52,13 @@ public function prepare(Request $request, Criteria $criteria, SalesChannelContex
         $currentSorting = $this->getCurrentSorting($sortings, $request, $context->getSalesChannelId());
 
         if ($currentSorting !== null) {
+            $fallbackSorting = null;
+            if ($this->hasQueriesOrTerm($criteria)) {
+                $fallbackSorting = new FieldSorting('_score', FieldSorting::DESCENDING);
+            }
+
             $criteria->addSorting(
-                ...$currentSorting->createDalSorting()
+                ...$currentSorting->createDalSorting($fallbackSorting)
             );
         }
 
@@ -73,6 +78,11 @@ public function process(Request $request, ProductListingResult $result, SalesCha
         $result->setAvailableSortings($sortings);
     }
 
+    private function hasQueriesOrTerm(Criteria $criteria): bool
+    {
+        return !empty($criteria->getQueries()) || $criteria->getTerm();
+    }
+
     private function getCurrentSorting(ProductSortingCollection $sortings, Request $request, string $salesChannelId): ?ProductSortingEntity
     {
         $key = $request->get('order');
diff --git a/src/Core/Content/Product/SalesChannel/Sorting/ProductSortingEntity.php b/src/Core/Content/Product/SalesChannel/Sorting/ProductSortingEntity.php
index 9073af3374c..4c3888029ba 100644
--- a/src/Core/Content/Product/SalesChannel/Sorting/ProductSortingEntity.php
+++ b/src/Core/Content/Product/SalesChannel/Sorting/ProductSortingEntity.php
@@ -30,10 +30,14 @@ class ProductSortingEntity extends Entity
     protected bool $locked;
 
     /**
+     * @deprecated tag:v6.8.0 - reason:new-optional-parameter - parameter $fallbackSorting will be added
+     *
      * @return array<FieldSorting>
      */
-    public function createDalSorting(): array
+    public function createDalSorting(/* ?FieldSorting $fallbackSorting = null */): array
     {
+        $fallbackSorting = \func_num_args() === 1 ? func_get_arg(0) : null;
+
         $sorting = [];
 
         $fields = $this->fields;
@@ -54,6 +58,10 @@ public function createDalSorting(): array
 
         $flat = array_column($fields, 'field');
 
+        if ($fallbackSorting instanceof FieldSorting && !\in_array($fallbackSorting->getField(), $flat, true)) {
+            $sorting[] = $fallbackSorting;
+        }
+
         if (\in_array('id', $flat, true)) {
             return $sorting;
         }