Thursday, April 28, 2016

Sitecore icons not loading in content editor

If you notice that some icons are not loading in the content editor of Sitecore:


The browser console may also have errors such as:
Failed to load resource: the server responded with a status of 401 (Unauthorized)
These errors occur on icon files such as /~/icon/Network/16x16/download.png.aspx and when this item is opened in the browser, a more detailed error message will show:
Access to the path 'C:\inetpub\wwwroot\sitecore\Website\temp\IconCache\Network\16x16\download.png' is denied.
The fix is to add security permissions to the IconCache folder for the NETWORK SERVICE and  IUSR accounts. The icons will then appear correctly.


Wednesday, April 27, 2016

Sitecore Lucene inconsistencies with urllink field

In the default configuration file for Lucene in Sitecore there is a field indexed and stored by default called urllink. This file is found under App_Config/Include and is called: Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config. The purpose of this field is to store the URL to the indexed item and the field index is defined as:

<field fieldName="urllink"              storageType="YES" indexType="TOKENIZED"    vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
  <analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
</field>

When I implement search functionality in Sitecore, I store all of the required field values in the index so that at search time no queries need to be made to Sitecore (this speeds up the search). The main problem with using the urllink field is inconsistencies in the URL is the fact that sitecore/shell appears in the URL for some media items.

This was discussed in a Stack Overflow post some years ago and Sitecore did not recommend using this field - and apparently it will be removed in the future... The post there suggests querying Sitecore at search time for a URL, however I am a fan of the custom computed index field approach to keep my Lucene search optimized.

Sitecore Lucene ensure there are no duplicate search results

If a Sitecore Lucene search index is set to update incrementally, when a document is updated it is simply added to the index (ignoring if it was already there). By adding the unique ID field (aka item GUID) to your search index using the lower case keyword analyser you can stop the duplicates.

<field fieldName="_uniqueid" torageType="YES" indexType="TOKENIZED" vectorType="NO" boost="1f" type="System.String" settingType="Sitecore.ContentSearch.LuceneProvider.LuceneSearchFieldConfiguration, Sitecore.ContentSearch.LuceneProvider">
  <analyzer type="Sitecore.ContentSearch.LuceneProvider.Analyzers.LowerCaseKeywordAnalyzer, Sitecore.ContentSearch.LuceneProvider" />
</field>

This should be in every custom Lucene index in which you create.

HttpHandler for PDFs resolve static item

In an implementation I had created an HttpHandler which was used to find PDF files. However there was an edge case where it was handling files in a virtual folder (used by Sitecore for Print Experience Manager Publishing) and this was not desired logic.

The following line of code can be used to return the physical PDF (and not one from my handler):
context.Response.Clear();
context.Response.ContentType = "application/pdf";
context.Response.TransmitFile(context.Request.PhysicalPath);

context.Response.Flush();
context.Response.Close();
It will also 404 if the PDF does not exist on the path.

Angular 2 and Sitecore Example

Having worked on a number of Sitecore projects which used version 1.x of AngularJS, and with Angular 2 now in beta, I decided to take a look and see how a migration path would be for existing Sitecore sites.

Initial thoughts

  • I was able to get Node.JS (including npm) integration into Visual studio which provided Typescript project templates and had a gulp file compiling the Angular 2 Typescript to ES5 JavaScript.
  • There is a learning curve after using Angular 1.x and not having used Typescript before.
  • Angular 2 appears to have large amounts of JavaScript (file size once compiled and minified) which will affect page load times.
  • It has been built with single page apps in mind, which is how a lot of the demos are structured (using routing for example). 
  • It's still in it's early stages so tooling and error reporting still have some way to come. Features apparent in documentation and example blogs have since been removed.

Setting up the environment

There are a lot of detailed blog posts about doing this, however the quick list of pre-requisites is:
  • Install Visual Studio 2015 - Select Visual C++ features to support Node
  • Install Node 5.x
  • Register Node at the top of External Web Tools in Visual Studio


  • Install Python 2.7.x - this is needed for Node and the C++ compiler
    • Set Python in the windows path
    • Run the command: npm config set python python2.7
    • Run the command: npm config set msvs_version 2015 --global
  • Install this Visual Studio add-on to get npm script support in task runner explorer
  • Install Typescript for Visual Studio
  • Install Node.js tools for Visual Studio - see Node.js npm integration with Visual Studio 2015 for more information

Setting up the solution

I chose to split the Visual Studio solution into two main projects:
  1. Typescript project for the Angular 2 app - this used gulp to compile into JavaScript
  2. A standard web forms project which had user controls which referenced the compiled JavaScript (and standard Angular 2 requirements)
I didn't want to get carried away with the tooling here, but the [future] idea was that the build of the Sitecore web forms project would compile the Angular 2 and clean/deploy it onto the target website, then deploy itself. It's manual deploy right now ;)

The code is available at: Sitecore Angular 2 on Github.



Angular (Ang) Project
The structure is:
  • dist - compiled JavaScript I checked this in (not included in solution) for demo purposes
  • src/app - the TypeScript source
  • gulpfile.ts - can be run from Task Runner Explorer to compile the TypeScript into JavaScript (ES5)
  • package.json - used by Node to define the various npm packages used y the solution
  • tsconfig.json - configuration for the TypeScript and is used for compiliation
To restore the npm packages, right click npm and select Update npm Packages - this will use package.json

To compile the TypeScript, open up the Task Runner Explorer and run the build. This will output it to the dist directory. 



Sitecore (Sc) Project
This one is fairly self explanatory, it contains one layout and two sublayouts. The layout references all of the required JavaScript resources and instantiates the Angular 2 (the script below the body tag). The two sublayouts simply output their Angular 2 components.

In Sitecore
Now it's simply a matter of creating a layout, two sublayouts and then assigning them to a page:


Then the two Angular 2 components as Sitecore sublayouts will appear on the page:


Final thoughts

This exercise was a proof of concept to get Angular 2 working in Sitecore. As Angular 2 is current under development/in beta it's not production ready, however it is a good idea to get a handle on the changes from Angular 1.x. I'll be working with some more advanced concepts in a future blog post.

