Friday, July 28, 2017

Glass Surprise - Get Your Ancestors like a champ

Glass just makes me so happy!  I do not have to write same 10-15 lines of code every time to do something very mundane when it comes to Sitecore.  Every other feature on sitecore demands some kind of relationship driven items to be accessible from context page on which your module would do some magic on.
Typically, developers tend to write their own custom code to do such things which would lead to bad performance when not done right.  Why not just go with Glass if you are using it in your instance development? It is far more easier.  I had done a similar blog post to grab children from Glass, but, this time around it is Ancestors.  Though similar, it could help some one who did not think or know that it could be used on both the relation ships on the tree, upwards or downwards.

Steps to do this is quite simple and three step process

  1.  Declare a custom partial class that extends your auto generated class based on say a template.  For example like below.  I like to keep these guys organized, usually do it in special Model project and namespace related to it, to keep things easy and manageable, so some one can easily know if the model has been extended. 
  2. Next up, add a Attribute that comes with Glass such as below, pass your template ID.  I actually tried getting this ID from a config setting which would have been great for maintenance, see if you can do that based on your project settings 
  3. Access the new ancestor strongly typed( A bonus, so you dont need to cast and make a messy view, the view simply get's what it needs and you access and ensure your checks are in place)

Sample Code Of Custom Partial Class 


namespace YourProject.Models
{
    public partial class Your_Template_Auto_Generated_Class
    {

        [SitecoreQuery("./ancestor-or-self::*[@@templateid='{7E6BC980-362C-4BBB-97E5-9DAA83B70812}']", IsRelative = true)]        
        public virtual Your_Strongly_Typed_class myAncerstorItem { get; set; }
    }
}


Voila! Goal accomplished and the best part clean code, clean views and happy MVC. 

Have a great weekend ahead!!!

Tuesday, July 25, 2017

Custom Sorting on Coveo Facet

I got to use a new feature of Coveo today because of new requirements.  How fun, though the request that came through felt not needed and a corner case in terms of user experience.  Pushing through limit is what we have to do if you have got super picky clients. :)
The outcome is always precious as you get to learn something new.   Here is the snapshot of what happened and how we were able to get it working per request and requirement.

Goal - Regardless of selections made on Coveo Facet because of url appending, the sort order of values available on facet stay per the field on which sort is based on.

Problem - The inherent default behavior of Coveo for better UX experience.  To be honest, I actually like what they have in terms of grouping the values selected to the top and rest are sorted based on the sort field set up.  But, we have to some how overwrite this default behavior.

Firstly, our front end contact explored why this happens and how coveo groups them the way it does inherently.  The reason for special attention that these selected values get is because of the below. Thanks to our front end resource to find this out.  Though we did not pursue anything in modifying this, it is always good to know the reasons behind how it is currently done.

https://developers.coveo.com/display/public/SearchREST/Group+By+Results






So, the reason is that when there is an appending in URL for a selection of a value or set of values in the facet, Coveo inherently tags these as Desired and hence the special treatment for those to be on the top.

For example, if your URL is like below may be because the user clicked on back button post user selected few values and moved on his journey, the user could land on pages like this or if marketing team linked off the user to a page with pre-selected values on a facet.  There could be more scenarios where your user would bump in to this situation, but to name a few.

Example URL - https://www.domain.com/press-releases-events-and-webcasts-landing#f:articlePostYear=[2017,2018]

The selected would be grouped on top like below due to the above explained reason.


 Again, I like what Coveo does inherently and I suspect that this needs to overridden in simple cases, but, if you absolutely need to do this? Which is where we stood, I logged a Q and A below and luckily got a direction.  I only wish there were more graceful options, but, we took what we got as well, we had to overwrite this and there was no other option unfortunately.

If you are curious, follow the discussion here and I will explain more in detail how I actually implemented what was recommended by Coveo team.

https://answers.coveo.com/questions/12071/facet-values-mentionedgrabbed-in-allowed-values-be.html?childToView=12086#answer-12086

Steps I did to Implement this solution:


  1. Created a copy of default Coveo MVC view for facet and named it differently and placed under correct project specific location. 
  2. Add the below line to the view created just above end of div tag in place for the facet
    data-custom-sort="2024,2023,2022,2021,2020,2019,2018,2017,2016,2015,2014">
  3. Note - With addition of this, we should be good on sorting with lower limit of 2014 to upper limit of 2014, based on your project data you could decide on good numbers for these limits. Only deal is post 2024, if this project has same implementation, we will need a code deploy to ensure sort works as expected. 
  4. Use this new view item on presentation for the facet and select all appropriate values that a coveo facet would need on the templates affected or will use such type of facet  
  5. That is it!! Post this change regardless if values are selected via url or not, the ordering will be based on data-custom-sort 






