Gravatar for david.masters1984@gmail.com

Question by David Masters, Feb 1, 2017 4:38 AM

No JavaScipt query

We are planning on using the standard Coveo UI components are product listing pages, however we have a requirement to provide a no JS fallback.

So what I'm looking to do is render the results server side, but still using the criteria defined against the existing Coveo sublayout component.

Is that possible?

We are using the latest version of Coveo cloud for Sitecore 8.2.

Thanks

2 Replies
Gravatar for jflheureux@coveo.com

Answer by Jean-François L'Heureux, Feb 3, 2017 7:11 AM

Hi Dave,

Coveo does provide an out of the box sublayout/rendering for SEO friendly, no JavaScript pages. It is called the Coveo Search Web Crawler component. It can use the same rendering parameters as the standard Coveo Search component. It will take the filtering and boosting rules and any other parameters, run the query with LINQ and output the results very basically in an HTML table.

The article I linked contains everything to get started with this component. You will have to create a Sitecore device to identify web crawlers. You will probably also have to duplicate the file and make your own version that outputs results similar to your JavaScript search page version.

If you want to re-define the settings of your full search page in the web crawler version, I recommend you to create an item in your content tree based on the "Coveo Search Parameters" template. Configure this datasource item once with the filters/boosting and parameters you want for both pages. Then, set the "Data source" field to that item in both the Coveo Search and Coveo Search Web Crawler component properties. They will then share the same settings. You might have to remove the individual settings of your Coveo Search component in order to use the datasource ones.

I hope this helps,

Jeff

Gravatar for david.masters1984@gmail.com

Comment by David Masters, Feb 3, 2017 8:10 AM

Hi Jeff,

That is a huge help and a bit of a relief!

I had a feeling that Coveo must have a solution to cover this scenario :)

Thanks very much. Dave.

Gravatar for flguillemette@coveo.com

Answer by François Lachance-Guillemette, Feb 1, 2017 7:45 AM

Hi @dave_masters!

Coveo for Sitecore have LINQ expressions that can be executed server-side. There are many extensions you can use and [the documentation][1] have very helpful links to help you. :)

However, it comes with many caveats. Using LINQ implies that when not using the JavaScript framework, you removed those features:

  • Analytics logging
    • These users will not show up in reports
  • [Coveo Machine Learning][2]-powered enhancements (machine learning)
  • Automatic Relevance Tuning
  • Query Suggestions
  • Recommendations based on the users visits

Also, it is way harder to implement since you need to code every "dynamic" components, like facets or tabs, server-side. Which all comes OOTB with the `coveo-ui-search` framework

If the requirement to have no JS is ready to accept those conditions, then you can follow parts of [this tutorial][3] that will help you build a search page using LINQ.

Hope this helps!

FLG

[1]: https://developers.coveo.com/display/SitecoreV4/Using+LINQ+to+Customize+Queries

[2]: https://onlinehelp.coveo.com/en/cloud/coveo_machine_learning.htm

[3]: https://developers.coveo.com/display/SitecoreV4/LINQ+QueryResults+Example+-+Introduction

Gravatar for david.masters1984@gmail.com

Comment by David Masters, Feb 1, 2017 10:39 AM

Hi,

Thanks for the swift response!

The page is just listing page so there won't be any controls on the page & we plan to hide facets so it is just results only.

I am aware there is a LINQ provider, but I guess my real questions is this: If I have a search page setup as normal with criteria defined as Sitecore rules on the Sitecore search component, can I create a sublayout or maybe extend the coveo one so that it takes this criteria and executes it with the LINQ provider?

Does that make sense?

Gravatar for flguillemette@coveo.com

Comment by François Lachance-Guillemette, Feb 1, 2017 1:43 PM

This is a very good use case, but I'm afraid we don't provide anything of the sort easily.

I suppose you could either extend or create an instance of the SearchModel class, located in the Coveo.UI.Mvc.Models namespace, in Coveo.UIBase assembly. This is where is computed the FilterExpression. generated from the rules that is then used client-side.

However, it won't contain all the information since some of the query is computed client-side in JavaScript. All the external sources/collections tricks are there and filters on the current language. If you are not using those features, you should be good to go, else you need to do that same work in your LINQ query.

Gravatar for david.masters1984@gmail.com

Comment by David Masters, Feb 2, 2017 5:35 AM

Thanks again.

I have created my own copy of the CoveoSearch.ascx which inherits from the original. When debugging I can see the SearchModel has the FilterExpresion property with the coveo expression as string. Do you know how/if I can execute this expression from the server side (I realise this isn't the entire query expression), but basically I think I just need to replicate what the JS is calling, but without making a http request to internal rest service. i.e. is there a service I can reference that takes the coveo expression and returns the results? I'm thinking this might be easier than iterating over the FilterRules collection and building up a linq query?

As a side note, this requirement has come from our in-house SEO team, who are basically saying that if the (product) listing pages are JS only then Google won't be able to crawl them. Do you have a take on that? It strikes me as quite a big flaw of Coveo for listing pages if that's the case?

Thanks.

Gravatar for flguillemette@coveo.com

Comment by François Lachance-Guillemette, Feb 2, 2017 8:34 AM

The class we use internally to parse the rules is in the Coveo.UI.Helpers.RulesHelper class, in the Coveo.UIBase assembly.

You could create this class and call ParseRules. This will return an Enumerable corresponding to the rules ready to be serialized.

The serialization is done with the Coveo.UI.Expressions.FilterExpressionBuilder, created using Coveo.UI.Expressions.ExpressionBuilderFactory.CreateFilterExpressionBuilder. Its methods can be used to add the rules and then build the final expression.

I have managed to do it using this procedure with the following code, feel free to adapt it to your needs:

    using Coveo.Framework.Databases;
    using Coveo.UI.Helpers;
    using Coveo.UI.Expressions;
    using Coveo.UI.Extensions;
    using Coveo.UI.Rules;
    using Sitecore.ContentSearch;
    using Sitecore.Rules;

    ...

       private string GetExpression() {
            IRulesHelper rulesHelper = new RulesHelper();
            IFilterExpressionBuilder builder = GetBuilder(rulesHelper);
            builder.AddFilterRules(GetRules(rulesHelper));
            return builder.BuildExpression();
        }

        private IFilterExpressionBuilder GetBuilder(IRulesHelper rulesHelper) {
            IProviderSearchContext searchContext = GetSearchContext();
            return new ExpressionBuilderFactory().CreateFilterExpressionBuilder(searchContext, rulesHelper);
        }

        private IProviderSearchContext GetSearchContext() {
            // Fetch the current Coveo index here. Name is case-sensitive.
            // Can also be an IIndexable.
            string currentCoveoIndex = "Coveo_master_index"; 
            ISearchIndex index = new SitecoreHelper().GetSearchIndex(currentCoveoIndex);
            return index.CreateSearchContext();
        }

        private IEnumerable<CoveoRule<RuleContext>> GetRules(IRulesHelper rulesHelper) {
            string currentDatabaseName = "master"; // Fetch the database name here.
            string filterExpression = ""; // Read the parameter here
            IDatabaseWrapper database = new SitecoreFactoryWrapper().GetDatabase(currentDatabaseName);
            return rulesHelper.ParseRules(database, filterExpression);
        }

The result of GetExpression is ((@fz95xpath5059=="0DE95AE441AB4D019EB067441B7C2450") (@fhaslayout5059=="1")), and I think this is what you need.

Ask a question