URLs with Redundant Facets Generated

This topic applies to the Elbrus release of SuiteCommerce Advanced (SCA).

When searching for an item using facets, the application can create a URL containing redundant facets. This error occurs because new facets are appended to the existing URL with a forward slash (/). As a result, the appended URL is relative rather than absolute. For example, the following filter can appear for a web site:

          http://<baseUrl>/Girls/Mens/Girls/Mens 

        

This patch extends the getUrl() method in Facets.Translator.js for the Facets module. The code changes ensure that each URL is prepended with a forward slash (if it does not already have one), making it an absolute URL.

To implement this patch, you must extend the prototype object for the getURL() method. You can download the code samples described in this procedure here: RandomFacetsGenerated.zip.

Note:

Before proceeding, familiarize yourself with Best Practices for Customizing SCA.

Step 1: Extend the Facets.Translator.js File

  1. To extend the Facets.Translator.js file, located in the Facets module, open the Modules/extensions directory and create a subdirectory to maintain your customizations.

    Give this directory a name similar to the module being customized. For example, create Modules/extensions/FacetsExtension@1.0.0

  2. In your new FacetsExtension@1.0.0 directory, create a subdirectory called JavaScript.

    For example: Modules/extensions/FacetsExtension@1.0.0/JavaScript

  3. In your new JavaScript subdirectory, create a JavaScript file to extend Facets.Translator.js.

    Name this file according to best practices. For example:

    Facets.Translator.Extension.js

  4. Open this file and extend the getUrl() method as shown in the following code snippet.

                    define('Facets.Translator.Extension'
     ,   [   'Facets.Translator'
        ,   'underscore'
       ,   'jQuery'
       ,   'SC.Configuration'
       ,   'UrlHelper'
       ]
       ,   function (
          FacetsTranslator
       ,   _
       ,   jQuery
       ,   Configuration
       )
    {
       'use strict';
    
       _.extend(FacetsTranslator.prototype,
          {
             // @method getUrl
             // Gets the url for current state of the object
             getUrl: function getUrl ()
             {
                var url = this.categoryUrl || ''
                ,   self = this;
    
                // Prepares seo limits
                var facets_seo_limits = {};
    
                if (SC.ENVIRONMENT.jsEnvironment === 'server')
                {
                   facets_seo_limits = {
                      numberOfFacetsGroups: this.configuration.facetsSeoLimits && this.configuration.facetsSeoLimits.numberOfFacetsGroups || false
                   ,   numberOfFacetsValues: this.configuration.facetsSeoLimits && this.configuration.facetsSeoLimits.numberOfFacetsValues || false
                   ,   options: this.configuration.facetsSeoLimits && this.configuration.facetsSeoLimits.options || false
                   };
                }
    
                // If there are too many facets selected
                if (facets_seo_limits.numberOfFacetsGroups && this.facets.length > facets_seo_limits.numberOfFacetsGroups)
                {
                   return '#';
                }
    
                // Encodes the other Facets
                var sorted_facets = _.sortBy(this.facets, 'url')
                ,   facets_as_options = [];
    
                for (var i = 0; i < sorted_facets.length; i++)
                {
                   var facet = sorted_facets[i];
    
                   // Category should be already added
                   if ((facet.id === 'commercecategoryname') || (facet.id === 'category'))
                   {
                      break;
                   }
    
                   var name = facet.url || facet.id
                   ,   value = '';
    
                   switch (facet.config.behavior)
                   {
                      case 'range':
                         facet.value = (typeof facet.value === 'object') ? facet.value : {from: 0, to: facet.value};
                         value = facet.value.from + self.configuration.facetDelimiters.betweenRangeFacetsValues + facet.value.to;
                         break;
                      case 'multi':
                         value = facet.value.sort().join(self.configuration.facetDelimiters.betweenDifferentFacetsValues);
    
                         if (facets_seo_limits.numberOfFacetsValues && facet.value.length > facets_seo_limits.numberOfFacetsValues)
                         {
                            return '#';
                         }
    
                         break;
                      default:
                         value = facet.value;
                   }
    
                   if (self.facetIsParameter(name))
                   {
                      facets_as_options.push({ facetName: name, facetValue: value });
                   }
                   else
                   {
                      // Do not add a facet separator at the begining of an url
                      if (url !== '')
                      {
                         url += self.configuration.facetDelimiters.betweenDifferentFacets;
                      }
    
                      url += name + self.configuration.facetDelimiters.betweenFacetNameAndValue + value;
                   }
                }
    
                url = (url !== '') ? url : '/' + this.configuration.fallbackUrl;
    
                // Encodes the Options
                var tmp_options = {}
                ,   separator = this.configuration.facetDelimiters.betweenOptionNameAndValue;
    
                if (this.options.order && this.options.order !== this.configuration.defaultOrder)
                {
                   tmp_options.order = 'order' + separator + this.options.order;
                }
    
                if (this.options.page && parseInt(this.options.page, 10) !== 1)
                {
                   tmp_options.page = 'page' + separator + encodeURIComponent(this.options.page);
                }
    
                if (this.options.show && parseInt(this.options.show, 10) !== this.configuration.defaultShow)
                {
                   tmp_options.show = 'show' + separator + encodeURIComponent(this.options.show);
                }
    
                if (this.options.display && this.options.display !== this.configuration.defaultDisplay)
                {
                   tmp_options.display = 'display' + separator + encodeURIComponent(this.options.display);
                }
    
                if (this.options.keywords && this.options.keywords !== this.configuration.defaultKeywords)
                {
                   tmp_options.keywords = 'keywords' + separator + encodeURIComponent(this.options.keywords);
                }
    
                for (i = 0; i < facets_as_options.length; i ++)
                {
                   var facet_option_obj = facets_as_options[i];
    
                   tmp_options[facet_option_obj.facetName] = facet_option_obj.facetName + separator + encodeURIComponent(facet_option_obj.facetValue);
                }
    
                var tmp_options_keys = _.keys(tmp_options)
                ,   tmp_options_vals = _.values(tmp_options);
    
                // If there are options that should not be indexed also return #
                if (facets_seo_limits.options && _.difference(tmp_options_keys, facets_seo_limits.options).length)
                {
                   return '#';
                }
    
                url += (tmp_options_vals.length) ? this.configuration.facetDelimiters.betweenFacetsAndOptions + tmp_options_vals.join(this.configuration.facetDelimiters.betweenDifferentOptions) : '';
    
                if (url && url[0] !== this.configuration.facetDelimiters.betweenDifferentFacets)
                {
                    url = this.configuration.facetDelimiters.betweenDifferentFacets + url;
                }
                return _(url).fixUrl();
             }
       });
    }); 
    
                  
  5. Save the file.