Sunday, July 9, 2017

Sitecore Launch Hiccups and Resolution

I know it has been a while, Vacationing and launch has been no joke on my side. :)
It has surely taken a toll and kept me away from blogging for quite a few days.  Finally, today I got some time to jot down the experiences of my launch after a pause.

Time Taken: 14 hrs straight starting 5.00 PM to Mid night around 2.00 AM PST, it was a grueling long night and I was supporting the go-live from India, how fun!

Sadly, I did not expect any issues or what so ever because we had code already up and running on the actual servers with all the things working and QA/UAT pass.  The only thing that was changing was DNS and binding being different, rest everything was absolutely same.  Well, everything does not happen as planned especially on the launch day.   I was supporting using a fairly fast internet for Indian standards, but, still fell a little short as I was used to things being done fast.

Below are few hiccups and how we resolved each of these, hope it helps some one who is stuck in a similar situation.


  1. xDB Cloud working excellent on sandbox license, but, lot of issues when swapped to prod license.    While launching the site, we obviously have to swap the connection strings to use production xDB license provided by sitecore.  We did so, but, as a surprise we encountered bunch of errors on logs and had to re-visit all the related configs to ensure we did everything as expected.  Sitecore did not mention in support ticket that extra steps would be needed on live license which are additional as compared to non-prod xDB license.  We followed the below blog and added host file entry as mentioned and left hostname empty on configuration. https://sitecorehacker.com/2017/02/12/sitecore-analytics-tracker-common-issues-and-how-to-resolve-them/
  2. IIS security hardening done prior to enabling anonymous access to the site.  It is kind of common practice that when we have a pre-prod or staging site behind some kind of authentication to ensure site is not publicly available since it is meant to be.  As part of deployment strategy, we had steps listed and unfortunately they were ordered incorrectly.  Since, enabling anonymous on parent site would trigger that change to all children and folders within the site, the hardening we had done per sitecore recommendations on CD servers was lost and we had to re-do the steps.  These things add time post launch especially on VPN, connected to remote servers from INDIA. lol
  3. Coveo cache - Still unsure what was causing Coveo to access a URL that is no longer configured on either Server URL or for that matter any where else.  While rebuilding master index, it kept failing saying that could not reach to a binding which is no longer available.  I am assuming it is some kind of cache, unsure where or what at this time.  I ensured there was no trace of old/outdated URL any where by going to /showconfig.aspx and also reviewing coveo configuration files.  Still a mystery to solve, but fortunately the error did not mean indexes were not built, so, we were safe to move forward and were successfully able to rebuild other web and liveweb indexes with out errors. 
  4. Cache - It is a boon and blessing.  We had set up cache on all renderings applicable.  But, there was a slight miss.  Parent placeholders that carried WFFM should not be allowed to cache, but, there were few misses which were uncovered only on regression testing that few forms were not working, once we removed cacheable setting on these renderings forms started working like a charm. 
  5. Errors on Log files -  It is important to monitor log files to check for any major errors on the logs that clutter the server and could have slow response times.  We un-covered a few and still in progress on identifying all the outstanding issues. 
  6. Redirects -  On our lower environments we had few different settings like www was being forced as it was not needed which was enabled post launch as a requirement.  This started throwing off the logic and plan around redirects.  We had to revamp the redirects loaded to ensure they are working alright and corrected few instances.  Especially when migrating or unifying multiple sites this could pose a challenge.  How I wish we had exact same settings and tested the logic against that to reduce this back and forth. 
At the end, all was well.  I am glad we stretched it instead of calling it off, it is a worst feeling to do a rollback.  Launch would mean a great move in the forward direction, never would want to associate it with a failure.  I am glad the site went live and has been appreciated both internally and public facing. 

Looking forward to more adventures in the future.   

Happy Weekend every one!


Friday, June 9, 2017

A different paradigm to bump up your site performance

You might have seen ample number of blogs, information and other resources out there that talk about the same topic.  But, I will try and make this in steps, so you have step-by-step guide all in here and you will surely spend less time scraping this data from 10 other places.
At the end, I will also list references on where I gathered all this from, so, you can refer and read more if you are an enthusiastic reader.

Have you heard about Google page speed extension?  If you did not, it is fine and I will not say you were living in a cave, in this functional desire world, I wonder why performance is always addressed at the very end of the tunnel in software life cycle.  I would go ahead and say a simple performance test plan should be part of every step of implementation.   It could be simple, but invasive.  It would help mitigate surprises which usually take time to resolve.