From what I have seen, the framework is ever improving, and breaking changes are made with each beta release. Many of the code samples online contain broken code, so I would recommend waiting for a more stable state before bringing larger solutions into the fold.

I kept this post brief as to cover a few concepts, feel free to comment below if you have any issues getting setup. Or you have any more discussion points on Angular 2 with Sitecore 8.1.

Tuesday, April 26, 2016

Sitecore Advanced Sitemap Module Updated

Mohammed Syam has developed a great module for Sitecore called Advanced Sitemap Module. I have used this on a number of implementations, and it works well. However with Sitecore 8.1 the following error might occur when installing the package:
Empty strings are not allowed. Parameter name: itemName
This appears to be due to a corrupt package (or one not supported by Sitecore 8.1 +). So I recreated the items to create a fresh package that will install on Sitecore 8.1.

Code was updated from a fork of the original by Patrick Stysiak. Here are a couple of notes:
  1. Fixes have been made to work on Content Delivery servers (no master connection)
  2. Error with info logger in one case removed
  3. Icons may be different from the original
  4. GUIDs have changed from the original (in terms of template IDs and SiteMap configuration content item).
  5. Field changed from Show In SiteMap to Show In XML SiteMap
  6. Code will no longer error when root site item has descendants which don't include the sitemap base template. This was P => P.Fields["Show In XML SiteMap"].Value == "1" code. We now check for items which have the field and the field value is set to "1". P => P.Fields["Show In XML SiteMap"] != null && P.Fields["Show In XML SiteMap"].Value == "1"
  7. Fixed config bug where Sitemap would not generate unless MultilingualSiteMapXML was set to true 

The Github source for the code is available at: Sitecore Advanced SiteMap module. - This is not required as the package has the DLL included.

The updated package is available here.

Notes

  • ERROR Advanced SiteMap config item was not found: This is because the SiteMap config item (ID {38ACC950-E87F-4A5C-9271-C55C4336AAAB}) could not be found in the web database
  • The Sitemap Site template has a field called Site Name, this should refer to a site defined in the sites node of Sitecore.config
  • This module uses the web database, so ensure a publish will be needed for changes to appear in the Sitemap

Sitecore access to the viewstate folder denied

If you are unable to load the Sitecore desktop and get errors pertaining to access being denied on the Data\viewstate folder (and its many child folders), it's a permissions issue...

To allow file uploading and modification of the site, grant the ASP.NET user Read/Write rights to the following folders:
  • /data
  • /upload
  • /temp (if this directory does not exists immediatly after installation, create it).
  • /sitecore/shell/Applications/debug (if this directory does not exist immediately after installation, create it).
  • /sitecore/shell/Controls/debug (if this directory does not exists immediately after installation, create it). 
  • /layouts (If Developer Center will be used to create and modify layouts and sublayouts).
  • /xsl (If Developer Center will be used to create and modify XSL renderings).
  • /App_Data/
In order to maintain the search indexes ASP.NET and IUSR_* users also require the modify access rights to the following folder:
  • /indexes
Both the ASP.NET and IUSR_* users require Read and Write access rights to the following folders:
  • /audit
  • /logs
  • /viewstate
  • /mediacache
  • /diagnostics
Where IUSR_* refers to IUSR_MachineName.

Friday, April 22, 2016

Sitecore web forms for marketers on a multi-instance environment

A typical multi-instance Sitecore environment will likely contain one content management (CM) server and two content delivery servers (CD). The master connection is removed from the CD servers as they should not be connecting to it, and this will affect web form for marketers (WFFM) because it has save actions such as creating Sitecore items and uploading files.

Therefore for these actions to work as expected the CD servers will need to be able to access the CM server via a service (port 80). The following connection string needs to be added to connectionstrings.config:

<add name="remoteWfmService" connectionString="url=http://[masterserver]/sitecore%20modules/shell/Web%20Forms%20for%20Marketers/Staging/WfmService.asmx;user=[domain\username];password=[password];timeout=60000" />

Wednesday, April 20, 2016

Node.js npm integration with Visual Studio 2015

One of the greatest features of Node.js is the ability to install and manage packages using npm. As a CMS developer on the Microsoft stack, I am more accustomed to using Visual Studio for my development environment. Luckily for me there is an (open source) extension available for Visual Studio called Node.js Tools for Visual Studio. It's even released on the Microsoft Github account...

Angular 2 errors when compiling with Gulp

When attempting to use a Gulp script to compile my Angular 2, I was getting a lot of various errors in the output window. These included:
error TS2304: Cannot find name 'Promise'.
error TS2304: Cannot find name 'Map'.
error TS2304: Cannot find name 'Iterator'.
Adding 'node_modules/angular2/typings/browser.d.ts' to the Gulp src appeared to fix the error and the code compiled correctly.

return gulp
    .src(['node_modules/angular2/typings/browser.d.ts','src/app/**/*.ts'])
    .pipe(typescript(tscConfig.compilerOptions))
    .pipe(gulp.dest('dist/app'))

This is a source map file required for the code to compile.

Tuesday, April 19, 2016

Sitecore publish to web failed - Web database full

While working on a Sitecore development environment which was using SQL Server Express, the following error came up when attempting a full publish to web:
Job started: Publish to 'web'|#Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Exception: Could not allocate space for object 'dbo.EventQueue'.'IX_Stamp' in database 'Sitecore_Web' because the 'PRIMARY' filegroup is full. Create disk space by deleting unneeded files, dropping objects in the filegroup, adding additional files to the filegroup, or setting autogrowth on for existing files in the filegroup.

Sitecore warning Could not compute value for ComputedIndexField

