Fermer

septembre 19, 2022

SXA Trier les résultats de la recherche par distance pour plusieurs emplacements cartographiés


Défi:

Nous avons vu comment trier les emplacements, c’est-à-dire les éléments POI par distance en fonction de l’emplacement actuel de l’utilisateur ou de l’emplacement donné par l’utilisateur. (Se référer à l’article – Composant SXA Map Partie 3 pour plus de détails.) Dans cet article, nous verrons comment trier les résultats de recherche des éléments non POI par distance. Fondamentalement, les éléments de contenu où chaque élément fait référence à un ou plusieurs éléments d’emplacement de POI.

Considérons maintenant une exigence telle qu’en tant qu’acheteur immobilier, je souhaite afficher le résultat des sociétés du groupe Builders avec les villes où elles ont lancé leurs projets immobiliers et la liste doit être triée par distance.

La solution:

Un rapide coup d’œil à la sortie suivante de la mise en œuvre discutée dans ce post, afin que nous obtenions plus de clarté.

Démo rapide de la sortie attendue

Résultat de la mise en œuvre

Ici, nous avons utilisé un localisateur personnalisé et des composants de résultats de recherche.

Remarque : Location Finder et Location Filter sont les mêmes composants. C’est juste que le nom d’affichage est Location Finder. Donc, à partir de maintenant, si je me réfère à Location Filter, c’est le même composant Location Finder 🙂

Idée de haut niveau

Puisque nous voulons trier la liste Builder Group par les villes les plus proches, nous allons introduire le champ calculé pour l’élément Builder group. Appelons cela « coordonnées multiples ». Ce champ calculé stockera toutes les coordonnées des éléments de POI référencés par l’élément de groupe constructeur correspondant. Nous personnaliserons le service de tri de Sitecore pour prendre en charge le tri basé sur le champ calculé « multiplecoordinates ».

Mise en œuvre

Original Location Finder transmet les coordonnées de l’emplacement saisi par l’utilisateur dans le paramètre de hachage « g ». L’implémentation backend du service de recherche Sitecore s’appuie sur ce paramètre g pour décider si la demande de recherche concerne les éléments POI ou les éléments non POI. (Se référer à l’article – Composant SXA Map Partie 2 pour plus de détails). Comme nous voulons afficher les résultats des éléments du groupe Builders, c’est-à-dire les éléments non POI, nous devons transmettre les coordonnées de localisation fournies par l’utilisateur dans le nouveau paramètre. Appelons-le cg. Nous avons donc cette coordonnée et l’utilisons pour notre implémentation personnalisée.

Pour réaliser cette partie, clonez le rendu existant de Location Finder /sitecore/layout/Renderings/Feature/Experience Accelerator/Search/Location Filter. Reportez-vous à la belle documentation de Sitecore sur Copier et personnaliser un rendu.

Cloner le localisateur

Cloner le localisateur

Cloner le localisateur - Configuration

Cloner le Localisateur – ConfigurerMettre à jour les champs ci-dessus et le reste reste inchangé.
Le rendu de la valeur de la classe CSS « custom-location-filter » est important car il sera utilisé dans nos nouveaux fichiers JS et SCSS.

Ajoutez un élément de modèle /Feature/Custom Experience Accelerator/Custom Location Finder/Custom Location Filter Folder, sous /sitecore/content/{tenant}/{site}/Data/Search.

Si aucun élément de ce modèle n’est trouvé sous /sitecore/content/{tenant}/{site}/Data, lors de l’ajout du rendu dans l’éditeur de page, la boîte de dialogue « Sélectionner le contenu associé » ne s’affiche pas pour définir la source de données.

Télécharger le CustomLocationFinder.js et chargez-le dans le dossier de script de thème de votre site /sitecore/media library/Themes/{tenant}/{site}/{theme}/Scripts.

Différence JS de recherche de localisation personnalisée

Différence JS de recherche de localisation personnalisée

Nous avons un fichier JS pour Location Finder d’origine /sitecore/media library/Base Themes/SearchTheme/Scripts/component-search-location-filter. Nous avons utilisé le même code avec quelques modifications. Ici, le nom de la classe CSS, le nom du composant pour l’enregistrement, et « g » et « _g » sont remplacés par « cg » et « _cg ».