Step 2: Prepare the Developer Tools For Your Customization

  1. To make sure that the Gulp tasks include your modules when you deploy, set up the ns.package.json file for your custom module and modify distro.json.

    Open your new FacetsExtension@1.0.0 module.

  2. Create a file in this directory and name it ns.package.json:

    Modules/extensions/FacetsExtension@1.0.0/ns.package.json

  3. Build the ns.package.json file using the following code:

                    {
        "gulp": {
            "javascript": [
                "JavaScript/*.js"
            ]
        }
    } 
    
                  
  4. In distro.json, add your custom modules to the modules object.

    Your code should look similar to the following example:

                    {
        "name": "SuiteCommerce Advanced Elbrus",
        "version": "2.0",
        "buildToolsVersion": "1.3.0",
        "folders": {
            "modules": "Modules",
            "suitecommerceModules": "Modules/suitecommerce",
            "extensionsModules": "Modules/extensions",
            "thirdPartyModules": "Modules/third_parties",
            "distribution": "LocalDistribution",
            "deploy": "DeployDistribution"
        },
        "modules": {
            "extensions/FacetsExtension": "1.0.0",
            "extensions/MyExampleCartExtension1": "1.0.0",
                 //... 
    
                  

    This ensures that the Gulp tasks include your module when you deploy. In this example, the custom modules are added at the beginning of the list of modules. However, you can add the modules anywhere in the modules object. The order of precedence in this list does not matter.

  5. Add Facets.Translator.Extension as a dependency to SCA entry point within the SC.Shopping.Starter entrypoint of the JavaScript array.

    Your Distro.js file should look similar to the following:

                    "tasksConfig": {
    //...
    "javascript": [
             //...
             {
                   "entryPoint": "SC.Shopping.Starter",
                   "exportFile": "shopping.js",
                   "dependencies": [
                      //...
                         "Newsletter",
                         "ProductDetailToQuote",
                         "StoreLocator",
                         "Facets.Translator.Extension"
                   ],
                               //... 
    
                  

Step 3: Test and Deploy Your Customization

  1. Test your source code customizations on a local server (see Test SCA Customizations on a Local Server) or deploy them to your NetSuite account (see Deploy SCA Customizations to NetSuite). If you are currently running SCA on a local server, your changes should appear on your local site immediately.

  2. Confirm your results.

    Upon successful deployment, filters to the products do not contain redundancies.

Related Topics

SCA Patches

General Notices