There are tons of tools out there as well to measure performance, but, I got hooked on to Google page speeds extension as it is easy to visualize and Google does do a good job of providing links to problems that were uncovered which would provide good insight to multiple solutions to the problem on hand.

Let us get this started -

1. First do not expect anything,  don't assume that your site is great or worst in terms of performance.  Just download the extension of your favorite choice, I like the Google Page Speeds extension, but, you could run anything
2. Address to one's Google put's more weight on and are in red.  I think that would be the critical one's for sure.  I did the following and saw immediate boost on numbers

Images and Images (Scaling and Optimization)

Firstly ensure you are scaling images on server side (Using Glass params) instead of depending on content authors to upload files of certain dimensions.  Though we tried to enforce this through documentation and collaboration, we still saw lapse.
Best way to battle this is use Glass params, then, regardless of whether recommended size is respected or not, your browser will not spend ton of time sizing and re-sizing images to fit your FEE needs(css)
Get the params based on FEE recommendations, the best thing to do is set width and let height be auto.
Example :@RenderImage(carouselSlide, m => m.Carousel_Image, new { @class = "carousel__image", w = 684, width = 684 }, true, outputHeightWidth: true)
Please re-upload all imagery that is not respecting the dimensions.  This is important for performance and critical 
Also, ensure good/web optimized imagery is loaded on to media library.  If tool complains that some images could do better in terms of performance, please re-upload the culprits.  Should be quick and the tool offers a download option on each of the offensive currently uploaded image.  Go to sitecore editor and do simple attach/detach.  You are done. 
Make sure all your site specific css/js is minified and only those minified versions are accessed in your HTML or view code


Ensure web server has compression enabled.  This is a simple check of a checkbox available on IIS under compression for a specific site(Ensure static compression is checked).  Sometimes, if installation is not done correctly even if you checkbox this it might not work.  Please ensure this works by looking at Network request and content-encoding attribute is being set as 'gzip'.  You can check in fiddler or on Google chrome by toggling the column display to show this response header.  If you dont see gzip, please check with support once you ensure you have enabled the IIS settings properly and things seem off.  This is v important for performance and must be ensured is working 
Enable cache control on static resources on web.config to ensure you enable this after talking to your FEE team on what would be a good max age time.  It could vary based on multiple things and should be verified with your team.


After these steps, please follow sitecore performance tuning guide no less than Bible(link in references), go over all content delivery preferences and ensure you set all of them correctly.  When in question about something please check with your support team.

That is it, you just made your sitecore instance super efficient.  The tuning guide should also cover caching best practices which should bump up good performance benefit second load on wards.

Happy Sitecoring!!

Few Good References

https://developers.google.com/speed/pagespeed/insights/
https://sdn.sitecore.net/upload/sitecore7/70/cms_tuning_guide_sc70-72-usletter.pdf
https://chrome.google.com/webstore/detail/google-pagespeed-insights/edbkhhpodjkbgenodomhfoldapghpddk?hl=en
https://developers.google.com/speed/docs/insights/EnableCompression




Friday, June 2, 2017

Deeper dive in to Coveo Advanced Expressions

In our implementation we stumbled upon looking at what Coveo calls 'aq' bunch of times.  It is simply because of complexity involved on our implementation where we had to bend Coveo a little to achieve what the business needs are.

First up, let us first understand a little what is aq, dq and cq per Coveo.  They have beautiful documentation that iterates what these are.
https://developers.coveo.com/display/public/SearchREST/Query+Parameters

So, every time a query is fired by Coveo rendering because of coveo components you have on the page.   All these query parameters based on what is applicable is generated by Coveo, you can see this on Network tab in your browser when you take a look at Request headers and parameters.  If what coveo generates satisfies your business goals, you are good to call it a day.  But, what if it is not enough, you have to then modify and tweak to achieve what is needed.

When it comes to modifying the aq generated gracefully it becomes a challenge specifically if you are having issues with what Coveo does inherently while computing 'aq' for a rendering/request
One such case happened recently, where we needed a disjunction to be applied at a specific piece of generated 'aq'.  We obviously could not get away with disjunctive expressions, I talked about this in my previous blog if you are curious.

https://deepthikatta.blogspot.com/2016/11/coveo-facet-slider-across-two-fields.html


The reason why this approach would not work in this case is because the way disjunctive expression works and is interpreted by Coveo in final query is aq OR dq which means in result set you will find all items that match your filters appended by Coveo in aq OR that match your expression that you added on dq.

But, what if you want this disjunction to applied only on a particular facet or custom advanced expression.  How can we do this? is it possible?

Like always, everything is possible. :)  In our case, it is little more complex because we also did not want what Coveo typically injects as a piece of aq on a Facet Slider for example because we would fall in to same problem which we began to solve if we don't do this.   So, to achieve this, we did two steps.