Nous pouvons hériter du même style de /sitecore/media library/Themes/Wireframe/sass/base/search/_component-location. Ajouter composant-emplacement-personnalisé.scss code de fichier pour le site. Reportez-vous à la documentation de Sitecore sur Stylez les sites SXA avec Sass. Sans cela, le rendu ne sera pas correct.

@import "base/search/_component-location";
.custom-location-filter {
   @extend .location-filter;
}

Implémentation back-end

Veuillez vérifier les commentaires pour plus de détails.

Code de champ calculé à coordonnées multiples

using Sitecore.ContentSearch;
using Sitecore.ContentSearch.ComputedFields;
using Sitecore.Data;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml;

namespace CustomSXA.Foundation.Search.ComputedFields
{
    public class Multiplecoordinates : AbstractComputedIndexField
    {
        public string TemplateName { get; set; }
        public string ItemFieldName { get; set; }
        public Multiplecoordinates() : base()
        { }
        public Multiplecoordinates(XmlNode node) : base(node)
        {
            if (node == null)
                return;
            this.TemplateName = node.Attributes?["templateName"]?.Value;
            this.ItemFieldName = node.Attributes?["itemFieldName"]?.Value;
        }
        public override object ComputeFieldValue(IIndexable indexable)
        {
            Item obj = (Item)(indexable as SitecoreIndexableItem);
            if (obj == null)
                return (object)null;
            if (string.Equals(obj.TemplateName, TemplateName, StringComparison.OrdinalIgnoreCase))
            {
                List<string> multipleCoordinates = new List<string>();
                MultilistField locations = obj.Fields[ItemFieldName];
                foreach (var item in locations.GetItems())
                {
                    string coordinate = GetCoordinate(item) as string;
                    if (coordinate != null)
                        multipleCoordinates.Add(coordinate);
                }

                if (multipleCoordinates.Count > 0)
                    return multipleCoordinates;
            }
            return null;
        }

        private static object GetCoordinate(Item obj)
        {
            double result1;
            double result2;
            return !double.TryParse(obj[new ID(Sitecore.ContentSearch.Utilities.Constants.Latitude)], NumberStyles.Any, (IFormatProvider)CultureInfo.InvariantCulture, out result1)
                || !double.TryParse(obj[new ID(Sitecore.ContentSearch.Utilities.Constants.Longitude)], NumberStyles.Any, (IFormatProvider)CultureInfo.InvariantCulture, out result2)
                ? (object)null : (object)new Sitecore.ContentSearch.Data.Coordinate(result1, result2).ToString();
        }
    }
}

Ajoutez un champ personnalisé à un schéma Solr pour ces coordonnées multiples.

Sitecore - Comprendre les approches de développement : une perspective de Sitecore

Code CustomPopulateHelper

using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Sitecore.ContentSearch.SolrProvider.Pipelines.PopulateSolrSchema;
using SolrNet.Schema;

namespace CustomSXA.Foundation.Search.PopulateHelper
{
    public class CustomPopulateHelper : SchemaPopulateHelper
    {
        public CustomPopulateHelper(SolrSchema schema) : base(schema)
        {}

        public override IEnumerable<XElement> GetAllFields()
        {
            return base.GetAllFields().Union(GetAddCustomFields());
        }

        private IEnumerable<XElement> GetAddCustomFields()
        {
            //Adds below field in the managed-schema file.
            //<field name="multiplecoordinates" type="location" multiValued="true"/>
            yield return CreateField("multiplecoordinates",
                "location",
                isDynamic: false,
                required: false,
                indexed: false,
                stored: false,
                multiValued: true,
                omitNorms: false,
                termOffsets: false,
                termPositions: false,
                termVectors: false);
        }
    }
}

Code CustomPopulateHelperFactory

using Sitecore.ContentSearch.SolrProvider.Abstractions;
using Sitecore.ContentSearch.SolrProvider.Pipelines.PopulateSolrSchema;
using SolrNet.Schema;

namespace CustomSXA.Foundation.Search.PopulateHelper
{
    public class CustomPopulateHelperFactory : IPopulateHelperFactory
    {
        public ISchemaPopulateHelper GetPopulateHelper(SolrSchema solrSchema)
        {
            return new CustomPopulateHelper(solrSchema);
        }
    }
}

Si nous n’ajoutons pas ce champ à un schéma SOLR et testons avec le reste de l’implémentation, nous obtenons l’erreur ci-dessous.

ERREUR Erreur Solr : [sort param could not be parsed as a query, and is not a field that exists in the index: geodist()]

Le code du service de tri a la même implémentation que Sitecore.XA.Foundation.Search.Services. SortingService avec l’ajout de la partie else comme ci-dessous dans la méthode Order. Vérifier Service de tri pour le code complet.

if (sortingFacet.Facet.DoesItemInheritFrom(Sitecore.XA.Foundation.Search.Templates.DistanceFacet.ID))
{
    if (center != null)
        query = (IQueryable<ContentPage>)query.OrderByDistance<ContentPage, Coordinate>((Expression<Func<ContentPage, Coordinate>>)(i => i.Location), center);
    else //This else part added to enhance the Sorting service with sort by distance for multiple coordinates i.e. POI items mapped for a non POI item.
    {
        center = Helper.GeoLocationHelper.GetLocationCentre();
        if (center != null)
            query = (IQueryable<ContentPage>)query.OrderByDistance<ContentPage, string>((Expression<Func<ContentPage, string>>)(i => i["multiplecoordinates"]), center); //sorting based on the computed field multiplecoordinates.
        return query;
    }
}

Classes GeoLocationHelper – Fournit le côté serveur des coordonnées de localisation données par l’utilisateur. Ceci est utilisé par plusieurs classes personnalisées utilisées dans notre implémentation.

using Microsoft.Extensions.DependencyInjection;
using Sitecore.ContentSearch.Data;
using Sitecore.DependencyInjection;
using System;
using System.Linq;
using System.Web;
using Sitecore.XA.Foundation.SitecoreExtensions.Interfaces;

namespace CustomSXA.Foundation.Search.Helper
{
    /// <summary>
    /// Used by several classes used in our sort by distance for multiple locations case
    /// </summary>
    public static class GeoLocationHelper
    {
        public static Coordinate GetLocationCentre(string key = "g")
        {
            IRendering rendering = ServiceLocator.ServiceProvider.GetService<IRendering>();
            if (rendering == null)
                return null;
            string sign = rendering.Parameters["Signature"];
            string coordinates = string.Empty;
            double lat, lon;
            if (HttpContext.Current.Request[$"{sign}_{key}"] != null)
            {   //case 1 - component signature_g value from browser URL hash parameter
                coordinates = HttpContext.Current.Request[$"{sign}_{key}"];
            }
            else if (HttpContext.Current.Request[key] != null)
            {   //case 2 - regular default g value from browser URL hash parameter
                coordinates = HttpContext.Current.Request[key];
            }
            else if (GetURLRefererQueryStringParamValue($"{sign}_{key}") != null)
            {   //case 3 - component signature_g value from browser URL querystring parameter
                coordinates = GetURLRefererQueryStringParamValue($"{sign}_{key}");
            }
            else if (GetURLRefererQueryStringParamValue(key) != null)
            {   //case 4 - regular default g value from browser URL querystring parameter
                coordinates = GetURLRefererQueryStringParamValue(key);
            }

            if (!string.IsNullOrWhiteSpace(coordinates))
            {
                string[] coordinatesValues = coordinates.Split('|'); //split the coordinates value to create and return coordinate instance
                if (coordinatesValues.Length == 2)
                {
                    lat = Convert.ToDouble(coordinatesValues[0]);
                    lon = Convert.ToDouble(coordinatesValues[1]);
                    return new Coordinate(lat, lon);
                }
            }

            if (string.Equals(key, "cg")) //end the recursive call
                return null;
            return GetLocationCentre("cg"); //recursive call to check for cg key value
        }

        private static string GetURLRefererQueryStringParamValue(string paramName)
        {
            if (HttpContext.Current.Request.UrlReferrer != null)
            {
                var queryCollection = HttpUtility.ParseQueryString(HttpContext.Current.Request.UrlReferrer.Query);
                if (queryCollection.AllKeys.Contains(paramName, StringComparer.OrdinalIgnoreCase))
                {
                    return queryCollection.Get(paramName) ?? queryCollection.Get(paramName.ToLower());
                }
            }
            return null;
        }
    }
}

Code LocationItemExtensions

using Sitecore.Data.Items;
using Sitecore.XA.Foundation.Search.Models;
using Sitecore.XA.Foundation.SitecoreExtensions.Extensions;

namespace CustomSXA.Foundation.Search.Helper
{
    /// <summary>
    /// Provides the distance between the given user location coordinate and the POI item's coordinate
    /// </summary>
    public static class LocationItemExtensions
    {
        public static double? GetDistance(this Item item, Unit unit)
        {
            if (item != null)
            {
                if (item.InheritsFrom(Sitecore.XA.Foundation.Geospatial.Templates.IPoi.ID))
                {
                    var centre = Helper.GeoLocationHelper.GetLocationCentre();
                    if (centre != null)
                    {
                        return new Geospatial(item, centre, unit).Distance;
                    }
                }
            }
            return null;
        }
    }
}

Code AddFollowFunctionsLocations

using Scriban.Runtime;
using Sitecore.Data.Items;
using Sitecore.XA.Foundation.Scriban.Pipelines.GenerateScribanContext;
using Sitecore.XA.Foundation.SitecoreExtensions.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using Sitecore.XA.Foundation.Search.Models;
using CustomSXA.Foundation.Search.Helper;

namespace CustomSXA.Foundation.Search.RenderingVariants.Pipelines.GenerateScribanContext
{
    /// <summary>
    /// Provides scriban function sc_followlocations. This is used to get the POI items refered by a non POI item.
    /// The list is sorted by distance in ascending order.
    /// </summary>
    public class AddFollowFunctionsLocations : IGenerateScribanContextProcessor
    {
        private delegate IEnumerable<Item> GetItems(Item item, string fieldName, string distanceUnit);

        protected readonly IPassthroughService PassthroughService;

        public AddFollowFunctionsLocations(IPassthroughService passthroughService) => this.PassthroughService = passthroughService;

        public void Process(GenerateScribanContextPipelineArgs args)
        {
            var getItemsImplementation = new GetItems(GetItemsImplementation);
            args.GlobalScriptObject.Import("sc_followlocations", getItemsImplementation);
        }

        public IEnumerable<Item> GetItemsImplementation(Item item, string fieldName, string distanceUnit = "Miles")
        {
            IEnumerable<Item> items = this.PassthroughService.GetTargetItems(item, fieldName);
            return items?.OrderBy(loc => loc.GetDistance((Unit)Enum.Parse(typeof(Unit), distanceUnit))); //returns the list of POI items sorted by distance
        }
    }
}

Code GetGeospatial

using System;
using Scriban.Runtime;
using Sitecore.Data.Items;
using Sitecore.XA.Foundation.Scriban.Pipelines.GenerateScribanContext;
using Sitecore.XA.Foundation.Search.Models;
using Sitecore.XA.Foundation.SitecoreExtensions.Extensions;

namespace CustomSXA.Foundation.Search.RenderingVariants.Pipelines.GenerateScribanContext
{
    /// <summary>
    /// Provides scriban function st_geospatial. This is used to provide the  Geospatial instance for a POI item.
    /// Using this Geospatial instance we get the distance.
    /// </summary>
    public class GetGeospatial : IGenerateScribanContextProcessor
    {
        private delegate Geospatial GetGeospatialModel(Item item, string distanceUnit);

        public void Process(GenerateScribanContextPipelineArgs args)
        {
            var getGetGeospatialModelImplementation = new GetGeospatialModel(GetGeospatialModelImplementation);
            args.GlobalScriptObject.Import("st_geospatial", getGetGeospatialModelImplementation);
        }

        public Geospatial GetGeospatialModelImplementation(Item item, string distanceUnit = "Miles")
        {
            if (item != null && item.InheritsFrom(Sitecore.XA.Foundation.Geospatial.Templates.IPoi.ID))
            {
                var centre = Helper.GeoLocationHelper.GetLocationCentre();
                if (centre != null)
                {
                    return new Geospatial(item, centre, (Unit)Enum.Parse(typeof(Unit), distanceUnit));
                }
            }
            return null;
        }
    }
}

Corrigez les classes ci-dessus dans un fichier de configuration. Vérifier CustomSXA.Foundation.Search.SortByMultipleDistance.config.

<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <generateScribanContext>
        <!--scriban function to calculate distance-->
        <processor type="CustomSXA.Foundation.Search.RenderingVariants.Pipelines.GenerateScribanContext.GetGeospatial, CustomSXA.Foundation.Search" resolve="true" />
        <!--scriban function to sort by distance, the locations mapped for an item-->
        <processor type="CustomSXA.Foundation.Search.RenderingVariants.Pipelines.GenerateScribanContext.AddFollowFunctionsLocations, CustomSXA.Foundation.Search" resolve="true" />
      </generateScribanContext>
      <contentSearch.PopulateSolrSchema>
        <!--custom solr schema populate code to add multiplecoordinates field-->
        <processor type="Sitecore.ContentSearch.SolrProvider.Pipelines.PopulateSolrSchema.PopulateFields, Sitecore.ContentSearch.SolrProvider">
          <param type="CustomSXA.Foundation.Search.PopulateHelper.CustomPopulateHelperFactory, CustomSXA.Foundation.Search" patch:instead="*[@type="Sitecore.ContentSearch.SolrProvider.Factories.DefaultPopulateHelperFactory"]"/>
        </processor>
      </contentSearch.PopulateSolrSchema>
    </pipelines>
    <services>
      <!--Sorting service enhanced to sort non-POI items by multiple locations mapped in each non-POI item-->
      <register patch:instead="register[@implementationType="Sitecore.XA.Foundation.Search.Services.SortingService, Sitecore.XA.Foundation.Search"]" 
        serviceType="Sitecore.XA.Foundation.Search.Services.ISortingService, Sitecore.XA.Foundation.Search" implementationType="CustomSXA.Foundation.Search.Services.SortingService, CustomSXA.Foundation.Search" lifetime="Singleton"/>
    </services>
    <contentSearch>
      <indexConfigurations>
        <!--multiplecoordinates computed field and mapping -->
        <defaultSolrIndexConfiguration type="Sitecore.ContentSearch.SolrProvider.SolrIndexConfiguration, Sitecore.ContentSearch.SolrProvider">
          <fieldMap>
            <fieldNames hint="raw:AddFieldByFieldName">
              <field fieldName="multiplecoordinates" returnType="stringCollection" />
            </fieldNames>
          </fieldMap>
          <documentOptions type="Sitecore.ContentSearch.SolrProvider.SolrDocumentBuilderOptions, Sitecore.ContentSearch.SolrProvider">
            <fields hint="raw:AddComputedIndexField">
              <!--Do update the templateName and itemFieldName property values-->
              <!--templateName - Name of the non POI item template-->
              <!--itemFieldName - Name of the field which references the POI items-->
              <field fieldName="multiplecoordinates" templateName="Builder Group" itemFieldName="Real Estate Projects Locations" returnType="stringCollection">CustomSXA.Foundation.Search.ComputedFields.Multiplecoordinates, CustomSXA.Foundation.Search</field>
            </fields>
          </documentOptions>
        </defaultSolrIndexConfiguration>
      </indexConfigurations>
    </contentSearch>
  </sitecore>
</configuration>

Mettez à jour les valeurs des propriétés templateName et itemFieldName pour le champ calculé – multiplecoordinates, avec celles que vous avez dans votre cas.

Découvrez le code complet de la Référentiel GitHub.

Créez et déployez des solutions sur le Webroot.

Action dans le CMS

Créez le modèle Builder Group héritant du modèle Page et ayez les champs comme ci-dessous.

Modèle de groupe de générateurs

Modèle de groupe de générateurs

La requête source pour le champ « Emplacements des projets immobiliers » est la suivante.

query:$site/*[@@name="Data"]//*[@@templatename="POIs"]|query:$sharedSites/*[@@name="Data"]//*[@@templatename="POIs"]

Ajoutez une nouvelle variante de résultat de recherche dans /sitecore/content/{tenant}/{site}/Presentation/Rendering Variants/Search Results et nommez-la Builders. Ajoutez un scriban sur la variante Builder et mettez à jour le champ du modèle avec le code ci-dessous.

<b>{{i_item.Title}}</b>

<div class="d-flex flex-wrap w-25 m-2" >  
{{ for i_location in (sc_followlocations i_item "Real Estate Projects Locations") }}
<br/>    
    {{o_geospatial = st_geospatial i_location 'Kilometers'}}
    {{ if o_geospatial }}
        <div class="m-1">
            <p> {{i_location.name}}, 
                Distance: {{ o_geospatial.distance | math.round 1 }} {{ o_geospatial.unit }}
            </p>
        </div>
    {{end}}
{{ end }}
</div>

Ajoutez une nouvelle portée à /sitecore/content/{tenant}/{site}/Settings/Scopes et nommez-la « Builders Projects » et mettez à jour le champ de requête Scope avec la valeur ci-dessous. Remplacez l’ID par l’ID de votre modèle de groupe Builder ou l’ID du modèle d’élément non POI.

template:{0a2d3ea5-83c6-47f0-8f52-b44a6d5eaee4}

Créez plusieurs éléments POI sous /sitecore/content/{tenant}/{site}/Data/POIs.

Créez un élément de page sous l’élément d’accueil de votre site de locataire SXA et nommez-le « Liste des projets du groupe de constructeurs ».
Sous cet élément de page, créez plusieurs éléments à partir du modèle « Builder Group ». Définissez les éléments POI dans le champ « Emplacements des projets immobiliers ».

Ouvrez l’élément « Liste des projets du groupe de constructeurs » dans l’éditeur d’expérience. Ajoutez le rendu « Filtre d’emplacement personnalisé » et fournissez la source de données.

Ajouter le localisateur d'emplacement personnalisé

Ajouter le localisateur d’emplacement personnalisé

Modifiez les propriétés du composant comme ci-dessous.

Propriétés du localisateur

Propriétés du localisateur

Définissez la facette Distance dans la source de données du filtre d’emplacement personnalisé.

Location Finder Datasource Set The Distance Facet

Source de données Location Finder – Définir la facette de distance

Ajoutez le rendu des résultats de recherche et définissez la variante « Constructeurs ». Définissez les « Projets de constructeurs » dans le champ Étendue de la recherche. Enregistrez la page.

Remplissez le schéma géré Solr à partir du panneau de configuration de Sitecore. Après cela, veuillez vérifier l’entrée ci-dessous dans votre fichier de schéma géré d’index SOLR (SOLR_FolderPath\server\solr{index_core_name}\conf\managed-schema). S’il n’est pas trouvé, vérifiez les journaux Sitecore ou le journal des événements Windows pour plus de détails.

<field name="multiplecoordinates" type="location" multiValued="true" indexed="false" stored="false"/>

Reconstruisez l’index de recherche (sitecore_sxa_master_index et sitecore_sxa_web_index) à partir du panneau de configuration Sitecore.

Démo rapide

Démo rapide - Trier les éléments du groupe de constructeurs en fonction des emplacements multiples mappés

Démo rapide – Trier les éléments du groupe de constructeurs en fonction des emplacements multiples mappés

Noter:

Initialement, lorsque la page est chargée, elle demande l’emplacement de l’utilisateur tout en affichant uniquement la liste du groupe de constructeurs et n’affiche pas encore les emplacements. C’est parce que o_geospatial est nul dans le code scriban. Ainsi, lorsque l’emplacement de l’utilisateur ou l’utilisateur saisit l’emplacement dans le localisateur, la clé de hachage « cg » contient les coordonnées de l’emplacement, puis o_geospatial est initialisé par la fonction scriban personnalisée st_geospatial dans notre implémentation. o_geospatial est ensuite utilisé pour obtenir la distance. Vous pouvez personnaliser davantage le code scriban pour afficher les emplacements sans la distance lors du chargement initial de la page.

Vous pouvez gérer la relation entre l’élément non POI et l’élément POI en fonction de vos besoins. Par exemple, vous pouvez avoir l’élément de détail du projet séparément et un élément du groupe de constructeurs peut faire référence à cet élément de détail du projet au lieu de l’élément POI. Chaque élément de détail du projet peut avoir un champ Emplacement pour référencer l’élément POI et peut avoir plus de champs pour gérer les informations de détails du projet. Mais modifiez également le code de la variante de résultat de recherche et les coordonnées multiples du champ calculé en conséquence.

Un merci spécial à l’un de mes formidables collègues – Jitesh Tambekar pour avoir jumelé le domaine d’investigation clé de ce défi.

Bon apprentissage Sitecore et SOLR 🙂






Source link

septembre 19, 2022