In one implementation where PDF content was being indexed in Sitecore (with Luncene), the content was not returning in the search results (no PDFs appearing). After looking in the crawling logs, the following warning was in there for each PDF document that was attempting to be indexed:
WARN  Could not compute value for ComputedIndexField: _content for indexable: sitecore://web/{10D8A7A1-880C-4143-923C-84D94BA56232}?lang=en&ver=1
Exception: System.Runtime.InteropServices.COMException
I am using PDFBox to index PDF content however there was an element left  in the default Lucene configuration file (/App_Config/Include/Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config):
<field fieldName="_content" storageType="no"  indexType="tokenized">Sitecore.ContentSearch.ComputedFields.MediaItemContentExtractor,Sitecore.ContentSearch</field>
Should be changed to the computed index field in your solution which does the PDF indexing.
<field fieldName="_content"                  type="MyProject.ComputedIndexField.IndexPdfContent,MyProject"></field>

Sitecore Lucene include and exclude template warning

With my Lucene indexes I tend to include the relevant templates which I want included in the index. This will often lead to the following warning:
You have specified both IncludeTemplates and ExcludeTemplates. This logic is not supported. Exclude templates will be ignored.
 Inside the default Lucene configuration file (/App_Config/Include/Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config) there is a section with some templates excluded by default:

<exclude hint="list:AddExcludedTemplate">
  <BucketFolderTemplateId>{ADB6CA4F-03EF-4F47-B9AC-9CE2BA53FF97}</BucketFolderTemplateId>
</exclude>

As the error suggests, with Lucene search in Sitecore you can't both include and exclude templates. Therefore as I choose to decide on what templates to include (opt-in rather than opt-out), this section can be commented out which fixes the warning throughout the logs.

Installing MongoDB on a Windows machine as a service

The great experience analytics features (including the experience profile) in Sitecore 8 and beyond require the use of MongoDB. MongoDB is not like common database management servers (such as SQL Server or Oracle) whom use tables and rows, MongoDB instead stores data dynamically in the JSON format. The instructions to install MongoDB on your windows machine (as a service) are as follows.

Monday, April 18, 2016

Creating a custom filter for advanced system reporter in Sitecore

The advanced system reporter module for Sitecore is a great way to provide reporting, in a similar way to the out-of-box broken links report. After installation the module comes with a number of pre-defined reports, along with scanner and filter, but there can be a need to customize for specific reports the business needs.

In this case I have written a custom filter to filter by template name. The business need for this one would be to use an existing report, but filtered on a specific template (for example media releases).

namespace MyProject.Reports
{
    public class TemplateNameFilter : BaseFilter
    {
        public string TemplateName { get; set; }
        public override bool Filter(object element)
        {
            Item item = null;

            if (element is Item)
            {
                item = element as Item;
            }
            else if (element is ItemWorkflowEvent)
            {
                item = (element as ItemWorkflowEvent).Item;
            }

            if (item != null)
            {
                if (item.TemplateName == TemplateName)
                {
                    return true;
                }
            }

            return false;
        }
    }
}

Once deployed to Sitecore, the custom filter can be created:


A custom parameter also needs to be created:



Now the filter can be added to any advanced system report.

Friday, April 15, 2016

Sitecore using a custom template for PDF and other media items

In cases where you index PDF content in Sitecore, it's a good idea to set a flag on the template which allows the content authors to exclude the item from search results. Instead of editing the system templates (both unversioned and versioned), it's possible to use your own. Simply:
  1. Create a new template which inherits from the base Sitecore media template 
  2. Add the custom fields or reference another base template which relates to search
  3. Open up the web.config (or sitecore.config) file and look for the mediaLibrary mediaTypes node
  4. Find the mediaType node for the template you are replacing
  5. Update it to use your new template
<mediaType name="PDF file" extensions="pdf">
  <mimeType>application/pdf</mimeType>
  <forceDownload>true</forceDownload>
  <sharedTemplate>Path/MyPDF</sharedTemplate>
  <versionedTemplate>Path/MyPDF</versionedTemplate>
</mediaType>

Simple, now there is no need to hack any of the Sitecore system templates

Thursday, April 14, 2016

What stood out to me in Sitecore's Context Marketing for Dummies book