1.  OR where you need - In event called buildingQuery, access the args and append the advanced expression that you need including a specific OR condition you care about.  Some thing like
 Coveo.$('#@Model.Id')
        .on("buildingQuery", function(e, args) {
            let mySlider = Coveo.$('#mySlider')
              if (mySlider != undefined) {
              let optionsOfComponent = mySlider.coveo().getSliderBoundaryForQuery()
               if (optionsOfComponent != undefined && optionsOfComponent[0] != undefined && optionsOfComponent[1] != undefined) {
                let fieldOneQuery= '@(Model.ToCoveoFieldName("field one")) >=' + optionsOfComponent[0] + ' AND @(Model.ToCoveoFieldName("field one")) <=' + optionsOfComponent[1]
                let fieldtwoQuery= '@(Model.ToCoveoFieldName("field two")) >=' + optionsOfComponent[0] + ' AND @(Model.ToCoveoFieldName("field two")) <=' + optionsOfComponent[1]
                args.queryBuilder.advancedExpression.add('((' + fieldOneQuery+ ') OR (' + fieldtwoQuery+ '))')
              }
      }

         })
2. Remove the advanced expression added by Coveo -  Reverse engineered the string that Coveo would append on the facet slider per configuration and removed it using helper provided under Expression Builder.
https://developers.coveo.com/display/public/JsSearch/ExpressionBuilder

Some thing like -
 .on("doneBuildingQuery", function(e, args)  {
   //reverse engineer the value you would like to remove and ensure you have proper checks on coveo      components or facets before you access the values
    let  expressionToRemove  = '@(Model.ToCoveoFieldName("your slider         field"))=='+optionsOfComponent[0]+'..'+optionsOfComponent[1]
    args.queryBuilder.advancedExpression.remove(expressionToRemove)
   })

That is it, we got what we needed when took a peek at Network tab and request parameters and the results matched to business goal.   One less thing to worry about.  We are launching this thing soon, totally psyched!


Monday, May 22, 2017

Coveo Computed Field based on Sitecore Parent needs additional configuration

In some of our critical pieces of implementation revolving around Coveo renderings, due to our heavy hierarchical data for SEO benefit, we had multiple situations where we were having computed fields that read a piece of data from direct or in-direct parent of the current item in question in sitecore.

It was working out perfectly, no additional load time or performance issue as indexing operation should fully load what we need on the current sitecore item.  Until!!!

Recently, I ran in to this situation where say you have the whole hierarchical data already in play, which just means we did not create a child and did not publish the current item.  But, a scenario where a field that you are reading in computed field from parent actually changed.  In this situation, due to inherent behavior of how indexing would work, the parent would be re-indexed(As that is the item that is changed and hence added to delta by Coveo).  Now, we have child having an outdated computed field which in index memory still has stale data until you force build indexes or publish the child.

In real life scenario, you would take an item through workflow, in this case parent is changed, so it would enter the Sitecore workflow and will be pushed live.  But, in our case, every time a parent changes, we want the children also to re-index, so, we do not have situation of out-of-sync data.

So, additional configuration would be needed every time you have a scenario where a computed field say depends on some other item (like parent in our case or it could be something else in the sitecore tree as well).  To address this and ensure it works as expected in ideal scenario, we need to do below steps

1.  Patch to coveoItemProcessingPipeline and add a new processor - call it say 'RelatedItemsPreProcessor'
2. Implement what happens in the processor, in our case we had to get all children and add it to List of items that Coveo re-indexes when this specific item is in delta.  Quick example below, it could be changed per your needs.  There is a basic example on Coveo documentation as well.

 public class RelatedItemsPreProcessor : IProcessor<CoveoItemProcessingPipelineArgs>
    {
        public void Process(CoveoItemProcessingPipelineArgs p_Args)
        {

            SitecoreIndexableItem indexableItem = p_Args.Item as SitecoreIndexableItem;
            if(indexableItem != null)
            {
                Item item = indexableItem.Item;
             
                if(item.TemplateID.Guid.Equals(yourguidgoeshere))
                {
                    if(item.HasChildren)
                    {
                        //Get all children using query
                        string query = string.Format("descendant - or - self::*[@@templateid = '{0}' ]", YourGUID);
                        var childrenOfItem = item.Axes.SelectItems(query);
                        if(childrenOfItem != null && childrenOfItem.Any())
                        {
                            foreach(var itm in childrenOfItem)
                            {
                                //Add the item to the output list
                                var itemToBeAdded = new SitecoreIndexableItem(itm);
                                if (!p_Args.OutputItems.Contains(itemToBeAdded))
                                    p_Args.OutputItems.Add(new SitecoreIndexableItem(itm));
                            }
                        }
                    }
                }

3.  Add this new processor in your Coveo.SearchProvider.Custom.config
<coveoItemProcessingPipeline>
        <processor type="namespace.RelatedItemsPreProcessor, Extensions" />
      </coveoItemProcessingPipeline>


That is it! Post this simple steps, I can be rest assured that our data integrity would be in place post the workflow is implemented.  It is really easy to miss this in your implementation when most of your users are logging in using admin credentials for example and probably publishing sub-items every time they publish a change.  Keep an eye open for these kind of situations.

Review pipeline's available here  https://developers.coveo.com/display/public/SitecoreV3/Understanding+the+Indexing+and+Search+Pipelines;jsessionid=814B71D25E05C8684E2C029CEC416070

Saturday, May 20, 2017

When you need more than filtered results

Recently, in one of our major Coveo renderings, there was a splurge of new requirements.  Well, no huge surprise there I think.  When powerful people meet in the same room, new ideas do come by, not such a good news to us developers who have scratched their brains and pulled up hours to wrap up the initial implementation.  Although, I believe it is a good venue when time is on your side to learn something new. :)
This is exactly what happened to us, the requirement sounds pretty simple, but took me few hours to find an optimum solution which solves the problem, but, also would not involve too many changes to existing logic in play.
Goal -   Get all the results that match the filters(facets) selected by end user with out the default pagination applied (Coveo has default pagination and only pulls the values entered in Number of results value given on the rendering properties).   After few hours of going over Coveo documentation, I found something though completely not the same as what I was looking for, it kind of sparked the similar wave of implementation.
I almost always start a Q&A either to confirm my thoughts or to see if there are any other ways to accomplish the same.   In this case, what i was going for just felt right and Coveo team member confirmed the same.  You can follow the trail here.

https://answers.coveo.com/questions/10368/do-we-have-allnot-limited-to-resultsperpage-result.html

So, basically to achieve what I was looking for, you need to fire a parallel query with exact same filters based on user interaction and simply change the results to an upper bound.  It would have been nice to actually set it to Totalresults, I have not tried that, but, could work when you get the value from the correct variable.

Here is a snippet -

Coveo.$('#<%= Model.Id %>').on(Coveo.QueryEvents.querySuccess,function(e, args){
  var query = args.query;
   query.numberOfResults = 2;
//Do any other modifications on the query
Coveo.SearchEndpoint.endpoints["default"].search(query).done(function(data) {
//do any other logic on the data up here
}
 });
});

That is it, we have everything we need plus a handler over all results.  I am pretty sure it would come up often hopefully it helps any one else.

Happy problem solving folks. :)



Sunday, April 30, 2017

Coveo Sorting Part 3

Hey There!

This time soon enough, I really wanted to complete my thoughts on Coveo sorting.  We so far learnt two main things from the previous posts.  How to accomplish Coveo Sorting on a typical custom coveo rendering on a sortable field and how to make sorting work when you have Coveo Tabs that list the results out.

Next step, we will learn how we can achieve the same on Java script, there are few situations where this would come in handy.  In my example, what I was trying to do is apply Coveo Sorting on a computed field.  We are all aware that a computed field is in memory and hence we do not have a GUID we could use to work around the active issue which was present on adding default sort order to Custom Coveo rendering.  With out GUID, the sorting will not work on the rendering due to the issue, this would not be a problem if you are using latest version of Coveo, but, in our case we had no option, but, to battle this challenge.

A option that you could achieve sorting via javascript was the key to successfully getting the sort to work on a sortable computed field.

Below are few resources that helped me get started.

https://answers.coveo.com/questions/1658/how-can-i-set-the-default-sort-order-using-the-jav.html

Below is the code snippet that I plugged in my Custom Coveo View which needed the default sort order to be set


Do note that you have to set this in function, so, the properties get set properly and applied on XHR request.  Mission accomplished.

Now, I covered all the ways that we applied Coveo sorting on different style components.  Another cool thing I noticed if it helps some one is that even if your field is of type Date, do not use that option for Default Sort Order.  Just use Field as your type and all is working as expected.

Happy Problem Solving people.   Enjoy your rest of the weekend!  I am actually blogging from SF airport after hogging on organic veggie quesadilla.   ;)




Saturday, April 29, 2017

Coveo Sorting Part 2

Hi There!

Welcome back again to my three part series of sorting with Coveo.
This time, we look more deeper in to how to make your tabs have a sorted list, below are few easy steps you will need to do make sorting work on Coveo tabs.


  1. Ensure you have a Sort Component added to your presentation.  If you do not do this step, the Default sort order you would enter on Coveo Tab Component would not work and could also lead to exceptions on console.   Read more details about Coveo Sort Component here if curious https://developers.coveo.com/display/public/JsSearch/Sort+Component;jsessionid=6D194F8CCE1AC89DDB1B92C50E446CFF
  2. See screenshot below to see how a Coveo Custom Sort View would look like. 
  3. Ensure you plug in the same Default Sort Properties you have defined on your Coveo Custom Tab, which means you should match Sort Order, Field and Order exactly to same values on both your components for the sort to work fine.  
 Shown below is the view of Custom Sort View that goes hand in hand with Coveo Tab 



Shown below is the Sort Order Default defition on Coveo Sort View 

Shown below is the Default Sort order properties on Coveo Custom  Tab view.  Notice how they are exactly the same, except that on the below we have to use GUID to overcome an existing bug on version of Coveo we are using. 


That is it, after this steps, publish your changes and go to the page where you have coveo renderings with tabs, you will now see two things.  One, your sort options will be appended to the URL by default and you can also confirm the parameters passed on the Network tab in the XHR request. 
If all is well, you now have your sort order working on Coveo Custom tabs. 














Monday, April 17, 2017

Coveo Sorting Part 1 - On the Rendering

Coveo provides lot of tools and places where you could provide a sort mechanism.  First things first, sort is the most important piece that goes with listing.  If the listing of search results that you are showing to end user are not sorted per either business drive or more power to user where the user could actually select how he/she wants to sort their results is the key for the user to be able to find what they are looking for. 

Steps to get sorting working 

  1. Firstly define which field either sitecore or computed field you are going to use as a sort field.
  2. Note that OOTB, not all fields are sortable and you will need to configure and ensure that the field you are going to base the sort on is Coveo sortable.  For example - string fields are not inherently sortable while number fields are. 
  3. If the field you decided as sort field is not inherently sortable, configure it per directions listed here by Coveo documentation and rebuild your indexes.
    https://developers.coveo.com/display/public/SitecoreV4/Making+a+Sitecore+Field+Sortable
  4. After this step, always do a sanity check on admin tool that this field has a checkbox for sortable. 

Now that you have basic configuration ready, the next step is fairly simple.  Go to presentation on the template which has your coveo rendering on which you would like to apply sort.  Pull open the properties of Coveo rendering and you will see a Default Sort order section like below.  Input three parameters it looks for - 

  • Default Sort Type - Field | Date | Relevancy - I found Field and Date to be extremely useful 
  • Default Sort Direction - Ascending | Descending 
  • Default Sort Field - You have a pick list provided by Coveo which is a searchbox where you can type and find the sortable field you are looking for.  We are using December 2016 version of Coveo which has an active bug, so, we had to use GUID as a workaround instead of using field picker.   See an example on the screenshot below 

After you pick everything coveo is expecting, give it a spin -  Go to the page where this rendering exists and check what is happening on the query request.  You should see the below two populate with the field you picked and direction you mentioned on default sort order.  If you do not see this then the sort would not be working and you will have to debug further.  Couple times, it is due to presentation being overridden, so try resetting it before you panic. 😱




Now, all this works beautifully if you have just the basic Coveo custom rendering on your page.  Now, how will you make sort work with tabs, how about facet ordering.  What happens when you have both going.  How about if you need to apply sort ordering on a custom or computed field.  I will post details about these scenarios soon.  More to come later....Sorting O what fun. 😆

Happy Sitecoring and have fun every one.  Between, on a side note, last month I presented at LASUG about Coveo, if you wanna to check it out here is the link to youtube video.  Post your comments.





Monday, February 27, 2017

Helix/Habitat for TDS Setup Steps

The buzz around is that Sitecore is heavily pushing for Helix/Habitat and making it a standard.
If you have not already read through the core concepts, there is some awesome documentation that can you started here on Helix concepts -
http://helix.sitecore.net/

Now, once you read through this, I bet just like me you will be tempted to get a copy for yours.
I use TDS for my everyday chores, so I got mine from here -
https://github.com/HedgehogDevelopment/Habitat/tree/TDS

fun fact: Habitat team maintains two trees of the sample project for Habitat, one for TDS and the default one uses Unicorn.(https://github.com/Sitecore/Habitat)

I really wanted to play with this after reading through bits and pieces of the information and would like to share my experience of setting Habitat on my local with you all.

I am ready to get started with Habitat, are you ready?

First things first,  get the repo from the Githib for TDS Habitat.  Please note, the clone URL setup on the github is not cloning the TDS version(may be not setup correctly, I will log a comment).  So, for now, please click on Download Zip instead of cloning the repo to continue with local set up.



After this step, I got some serious code on my local.   For the next step, I needed SIM which I already had on my machine, so went straight for it.  I went ahead and installed a fresh Sitecore Instance 8.2, Update 1 per recommendation.  Not sure if it is my internet connection, it did take some time. :)

Next step is to install webforms for marketers.  You can get this as a package specific for the sitecore version and can install through the site once it is up.  In my case here is the version needed for Sitecore 8.2, Update 1

https://dev.sitecore.net/Downloads/Web%20Forms%20For%20Marketers/82/Web%20Forms%20For%20Marketers%2082%20Update1

Important point to note here - When you install WFFMModule from link above, do not think it is a sitecore package, unzip the folder and choose the one based on your server environment, mine is obviously local so I picked the basic package for install.  After zipping pick the one highlighted below when installing from Sitecore Package Installer.





After this step, please rebuild the whole solution and ensure there are no errors.  Then, right click on your solution and select deploy.  Quick note on deploy, It takes a while as there are lot of solutions and lot of items to deploy, it did time out for me once, I did a redeploy and it worked.

Login to sitecore admin(admin/b) and Publish the site.  Go to your local URL and ensure the site is up and running(screenshot below).  Now, for the next steps, I will explore the solution and excited to see what Helix/Habitat could do for us. :)










Tuesday, February 14, 2017

Sitecore Schedule Tasks - CM/CD Environment

I recently had to set up sitemap on CM/CD environment where we had the typical sitecore configuration one CM and two load balanced CD servers. 
I wanted to run some experiments to see optimal items and configuration needed to ensure both CD's have the sitemap.xml auto generated. 
I did this because I was curious to know why folks said we need multiple same scheduled tasks one for each server node.  I was definitely positive that I can pull this off with just one scheduled task across all environments.  Turns out, I was over ambitious!

Below are the experiments I did to content my curious brain. 

Case 1 -  Only one task across all environments

My ambitious drive of making it work with just one scheduled task, in our patch file where we have the path for scheduled tasks defined which would be incorporated on showconfig, I ensured that all the servers pointed to the same path. 
For example - 

     <agent type="Sitecore.Tasks.DatabaseAgent" method="Run" interval="00:10:00"             name="Master_Database_Agent">
        <param desc="database">master</param>
        <param desc="schedule root">/sitecore/system/tasks/schedules/CM</param>
        <LogActivity>true</LogActivity>
      </agent>

Results 

Post this setup, all is well on CD1, the sitemap was generated and by the looks of it covered all URL's of items in content and protocol was followed fine as well per setup. The issue is the CD2, turns out sitemap is not updated on this server. 
I checked the logs on CD2 to see if there was an error, there were none related to sitemap generation, but, one thing I did notice on the logs is that - every time I would see that the schedule specific to refreshing sitemap would come back as not due. 
In the logs, I would see entry like below - 

ManagedPoolThread #3 18:19:38 INFO  Scheduling.DatabaseAgent started. Database: liveweb
ManagedPoolThread #3 18:19:38 INFO  Examining schedules (count: 1)
ManagedPoolThread #3 18:19:38 INFO  Not due: Refresh XML Sitemap
ManagedPoolThread #3 18:19:38 INFO  Job ended: Web_Database_Agent (units processed: 1)

This would mean that every time the scheduling agent runs it finds out the task has already been run per schedule and does not run it any more. 

Case 2 -  One task per server 

Now, the case which I did not wanted to do, I always strive to avoid duplication which would mean more management and more configuration, but, I had to test and ensure load balanced servers have sitemap served properly when crawlers do their stuff. 

What I did to test this case is to duplicate the scheduled tasks one for each server, so on my master database I would have three different nodes and scheduled tasks and on each server the path on configuration would be different as well. 

On CD1 - 
 <agent type="Sitecore.Tasks.DatabaseAgent" method="Run" interval="00:10:00" name="Web_Database_Agent">
        <param desc="database">liveweb</param>
        <param desc="schedule root">/sitecore/system/tasks/schedules/CD1</param>
        <LogActivity>true</LogActivity>
      </agent>

On CD2- 
<agent type="Sitecore.Tasks.DatabaseAgent" method="Run" interval="00:10:00" name="Web_Database_Agent">
        <param desc="database">liveweb</param>
        <param desc="schedule root">/sitecore/system/tasks/schedules/CD2</param>
        <LogActivity>true</LogActivity>
      </agent>

 Results - 

In this scenario and setup, everything works well and servers are happily serving the most updated sitemap.xml 

So, the bottom line is,  if you want a task to run on all servers at least once and can not possibly live with running just once regardless of which server it ran on, then, we need to duplicate and there seems to be no option. 

Do you all have any other ways to make this work with no duplication of tasks when both load balanced servers are pointing to same database. (web)?

I would be super curious to know, do post comments or suggestions. 









Monday, January 23, 2017

Coveo Zero Results Issue

First, based on project requirements on Coveo version you have installed all Coveo components, hooked up your sitecore to use Coveo and all is well on Diagnostics. All components are Green.

Now, you drop or use newly and successfully built index for your search queries, you get zero results back.
Why would it return zero results, is it picking incorrect index? Are my configurations fine? Then you go the good old CES console to see if there are any errors.  Except for query returning 0 results, there are no errors.
But, I note this on the CES console -

Query (@fz95xlanguage76852=="en") (@fz95xpath76852==3ab17f3f16be4a018105ecade4380857) (@fz95xtemplate76852==f5cc486b394c40ff8320480ec7c650a7) performed by extranet\Anonymous [Sitecore Security Provider for blah-blah.com]. 0 results in 0.016 seconds.

I copied the query and ran it in Index Browser on CES Administration tool.  It did return loads of results.  So, it is not data, it is there for sure and query is correct as well.

Seems like the query was run by Anonymous user.  So, few check points to ensure this is not permissions issue.


  1. Ensure extranet/anonymous user on sitecore instance have read permissions on the content tree 
  2. Go to Index Browser and run the query above, go to any of the search results and look for permissions tab under Details.  It should show who all have access to this item.  
  3. You should see 'Anonymous' there.  If Anonymous is not there, that could be a problem and which is why the results come back as '0'.  I did not see this user in permissions and started scrambling on what I can do to fix this.  I came across the below blog 

The problem stated there looked exactly like mine.  I did the last step which is to clear caches on Details Tab under content security and once I did that, I could now see anonymous under permissions in individual documents. 

All is well and no more empty results. 

Query (@fz95xlanguage76852=="en") (@fz95xpath76852==3ab17f3f16be4a018105ecade4380857) (@fz95xtemplate76852==f5cc486b394c40ff8320480ec7c650a7) performed by extranet\Anonymous [Sitecore Security Provider for blah.com]. 203 results in 0.031 seconds.


Friday, January 13, 2017

Debugging CD issues - No matching constructor was found

Most of the times, when you set up a CD server at some point or the other.  You will see errors like 'No matching constructor found....'
These nasty errors are hard to debug specifically if you have bunch of complex third party system's interacting with your sitecore instance. I encountered something like this while setting up our pre-production environment with load balancer going on.  If you choose to do trial and error, these errors could take for ever to resolve.  
I applied a strategy and that seemed to get me to the problem more quickly.  Also, I felt the strategy is generic, so, it could be applied to any error similar to this kind.

So, here is the error I had to battle - 
Could not create instance of type: Sitecore.ContentSearch.LuceneProvider.LuceneIndex. No matching constructor was found.

Here are the steps I took to resolve this.  Hopefully, it will help some one scrambling for a resolve. 

Go to sitecoreinstance/sitecore/admin/showconfig.aspx and ensure there are no references to 'master' any where, since this is a CD after you enable Switch master to web config and you did a good job at it, you should not be seeing any references.  If you do, then, revise your config. 

After you eliminate #1, check for which constructor it is is complaining about.  In my case it was Sitecore.ContentSearch.LuceneProvider.LuceneIndex.  So, I pulled up the *.dll specific to this that comes with Sitecore installation using reflector. 



If you notice - there are three constructors I could see from what reflector has to say -  In this case the below:

protected LuceneIndex(string name);
public LuceneIndex(string name, string folder, IIndexPropertyStore propertyStore);
public LuceneIndex(string name, string folder, IIndexPropertyStore propertyStore, string group);

Next, I opened up sitecoreinstance/sitecore/admin/showconfig.aspx again and went through all entries on the config that inherit or have provider listed as Sitecore.ContentSearch.LuceneProvider.LuceneIndex to check and see if they are passing the params to adhere to one of the three the *.dll supports.  

There were only about nine references, so, it was not such a pain to see each of those to compare.  I found one entry that was not passing params per expectation.  You should also see from which patch file this entry is coming from.  Thank you Sitecore. J

I deleted that entry as I did not need it as the original config file from which this index was originally defined was disabled per Sitecore set up instructions.  But, in your case if you need that entry, ensure you are passing in params that would match atleast one constructor. 

That’s all!! Error behind us and I could go back to sleep peacefully.  This strategy could be applied to any error you will face.  The fact is trial and error is not so much fun and application of clear strategy shows you understand what you are doing. 

Hope this helps someone!!!