Produkte nach Custom Fields sortieren

Hallo,

mein Kunde bnötigt eine individuelle Sortierung seiner Produkte im Shop.
Diese habe ich per Import in ein Custom Field „products_sorting“ importiert.

In Products Listing habe ich den Filter zur Sortierung in der product.xml wie folgt erweitert:

	customSorting-asc
	filter.sortCustomAscending
	
		asc

Bei der Auswahl des Filters werden die Produkte zwar umsortiert, jedoch nicht wie erwartet.
Die Werte innerhalb des Custom Fields sind numerisch: 10010, 10020, 10030, …
Ich kann bei der Sortierung der Produkte im Shop keine Logik erkennen.

Hat jemand eine Idee, warum die Sortierung nicht funktioniert?

Danke!

Welchen Datentypen hast du für das Custom Field eingestellt?

AlexGalax, danke für den Hinweis.

Bisher hatte ich “Textfeld” als Typ für das Custom Field eingestellt.

Jetzt habe ich folgende Konfiguration für das Custom Field:

Typ: Zahl
Zahlentyp: Ganzzahl
Schritte: 1
Minimum: 0
Maximum: 999999999999

Die Sortierung funktioniert jedoch immer noch nicht wie erwartet und eine Sortierungs-Logik lässt sich aus dem Listing nicht ableiten.
Die Reihenfolge der Produkte ist beispielweise (im Custom Fileld der gelisteten Produkte steht): 1030040, 1030050, 1010110, 1010090, 1030140, …

Hier die SQL-Query (aus Symfony Profiler/Doctrine), in der das Custom Field “productsSorting” im ORDER BY Teil verwendet wird:

SELECT SQL_CALC_FOUND_ROWS `product`.`id` FROM `product`
...
ORDER BY MIN(COALESCE(IF(JSON_TYPE(JSON_EXTRACT(`product.translation.customFields`, '$.productsSorting')) != "NULL", CONVERT(JSON_UNQUOTE(JSON_EXTRACT(`product.translation.customFields`, '$.productsSorting')) USING "utf8mb4") COLLATE utf8mb4_unicode_ci, NULL),IF(JSON_TYPE(JSON_EXTRACT(`product.parent.translation.customFields`, '$.productsSorting')) != "NULL", CONVERT(JSON_UNQUOTE(JSON_EXTRACT(`product.parent.translation.customFields`, '$.productsSorting')) USING "utf8mb4")

Wirst Du daraus schlau?

ORDER BY MIN(
	COALESCE(
		IF(JSON_TYPE(JSON_EXTRACT(`product.translation.customFields`, '$.productsSorting')) != "NULL", 
			CONVERT(JSON_UNQUOTE(JSON_EXTRACT(`product.translation.customFields`, '$.productsSorting')) USING "utf8mb4") COLLATE utf8mb4_unicode_ci, 
			NULL
		),
		IF(JSON_TYPE(JSON_EXTRACT(`product.parent.translation.customFields`, '$.productsSorting')) != "NULL", 
			CONVERT(JSON_UNQUOTE(JSON_EXTRACT(`product.parent.translation.customFields`, '$.productsSorting')) USING "utf8mb4")

Ist unvollständig aber ORDER BY MIN(... finde ich schon merkwürdig. MIN() gibt ja immer nur einen Wert aus dem gesamten Ergebnis zurück, keine Ahnung wie das bei der Sortierung helfen soll.

1 „Gefällt mir“

Ich habs, jetzt funktioniert es!

Ich nahm an, dass das Custom Filed in der product.xml in Camel Case geschrieben werden muss, also productsSorting , wie z.B. productNumber, da diese in der products Tabelle product_number heißt. Es muss allerdings der technische Name des Custom Fields verwendet werden, also in meinem Fall „products_sorting“.
Hier noch einmal die korrekte XML-Definition:

	customSorting-asc
	filter.sortCustomAscending
	
		asc

Möchte man im Übrigen die Standart-Sortierung des Filters auf das Custom Field ändern, dann muss man die Konstante DEFAULT_SORT in 
vendor/shopware/core/Content/Product/SalesChannel/Listing/ProductListingFeaturesSubscriber.php wie folgt ändern:

public const DEFAULT_SORT = 'customSorting-asc';

Der Titel ‚customSorting-asc‘ ist von mir gewählt und lässt sich natürlich frei definieren.

Im Übrigen ist das Ganze natürlich nicht Updatesicher.
Falls jemand eine Anleitung hat, wie man das ins custom Template oder in ein custom Plugin packt, dann bitte her damit!

AlexGalax, vielen Dank für Deine Hilfe!

Darf ich fragen, wie du das Freitextfeld in den Query mit einbezogen hast?
Ich sitze gerade daran, ungefähr das gleiche zu realisieren.

Ich habe ein Freitextfeld angelegt weiß aber zur Zeit noch nicht, wie ich jetzt Shopware sagen kann, dass er den int-Wert des Freitextfeldes zum Sortieren nutzen soll.

Vielleicht kann ich dir dann dabei helfen das als Plugin zu verpacken.

Cheers

Hallo @SF-Schneider,

Dein Freitext-Feld musst Du in vendor/shopware/core/Content/DependencyInjection/product.xml integrieren, damit es in der Query einbezogen wird.
Mein Beispiel: Sortierung absteigend nach Produkt-Attributen:

<service id="product_listing.sorting.customFields.custom_products_sorting_ascending" class="Shopware\Core\Content\Product\SalesChannel\Listing\ProductListingSorting">
  <argument>attributes-asc</argument>
  <argument>filter.sortByAttributesAscending</argument>
  <argument type="collection">
    <argument key="product.customFields.custom_products_sorting">asc</argument>
  </argument>
  <tag name="shopware.sales_channel.product_listing.sorting" />
</service>

Hallo,

habt ihr das Beispiel von Shopware in der Dokumentationen genau für diesen Zweck mal probiert: Add custom sorting for product listing - Shopware Developer ? Damit dürfte es doch problemlos möglich sein - als „field“ - Wert dann natürlich „product.customFields.myprocustumfield“.

Die Sortierung als Standard-Sortierung updatesicher festzulegen, dürfte über einen Subscriber auf ProductListingCriteriaEvent und ProductSearchCriteriaEvent, wo die Variable order vom Request entsprechend angepasst wird, genauso möglich sein.

Viele Grüße

Sebastian

Vielen Dank für die Details!

Ich habe mich gestern noch mit der Thematik auseinander gesetzt und ein Plugin geschrieben, welches aber die angemerkte Methodik von @sschreier verwendet.
Ich bin anfänglich auf Probleme gestoßen, aber jetzt sollte es funktionieren.
Da die Sortierung nur ein Teil des Plugins ist, kann ich bei Bedarf die Sortierung schnell in ein eigenes Plugin ziehen.

Ich bin dabei aber direkt über die Datenbank gegangen und habe die Sortierung fest geschrieben.

Cheers

@SF-Schneider Steht das erwähnte Plugin im Store zur Verfügung? Wenn ja, mit welchem Namen?
Wenn nein, wäre es möglich das Plugin auf einem anderen Weg zu erhalten?
Wir sind sicher auch nicht die einzigen, die mit der Anforderung nach „individuellen Sortiermöglichkeiten“ in Shopware 6 kämpfen.

Hi @stormerMike,
leider war das erwähnte Plugin nicht für den Store gedacht und dient als interne Lösung für einen Kunden.

Vielleicht kann ich dennoch Hilfe leisten:
Ich habe per Plugin-MIgration einen neuen Eintrag in die product_sorting-Tabelle geschrieben

$customSorting = [
            'id' => Uuid::randomBytes(),
            'url_key' => 'sfce-value-sort',  // shown in url - must be unique system wide
            'priority' => 5,                // the higher the priority, the further upwards it will be shown in the sortings dropdown in storefront
            'active' => 1,                  // activate / deactivate the sorting
            'locked' => 0,                  // you can lock the sorting here to prevent it from being edited in the administration
            'fields' => json_encode([
                [
                    'field' => 'product.customFields.sf_cms_elements_product_sort_value',  // field to sort by
                    'order' => 'asc',          // asc or desc
                    'priority' => 100,            // in which order the sorting is to applied (higher priority comes first)
                    'naturalSorting' => 0       // apply natural sorting logic to this field
                ],
                [
                    'field' => 'product.name',  // field to sort by
                    'order' => 'asc',          // asc or desc
                    'priority' => 50,            // in which order the sorting is to applied (higher priority comes first)
                    'naturalSorting' => 0       // apply natural sorting logic to this field
                ],
            ]),
            'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT),
        ];

        // insert the product sorting
        $connection->insert(ProductSortingDefinition::ENTITY_NAME, $customSorting);

        // insert the translation for the translatable label
        // if you use multiple languages, you will need to update all of them
        $connection->executeStatement(
            'REPLACE INTO product_sorting_translation
             (`language_id`, `product_sorting_id`, `label`, `created_at`)
             VALUES
             (:language_id, :product_sorting_id, :label, :created_at)',
            [
                'language_id' => Uuid::fromHexToBytes(Defaults::LANGUAGE_SYSTEM),
                'product_sorting_id' => $customSorting['id'],
                'label' => 'SfCmsElements - SortValue-Sorter',
                'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT),
            ]
        );

Hier wird eine neue Sortierung zur Verfügung gestellt, die zuerst nach dem Freitextfeld ''sf_cms_elements_product_sort_value" (integer) der Produkte sortieren soll und danach nach dem Namen. Da das alles schon etwas her ist, stecke ich da nicht mehr so genau im Thema drin.

Vielleicht hilft dir ja der Ansatz weiter. Solltest du doch mehr Hilfe benötigen gerne per DM.

Cheers

Danke @SF-Schneider für die Bereitstellung des Codes.
Hilft mir/uns eventuell schon weiter bzw. anderen auch die hier noch vorbei kommen.