Unfortunately it's not George R. R. Martin's long awaited next book, but the Sitecore edition of Context Marketing for Dummies is a fascinating read with some great insights. I had seen physical copies of the book on Twitter, but was pleasantly surprised to receive an email campaign with a link to download the ebook version (grab your copy here, it's free). Even before the book had finished downloading there were some takeaways for me around how Sitecore themselves were doing internal context marketing. The email itself contained four calls to action, which   linked off to a redirect page on the Sitecore site. Embedded in the URL was my Sitecore contact ID (for their CRM and experience profiles) along with the email campaign message ID. Obviously that is standard for emails sent with the email experience manager, but the download page then promoted for personal details (including phone, title and company). This detail collection to me has two key purposes:
  • Data mining around companies interested in Sitecore context marketing - perhaps a chance at some sales. They did ask for country so, data could be accessible to local sales representatives. Perhaps Sitecore sees a high/low interest for marketing in region X, and should invest in conferences there.
  • Contact confirmation - it's only natural to share an email, so if another user were to click the campaign with my contact ID and entered fresh details, a new experience profile could be created.
With that all aside, I enjoyed the book and wanted to discuss a few of the points that interested me the most.

Understanding the digital consumer

The first point that really jumped out at me from chapter 1, was this graph. The second most important factor which can influence customer opinions was "Offer a consistent experience regardless of how I shop". This is particularly relevant to Sitecore because one of the key selling points is the ability to give users, the same experience no matter the channel. Secondly, the greatest difference between the millennials and all other age groups was on "Offer different ways to purchase (website, mobile app, and so on)". Although this wasn't in the higher ranking answers, it does show how important catering to these different channels can be to the younger demographics. The least popular factor "Use marketing that is specifically tailored for me", is never really going to rank well in this question set, people are also quite afraid of the ramifications of this so might be put off.
This leads quite nicely into the next graph, which shows what survey respondents preferred method of contact was. It's no surprise that email ranks so highly (and telephone so lowly). What really stands out here is the high response that millennials have to social media as their preferred method of contact. This factor is an argument that should influence an investment into social media strategies and perhaps integration with your system (Facebook message e-commerce receipts maybe?).

Context marketing case study

One case study mentioned in the book which was a bit different from the usual ones I see was for USA Soccer. "Its primary touchpoint with customers is its website, ussoccer.com", "Website visitors include casual fans who check in on teams every now and again, all the way up to die‐hard fans who follow teams around the country.", "Other groups of visitors include elite players, coaches, and referees". This is an interesting dilemma, where previously the outcome would be a bloated website with too much information, for too many audiences (and not optimised for any one group). "By leveraging personalization capabilities, U.S. Soccer provides each website visitor with a unique and engaging experience". This is a prime example of how Sitecore can be used to tailor experiences for multiple distinct audiences, all off of the same website and same content. The great thing about building this sort of website is how easy it is to get started and take your first bite into Sitecore's marketing offerings. It's actually best to start small with this sort of thing, maybe as simple as personalising a banner or image slider to particular browsing patterns.

Disconnected data

Another concept introduced in the book is around the term disconnected data. Effectively this happens when you require manual intervention for key marketing flows. The example given was a consumer researching cars, who emailed several dealerships to find out more information. They eventually made their purchase, but two weeks later they finally got a reply from one of the dealerships they queried. That contact form simply sat in a database of emails (potential leads), instead of being linked to a CRM containing the full picture on who the user is. Imagine if that dealership was using Sitecore. An experience profile would know what vehicles they were browsing (for how long as well) and could likely profile what sort of customer they were. This could all be used with automated marketing via Sitecore's engagement plans, where the customer would receive an email (mot popular contact method from the survey graph earlier) that day which was personalised to the vehicle types they had been browsing. That could have easily been a conversion, and all automatically by Sitecore.

A don't when investing in context marketing technology

Don’t invest in technology that adds another application or data silo. This is a good point, because too many systems (silos) is not going to deliver a clean, easy to use and integrated experience. It will likely lead to large investment in integration activities and more training for the end users of the applications. This related well to one of the cautions Gartner made about Adobe's CMS offering in their 2015 report: "Gartner has heard of a few organisations using other WCM products in addition to Adobe, because of implementation costs being higher than expected with Adobe.". With Sitecore you know that you are getting a fully integrated suite of products (which includes the engagement plans, email experience marketing, print experience marketing, and optimised and personalised websites). Of course there is no such caution when it comes to Sitecore, in fact one of the strengths was listed as "Sitecore has incorporated into the product some highly valuable features, such as engagement analytics, a/b testing (or split testing) and data management platform capability."

Wrap-up

I have only just discussed the tip of the iceberg when it comes to the great information laid out in Context Marketing for Dummies (Sitecore edition). It really is a good read, and for the great price of free you'd be silly not to download your copy today.

Tuesday, April 12, 2016

Sitecore content migration strategies

When migrating an existing website onto Sitecore, one of the biggest considerations is around the migration of content. In cases where multiple sites are merging into one, or a multisite environment it can become even more tricky. When it comes to the migration there are two main points to consider, the migration of the content itself and the URL structure after the fact. Even in cases where content URLs remain exactly the same, the media library items (PDFs in particular) will most likely be different.

Initial planning

This first step with content architecture in Sitecore is to identify all of the different unique content types. It's these types that will form the data templates, and early planning can help identify similarities and build an object orientated structure. The benefit of object orientated template structure in Sitecore, is the use of base templates to provide common fields (which means less field duplication). In terms of content migration, the less unique fields, the less tricky it can become. Once you have defined your data structure (in the form of templates) it's time to plan out the architecture of the content itself on the site. A website migration such as this is a great time to hold workshops amongst the business to decide on the best architecture moving forward. It may mean slight reorganisation once the content is brought across but can lead to easier management and a better experience for users. There are many different ways to architect the content on your website, it all comes back to the type of website being built and quite often the structure of the company behind it. If you get the top level architecture right, you can even use it as a facet for search results in Sitecore.

Migrating the content

With content migration there are multiple ways that it can be achieved, and each comes with their own pros and cons.

Manual migration

Manual migration involves content editors moving all of the content from the old site to the new site by hand. This method can generally be the most time consuming of the bunch, however is best suited for websites with smaller amounts of content where automated migration would not save time.

Pros:
  • Will often lead to a cleaner media library architect where only items which are used are brought over and organisation can be much tidier.
  • It gives a chance to have all content reviewed in terms of fact checking, spell checking and ensuring consistency across the website.
  • It gives content editors more exposure to Sitecore and in turn they are more confident in the system.
Cons:
  • More time consuming than automated migration.
  • Can be difficult to evenly split content, so multiple people handling the same content types might lead to inconsistencies.
  • Content might be missed in these instances.
Considerations:
  • Delays in content creation can and will affect development.
  • Content editors using key testing servers may mean less test deployments for code.
  • How will links from content to content be handled? If a page being linked to hasn't been created yet.
Tips:
  • Setup any URL strategies mentioned below at the same time to stop double handling of content.
  • If workflow is enabled, temporarily add a skip button which automatically sets and item to approved/published.

Automated migration

Automated migration is a no-brainer when it comes to websites which have large amounts of content. There are tools out there that specialise in this, however the Sitecore API is simple enough that developers can easily setup custom migrators with business logic included.

Pros:
  • Faster than manually creating the content.
  • Can automatically spell check all content from a single source.
  • Logic can be built to re-create all content to content links.
Cons:
  • Any URL strategies may mean extra "content" to create and more development effort.
  • Developers can get carried away building tools (12 hours of effort for a saving in 3 hours content editing).
Considerations:
  • Paid migration tools may not be customised to your needs.
  • Paid tools may cost more than development effort for custom tools.
Tips:
  • When testing migration tools, set a limit of X items to be moved. Nothing worse than running one for several hours only to see fields mismatched.
  • Don't forget to take into account the image width/heights when migrating into media library. You don't want a thumbnail appearing as full resolution because you simply moved the source and didn't record attributes.

Hybrid approach

A hybrid approach is a great way to get the best of both worlds when it comes to content migration. Large data sets such as news article, media release and blog posts are great candidates for migration. Where key pages might benefit from the pros of a manual migration.

Pros:
  • In the middle in terms of time to move the content across.
  • Gives content editors more exposure to Sitecore and in turn they are more confident in the system.
Cons:
  • Potential for duplication of content.
  • Potential for content to be missed.
Considerations:
  • How are shared media library resources handled by both content editors and migration tools?
  • Perhaps an automated migration with manual checking on key pages is a better strategy?
Tips:
  • Let the automated build run first, that way the content editors have access to any migrated media items.

Link structure changes

So now that all of your content has been migrated over to a shiny new Sitecore install, the only question remaining is how different the link structure is. If you are really lucky, you will have been able to utilise the same link structure in Sitecore as the previous CMS, however for those of you dropping file extensions (*gasp* .php for example) theres some work to be done. In fact it's almost guaranteed that some work will need to be done when it comes to URL redirecting, not only due to site structure changes but the inevitable PDF link changes. There are a number of options available to handle these URL redirects:
  • Sitecore URL rewrite/redirect modules: On the Sitecore marketplace there are quite a few rewriting/redirecting modules available of varying complexity. URL Rewrite is a favourite of mine due to the rich feature set (regular expressions and exact matches) and because it uses 301 redirects which are recommend by Google - best for SEO.
  • Custom item resolvers: Sitecore uses an order of precedence when trying to resolve a web page or media item. So once Sitecore has attempted to find the item (and fails) and before it hits a 404 not found you can inject your own custom resolver for finding the item. Potential use cases are:
    • Business logic to find the correct page
    • Use Lucene search index to find the correct page or suggest multiple pages
    • Redirect URLs from a specific content type to the new area or item (based on name)
  • Custom media handlers: In one case I used a custom media handler to handle for PDFs not found by Sitecore's media handler. It made use of a Lucene index of all PDFs and then searched this index to check for an exact match based on the file name. PDFs were served up for any matches and 404s were raised for any not found.
It's always an awkward moment for new Sitecore users to see the 404 page as the highest entry page/exit page in Sitecore's experience analytics...

Wrap-up

Migrating content to Sitecore and handling the resulting changes in link structure with Sitecore is no easy task. Even with automated content migration strategies, there will often be extra manual work in redirecting the old URLs to these new items. Each implementation is different and the best generalised advice I can give is to spend more time in the early stages planning these two factors, this is what leads to better outcomes.

Using Sitecore search to resolve PDFs not found

When you link to a PDF or other media library item in Sitecore, and subsequently move that file, the link will remain intact. Likewise if you attempt to delete an item linked internally, a warning will present itself to the user. The problem I faced is PDF files which are linked externally (via email and third party websites for example), along with migration from another CMS to Sitecore with a large amount of PDFs.

The solution, was to index all PDFs in the media library (using a Lucene search index) by name. Then after the default Sitecore media handler, add a custom one for PDFs that searched that index for a file that macthes the requested document name. If a single match was found, that would then be served up. If not the request would ultimately 404.

Lucene Index
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <contentSearch>
      <configuration type="Sitecore.ContentSearch.ContentSearchConfiguration, Sitecore.ContentSearch">
        <indexes hint="list:AddIndex">
          <!-- Change this to Sitecore.ContentSearch.LuceneProvider.SwitchOnRebuildLuceneIndex, Sitecore.ContentSearch.LuceneProvider if you would like indexes to be
               built in a temporary directory i.e. while rebuilding is happening, your old indexes work like normal until the rebuild is finished. -->
          <index id="PdfIndex" type="Sitecore.ContentSearch.LuceneProvider.LuceneIndex, Sitecore.ContentSearch.LuceneProvider">
            <param desc="name">$(id)</param>
            <param desc="folder">$(id)</param>
            <!-- This initializes index property store. Id has to be set to the index id -->
            <param desc="propertyStore" ref="contentSearch/indexConfigurations/databasePropertyStore" param1="$(id)" />
            <configuration ref="contentSearch/indexConfigurations/defaultLuceneIndexConfiguration">
    <include hint="list:IncludeTemplate">
     <template>{0603F166-35B8-469F-8123-E8D87BEDC171}</template> <!-- Unversioned PDF -->
    </include>
    <IndexAllFields>true</IndexAllFields>
            <fields hint="raw:AddComputedIndexField">
            <field fieldName="pdfname" storageType="yes" indexType="untokenized"
                  patch:after="field[last()]">MyProject.ComputedSearchFields.PdfCleanName, Sitecore.Common.Website</field>
          </fields>
   </configuration>
            <strategies hint="list:AddStrategy">
              <!-- NOTE: order of these is controls the execution order -->
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/onPublishEndAsync" />
            </strategies>
            <locations hint="list:AddCrawler">
              <crawler type="Sitecore.ContentSearch.SitecoreItemCrawler, Sitecore.ContentSearch">
                <Database>web</Database>
                <Root>/sitecore/media library</Root>
              </crawler>
            </locations>
          </index>
        </indexes>
      </configuration>
    </contentSearch>
  </sitecore>
</configuration>

Computed Search Field
namespace MyProject.ComputedSearchFields
{
    public class PdfCleanName : IComputedIndexField
    {
        /// <inheritdoc />
        public string FieldName { get; set; }
        /// <inheritdoc />
        public string ReturnType { get; set; }

        /// <inheritdoc />
        public object ComputeFieldValue(IIndexable indexable)
        {
            Item item = indexable as SitecoreIndexableItem;

            if (item != null)
            {
                MediaItem mediaItem = new MediaItem(item);
                if (mediaItem != null)
                {
                    return mediaItem.Name.Replace("-", " ").Replace("%20", " ").Replace("_", " ");
                }
            }
            return null;
        }
    }
}

The Handler
namespace MyProject.Handlers
{
    public class PdfRewriteHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context)
        {
            try
            {
                // If PDF request
                if (context.Request.RawUrl.ToLower().EndsWith(".pdf"))
                {
                    // Terrible code to get the pdf file request file name... I need to practice REGEX
     var itemName = context.Request.RawUrl.Substring(context.Request.RawUrl.LastIndexOf("/")).Replace("/", "").Replace(".pdf", "").Replace("-", " ").Replace("%20", " ").Replace("_", " ");

                    var index = ContentSearchManager.GetIndex("PdfIndex");

                    using (var seaechContext = index.CreateSearchContext())
                    {
                        var results = seaechContext.GetQueryable<MyResultItem>().Where(resultItem => resultItem.Name == itemName).GetResults();

                        if (results.Hits.Count() == 1)
                        {
                            // one match found
                            MediaItem item = (MediaItem)Factory.GetDatabase("web").GetItem(results.Hits.FirstOrDefault().Document.ItemId);

                            if (item != null)
                            {
                                // Get name to be shown when image is saved
                                var fileName = string.Format("{0}.pdf", item.Name);

                                context.Response.Clear();
                                context.Response.ContentType = item.MimeType;
                                context.Response.AppendHeader("Content-Disposition", string.Format("inline;filename=\"{0}\"", fileName));
                                context.Response.StatusCode = (int)HttpStatusCode.OK;
                                context.Response.BufferOutput = true;
                                item.GetMediaStream().CopyTo(context.Response.OutputStream);
                                context.Response.Flush();
                                context.Response.End();
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(e.ToString(), "");

                context.Response.StatusCode = 404;
                context.Response.End();
            }

            context.Response.StatusCode = 404;
            context.Response.End();
        }

        public class MyResultItem : SearchResultItem
        {
            [IndexField("pdfname")]
            public string Name { get; set; }
        }
    }
}

Web.config
<add verb="*" path="sitecore_media.ashx" type="Sitecore.Resources.Media.MediaRequestHandler, Sitecore.Kernel" name="Sitecore.MediaRequestHandler" />
<add name="PdfRewriteHandler" path="*.pdf" verb="*" type="MyProject.Handlers.PdfRewriteHandler" resourceType="Unspecified" preCondition="integratedMode" />

We place the custom handler after the Sitecore media handler, because if Sitecore doesn't find the file, it's a 404.

This concept could be extended using Lucene to find files that are not exact matches (like the file name or contains key words for example). In my case the requirement was an exact match, however if there were more than one they could be presented on a page where the user is able to select the relevant one.

Another option is to place all legacy PDF files in a single folder and set that as the crawler root in the Lucene search index configuration.

Monday, April 11, 2016

Custom item resolver in Sitecore

I had a website migration to Sitecore with a large subset of URLs which could not be mapped using any of the available URL redirect modules (due to custom business logic). Therefore a custom item resolver had to be written.

This then gets referenced in the Web.config or Sitecore.config file after the default item resolver. That means that if Sitecore doesn't find the item it goes into this custom resolver. If the business logic doesn't find the correct item, it continues on through to a normal 404 error.

Sunday, April 10, 2016

Bridging the gap between the various stakeholders of your Sitecore implementation

I see a lot of Sitecore implementations of varying sizes and complexities and one of the common themes I notice is the disconnect between the various stakeholders. I see these stakeholders as fitting into some high level groups; marketing (including sales), developers, and business users (content authors/end users). It’s an interesting observation where the distinct groups can often end up fighting from their perspective because they tend to have different thought processes, knowledge areas and goals. The purpose of this post is to look into the viewpoints of each stakeholder group to provide awareness of where they are coming from and hopefully spark discussion in the community.

Marketing & sales

For a marketer or sales person some of their key goals might be:
  • Building brand awareness and engagement
  • Generating leads
  • Making conversions
  • Consistency
Ultimately the marketing and sales departments live and breathe the brand, and the consistency of that brand is an important concept. While title case vs sentence case might not factor into developers thoughts, or each of the many content editors, marketing teams will pick up on it.

The website is ultimately one tool in the arsenal in which to interact with customers of the company. A consistent website, with the correct branding and which ties in well with social media is a great baseline to have. Once this is established, it can be built upon to get more awareness (and engagement) which in turn leads to the ultimate goal of leads and conversions. Perhaps the company is selling a product or even a service, it makes no difference their journeys are very similar.

Think of a product sales company like Coca Cola and contrast that with a service company such as your local job listing website. They both focus heavily on a clean/consistent website experience, which then draws visitors from the multitude of marketing efforts across online channels and offline channels.

Developers & technology department

For a developer (or others in the information technology department) some of their key goals might be:
  • Deliver on time
  • Deliver quality (free of bugs and using best practices)
  • Be given a clear outline of requirements
  • Use the latest technologies/frameworks etc.
A lot of developers will get short sighted when they start working on a Sitecore project. For them the real focus is generally on the technical side of equation, thats all the cool technologies they work with and the complex code they get to write. On top of that is the constant worry of being able to deliver on time and with as few bugs as possible (believe it or not, most developers don't like seeing bugs they caused in a production environment).

The Sitecore website itself is generally not the only development work they are involved in. There are often intranets, business applications, mobile applications, services and database/business intelligence. So they are in the unique position of seeing the full puzzle technically (not just the single piece), which will often affect decisions and outcomes. For example the use of less modern front end techniques (responsive design with JavaScript libraries) due to the need to support a legacy browser (internet explorer 6) because of that one mission critical business application.

Business user

For the business user, both those who edit content on the website or other who are end-users their goals might be:
  • Empowerment on how to use Sitecore
  • Key website features are implemented
  • Stability of the platform and website
  • The website looks good
The business users are generally not the strongest technically, so when they come onto a platform like Sitecore they can often get overwhelmed at all of the features. They are generally split across a number of business units, each of which has core website functionality which they are in charge of (and worried about). Don't forget they have primary jobs that need to be completed, so if there is a large amount of content to migrate or work on, they often can't be dedicated full time like developers could.

So where is the gap between these users?

How I see the problem can occur is that the developers often won't have an end goal in site (what the vision is for the brand and website itself). They are in many cases working on minimal requirements, so end up having to fill in a lot of gaps. The marketing and sales departments place a lot of planning into where the brand is heading and like the business users know exactly what the web site needs to achieve and how it needs to do it. The business knowledge is part of their day to day work, so they assume others (developers) are aware of obscure rules which can affect functionality.

So the developers get through an agile sprint, they used what requirements they have to build out some key functionality. The design might not be all there (or there at all - quite often it comes at the end) but thats easy enough to put in later... Then the demo day comes along and marketing/business users are in there eagerly awaiting a look at the results. It inevitably comes out that there is key logic missing from a feature or perhaps an entire feature is not in the scope at all! Then theres the poor business users that are being shown how they can edit content with the experience editor, but what about the design, thats a key concern.

This all culminates in a team of developers with lists of action items that have come out of this demo. The business users are losing confidence due to all of the issues that came up, it can be obvious deadlines won't be met when the scope is getting longer and not shorter. The marketing department were on Twitter for most of the demo but noticed no fewer than 73 casing errors across the website. Okay I joke about that last one, but heres one of the major issues, a focus on content over functionality.

Content editors, whom generally aren't fully across the platform like developers (in terms of the full stack) or marketers (with knowledge of the great marketing features Sitecore has to offer). They may have been given basic content editor training, but often this is early on well before a full solution has been delivered. Quite often these editors are thrown in the deep end of a half complete solution they might not fully understand and are expected to work on large amounts of content (of varying types). The key gaps can include:
  • Not enough planning/scoping which leads to incomplete or missing features
  • No real ownership of content where developers might become the de facto owners
  • Late delivery of key design and branding elements
  • The goal posts are constantly moving which makes the project a game of catch up - this leads to less functionality overall, unless deadlines are moved as well
  • Lack of training (specific to the solution) for the content editors

Bridging the gap

  1. Set aside more time in the planning phase and include more members of various business units together. Instead of using business analysts in one-on-one environments, getting groups together in workshops are a great way to get the most information out. Everyone has a different point of view and can work together to ensure all points are covered. Later on, more detailed analysis can be performed to lock the scope down, but at least this way everyone feels they have contributed and had their thoughts heard.
  2. Nominate a knowledge area expert of the business to champion the content. This person would be across all types/areas of content of the website and would be able to work as an intermediary between other stakeholder groups. It ensures that communication lines stay intact and that someone owns the content aspect of the Sitecore implementation.
  3. Branding/design and other related templates may not always be possible to be delivered early on in a project. It's important here to share the end goal between all stakeholders and keep everyone informed. if the developers know how the site will be branded, they can work to it. If the content authors know exactly when key assets are to be delivered, they won't think the plain site in the demos is the end result.
  4. Scope creep is almost always going to happen on any technology project. If the project is run in a proper agile way, then the business can add as much functionality to the backlog as they want. It comes down to how much of that work can be achieved in the number of sprints the project has until competition. The developers are happy because they don't feel as much pressure - theres only so much work that can be allocated each sprint. The business is happy, because all of these features are listed out to be chosen by them for each sprint.
  5. The general content training at the beginning (or before) the project starts is a great way to get business users across the Sitecore CMS. The important part is to continue to share knowledge with them as the project continues along. This may be in the form of in-person training, video training or even user guides. At the end of the day, they feel empowered to use the CMS and work with all that great customisation the developers have made.
Bridging the gap between various stakeholders is a lot easier said than done, and a single article like this one isn't going to fix things overnight. Ultimately all I can do is bring the issue forward for discussion, show readers the various viewpoints and hopefully work on perceptions of the various stakeholders involved in your Sitecore implementation. This gap is of course in no way limited to Sitecore, it's right across the technology area, this is just a topic point in which I primarily work in and write about.

Friday, April 8, 2016

Sitecore Could not find configuration node: databases/database Core

While playing around in a development environment I loaded up the Sitecore admin area only to  be greeted with the error:
Could not find configuration node: databases/database[@id='core']
 It was down to a simple mistake where a new Visual Studio solution had deployed the default web.config over the Sitecore one. The fix is to restore the web.config from a backup or to get a new one off of a clean Sitecore install.

Sitecore install errors

If you are running through the Sitecore installation wizard and at the instance name step get this error:
The name you entered is not unique
It is likely due to the fact that you have previously uninstalled a Sitecore instance with the same name. To fix this error (after first ensuring a Sitecore instance does not currently exist with the given name), you will need to:

  1. Open up the registry editor (regedit)
  2. Navigate to HKEY_LOCAL_MACHINE > SOFTWARE > Wow6432Node > Sitecore CMS
  3. Then select the child item (will have a GUID for a name) where the InstanceName value is equal to that which you are trying to install and right click delete
  4. Now restart the Sitecore installation wizard
If you then get to the IIS Web Site > Create a New Web Site step and get this error:
The site name must be unique.
 Then there may still be artifacts left over from the old Sitecore installation, ensure the following items have been removed/renamed:

  • IIS Application pool
  • IIS Web Site
  • Inetpub website root
  • SQL Server databases
Once these have all been removed you will need to restart the Sitecore installation wizard.

One final error which may occur is in relation the Sitecore installation wizard attaching the databases in SQL Server. If this error occurs, firstly ensure that the databases from the previous installations have been removed and then restart the server (the computer, not SQL Server instance).

Thursday, April 7, 2016

The Sitecore community and what is available

Personally, one aspect of Sitecore of which I am particularly passionate about is the community that surrounds the platform (both online and offline). The various community channels have helped me with many Sitecore implementations and this blog (among other efforts) is one way that I try and give back. Today is going to be a writeup focusing on what is out there in terms of the Sitecore community, and what benefits they provide.

Online Community

Sitecore Forum: Available at https://community.sitecore.net/, the official forums (currently beta) are the prime location to read up on the latest Sitecore updates, as well as have a general discussion about the product. The developer section provide a medium for specific questions to be asked and usually answered, in one of the following categories:
  • Installation and Upgrading Sitecore
  • Marketplace modules
  • Official Modules and Add-Ons
  • Sitecore Commerce
  • Sitecore: Core CMS
  • xDB, Experience Marketing, and DMS
It's a budding community with many dedicated posters whom aim to assist users with any queries they may have. From my observations, there will usually be at least one response/answer to any help requests, which can provide more detail than other mediums.

Sitecore Official Blogs: There are a number of Sitecore employees whom blog about various topics on the Sitecore website. John West was one such blogger, who has since retired but I guarantee has helped each and every Sitecore developer with one of his posts. These blogs fit into three main categories:
Each provides great insight into their specific areas, and have multiple authors writing for each section. The business blogs contain posts from some of the Sitecore executive team, which can yield some great knowledge and discussion points.

Third Party Blogs: There are literally thousands of bloggers out there sharing their experiences (no pun intended) on the Sitecore platform. You will likely stumble across these when searching for an answer to a problem, using social media, or perhaps shared from friends. There are far too many blogs to list here, but feel free to mention your own in the comments below.
 
Youtube: For some people reading articles and following lists of instructions is not the best way to learn. Luckily there are a number of users who upload videos to YouTube with content relating to Sitecore. The official Sitecore YouTube channel has a number of videos which cover product features, recorded webinars, and even conference videos. Try a search over at YouTube for a Sitecore topic which interests you, and take a look at some of the well produced content available out there.

Webinars: You probably receive emails from Sitecore's marketing department about many of the great webinars they have to offer. Packed with great content across all topics and disciplines (developer, marketer, architect), these webinars are a great way to learn more about the product and provide ideas to implement on your website. The presenters are usually top notch and considered experts in their fields (such as the many great marketers who present on that area, or technical MVPs about development). These webinars are listed on the events section on the Sitecore website, and there is also a feed available here.

Stack Overflow: Perhaps one of the most important community aspects for any developer, in any CMS or language. If you are having trouble with a specific aspect in Sitecore and it doesn't warrant a ticket to Sitecore support, then Stack Overflow is a great place to visit. The collective knowledge of the users answering questions is impressive, and I find that answers will start streaming in right away. For those of you interested in becoming a Sitecore MVP, Stack Overflow is a great place to help the community out and to show you are worthy of the title. For a look at questions related to Sitecore on there, you can use the tagged with Sitecore feature.

Sitecore Marketplace: A treasure trove which contains a number of Sitecore packages (written by community members) that add functionality into the Sitecore platform. It's a great way to save on development costs and ultimately provide a better experience for your site visitors. Some of the modules which I use in a lot of Sitecore projects are for advanced workflows and Sitemap functionality. There are also some tools available here such as the Sitecore log viewer or the Sitecore Instance Manager (SIM), which is an official tool which aids in managing/deploying your Sitecore instances.

Twitter: Twitter is a popular location which is used by many of the Sitecore community for: official news, links to great content, to ask for help and to have general conversation. Sitecore has a number of accounts, as do providers of products such as Hedgehog development or your favourite Sitecore partner. Personally I find it the easiest way to stay up to date with Sitecore, and have found a number of personalities in the industry to follow.

Sitecore Slack: Slack is a collaboration tool used my many large organisations and education institutions all over the world. It allows users to join groups together (in this case the Sitecore group) and not only message, but share files, and integrate with other applications such as Skype. The application works on all platforms and devices and is a great way to get together with the Sitecore community and maybe share some Sitecore memes you might have up your sleeve.

Offline Community

Sitecore User Groups: Sitecore user groups are useful in the fact that they get like minded Sitecore users together for networking and presentations of some interesting content. They are often run and sponsored by the local Sitecore representatives, however they tend to run when there is demand, so speak to your local Sitecore contact and let them now your interested. Using Google to search for [location] Sitecore user group, is how you can find if there is an established group in your area. Dedicated Conferences: Sitecore holds a number of dedicated conferences throughout the year. Two current examples would be:
  • Sitecore Symposium: a global conference which as stated allow you to "connect with Sitecore experts, marketers, developers, partners, and customers from around the world for two full days of education, inspiration and so much more". I hope to see you there!
  • Sitecore User Group Conference (SUGCON): Is a users organised conference which "will be packed with the latest insights and advice from some of the most experienced, skillful Sitecore experts in the world, both from Sitecore and the community."
Industry Conferences: Sitecore is often a presenter, sponsor and booth holder at many industry conferences all over the world. A recent example would be MarTech 2016 where Sitecore held a booth and their CMO Scott Anderson made a presentation. The best place to follow what conferences and other events Sitecore will be represented at is by following them on Twitter or visiting their events page.
 
Sitecore Hackathon: This competition sponsored by Sitecore aims to have teams of three competing from all over the world to implement a Sitecore feature over a weekend. It's a great way to build up competition among Sitecore developers worldwide and also to get some great new features entered into the community.

Conclusion

There really is a lot of community support out there available for the Sitecore Experience Platform, and the dedication by those who invest their time into it shows how the product is at the front of a lot of peoples minds. If you think I have missed any community aspects in this post, or want to plug your own site, feel free to in the comments below.

Wednesday, April 6, 2016

How to give Sitecore sublayouts and renderings custom thumbnails

Where possible, it's nice to configure Sitecore in a way that makes it easier for the content authors to use the system. One such way is to provide custom thumbnails for any sublayouts or renderings (instead of the standard blue rectangle). The main benefit here is that it helps content authors to distinguish between the many sublayouts or renderings available and also gives them a preview of what it looks like.

Tuesday, April 5, 2016

Woff2 font giving 404 error in console

If you are using a font face which has the extension of woff2, by default users may get a 404 error when attempting to access the resource. The MIME type for woff2 will need to be added to IIS for the website. This can be done as follows:

Monday, April 4, 2016

Custom workflow actions in Sitecore

Simple workflows (content approval with rejection for example) in Sitecore can be achieved out of the box, and there are also modules such as Dynamic Workflow for more complex solutions. However there are cases where there is need to create a custom action (perhaps for a more advanced emailer with HTML templates and other advanced logic), this can be achieved with the following code: