Custom Theme MVC View Engine for Sitecore Multisite Implementation

Custom MVC view engine for extending theming in the MVC application is a well discussed topic. You will find it in many discussion forums and in many blog posts. The problem in question is, how can you extend the theme of your MVC application from a base theme, so that if you want to extend certain pages in your application, the child page should override the base page. The most well known solution is to create your own View Engine with ordered view and partial view locations and Insert your View Engine as the first item in the View Engine collection. This way MVC will find your View Engine first and find the views as you desire. Here are some code example.

    public class CustomViewEngine : RazorViewEngine
    {
        public CustomViewEngine()
        {
            var themeName = ConfigurationManager.AppSettings["ThemeName"];
            var baseThemeName = ConfigurationManager.AppSettings["BaseThemeName"];
            Assert.ArgumentNotNullOrEmpty(baseThemeName, "BaseThemeName");
            if (!String.IsNullOrWhiteSpace(themeName))
            {
                ViewLocationFormats = new string[] { "~/Themes/" + themeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + themeName + "/Views/Shared/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };
                PartialViewLocationFormats = new string[] { "~/Themes/" + themeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + themeName + "/Views/Shared/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };
            }
            else
            {
                ViewLocationFormats = new string[] { "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };
                PartialViewLocationFormats = new string[] { "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };
            }
        }
    }

If the ThemeName is not empty, then ViewLocationFormats and PartialViewLOcationFormats contains the ThemeName folders path first on the order and then the BaseThemeName folder path. That ensures, when there is a view available in the ThemeName path, that will be rendered, otherwise, the view from the BaseThemeName path will be rendered.

Now we have to add this custom view engine to the View Engine collection.

ViewEngines.Engines.Insert(0,new CustomViewEngine());

Usually you will do this in global.asax Application_Start event method or  WebActivator’s PreApplicationStartMethod.

This works fine, when you have developed a base website and then you customize that website for many implementation. But, at a time you have only one site.

Now, consider this situation, when you have to implement multiple sites in the same Sitecore instance and each site can have a different theming from the base theme. In this case, you will have multiple theme folders and those folders can contain the same views or partial views. If you add all these theme folders in the view location, MVC will render the one that is on top in the order, not the one that you intend it to do. How to solve this problem?

First of all, we need to know what’s the correct theme for a site in the multisite scenario. This is not difficult. We just put the theme name in the SiteDefinition.config in the site node as custom attribute ‘themName’, like below.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <sites>
      <site name="site1" patch:before="site[@name='website']" 				 enableTracking="true" 				 hostName="site1.com"          virtualFolder="/" 				 physicalFolder="/" 				 rootPath="/sitecore/content/site1" 				 startItem="/home" 				 database="web" 				 domain="extranet" 				 allowDebug="true" 				 cacheHtml="true" 				 htmlCacheSize="50MB" 				 registryCacheSize="0" 				 viewStateCacheSize="0" 				 xslCacheSize="25MB" 				 filteredItemsCacheSize="10MB" 				 enablePreview="true" 				 enableWebEdit="true" 				 enableDebugger="true" 				 disableClientData="false" 				 cacheRenderingParameters="true" 				 renderingParametersCacheSize="10MB"          themeName="site1theme"     />
      <site name="site2" patch:before="site[@name='website']" 				 enableTracking="true" 				 hostName="site2.com"          virtualFolder="/" 				 physicalFolder="/" 				 rootPath="/sitecore/content/site2" 				 startItem="/home" 				 database="web" 				 domain="extranet" 				 allowDebug="true" 				 cacheHtml="true" 				 htmlCacheSize="50MB" 				 registryCacheSize="0" 				 viewStateCacheSize="0" 				 xslCacheSize="25MB" 				 filteredItemsCacheSize="10MB" 				 enablePreview="true" 				 enableWebEdit="true" 				 enableDebugger="true" 				 disableClientData="false" 				 cacheRenderingParameters="true" 				 renderingParametersCacheSize="10MB"          themeName="site2theme"     />
    </sites>
  </sitecore>
</configuration>

We need to override two methods FindView and FindPartialView in our custom view engine. In these methods, we need to read the themName for the site in the current sitecore context and return the appropriate view ViewEngineResult.

    public class CustomViewEngine : RazorViewEngine
    {
        public CustomViewEngine()
        {
            var baseThemeName = ConfigurationManager.AppSettings["BaseThemeName"];
            Assert.ArgumentNotNullOrEmpty(baseThemeName, "BaseThemeName");
                ViewLocationFormats = new string[] { "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };
                PartialViewLocationFormats = new string[] { "~/Themes/" + baseThemeName + "/Views/{1}/{0}.cshtml", "~/Themes/" + baseThemeName + "/Views/Shared/{0}.cshtml" };
        }

        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            if (controllerContext == null)
                throw new ArgumentNullException(nameof(controllerContext));
            if (string.IsNullOrEmpty(viewName))
                throw new ArgumentException("viewName");
            var currentSite = Sitecore.Context.Site;
            var themeName = currentSite.Properties["themeName"];
            string controllerName = controllerContext.RouteData.GetRequiredString("controller");
            if (!string.IsNullOrEmpty(themeName) && !viewName.Contains("/"))
            {
                var viewPath = $"~/themes/{themeName}/views/{controllerName}/{viewName}.cshtml";
                //If the view file doesn't exists in the folder look at the shared folder
                var absolutePath = HttpContext.Current.Server.MapPath(viewPath);
                if (!System.IO.File.Exists(absolutePath))
                {
                    viewPath = $"~/themes/{themeName}/views/shared/{viewName}.cshtml";
                    absolutePath = HttpContext.Current.Server.MapPath(viewPath);
                    if (!System.IO.File.Exists(absolutePath))
                    {
                        throw new Exception(string.Format("View {0} doesn't exists.", viewName));
                    }
                }
                return new ViewEngineResult(this.CreateView(controllerContext, viewPath, string.Empty), (IViewEngine)this);
            }
            return base.FindView(controllerContext, viewName, masterName, useCache);
        }

        public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            if (controllerContext == null)
                throw new ArgumentNullException(nameof(controllerContext));
            if (string.IsNullOrEmpty(partialViewName))
                throw new ArgumentException("partialViewName");
            var currentSite = Sitecore.Context.Site;
            var themeName = currentSite.Properties["themeName"];
            string controllerName = controllerContext.RouteData.GetRequiredString("controller");
            if (!string.IsNullOrEmpty(themeName) && !partialViewName.Contains("/"))
            {
                var partilaViewPath = $"~/themes/{themeName}/views/{controllerName}/{partialViewName}.cshtml";
                //If the view file doesn't exists in the folder look at the shared folder
                var absolutePath = HttpContext.Current.Server.MapPath(partilaViewPath);
                if (!System.IO.File.Exists(absolutePath))
                {
                    partilaViewPath = $"~/themes/{themeName}/views/shared/{partialViewName}.cshtml";
                    absolutePath = HttpContext.Current.Server.MapPath(partilaViewPath);
                    if (!System.IO.File.Exists(absolutePath))
                    {
                        throw new Exception(string.Format("View {0} doesn't exists.", partialViewName));
                    }
                }
                return new ViewEngineResult(this.CreatePartialView(controllerContext, partilaViewPath), (IViewEngine)this);
            }
            return base.FindPartialView(controllerContext, partialViewName, useCache);
        }

    }

That’s it! Happy coding.

Posted in MVC, Sitecore | Tagged , | 1 Comment

Inbound Marketing with Sitecore – Social Media

In the last blog post, I discussed about importance of engagement in SEO. One of many ways to engage users to the site is to use social media. In this blog post, we will talk about role of social media in Inbound Marketing and how Sitecore can help with including social media in a Sitecore implementation.

Let’s start with some statistics to understand why social media is so important for Inbound Marketing.

  • There are more than 2 billion social media users worldwide
  • In 2016 68.3% internet users are social media users
  • 9 out of 10 US business actively use social media
  • 1 in every 5 page views in internet is Facebook

I can go on and on with more statistics but, it suffices to say from the above,  businesses have to include social media in the core  strategy.

Social Media Strategy

For effectively amplifying the content in social media, there need to have a clear strategy. Here are few things, that we need to consider for creating a solid strategy

  • Choosing an appropriate social media platform is very important. We need to look at the buyer’s personas of the company to understand which social media platform is most effective to amplify the content. For example, if your company is in professional services, LiknedIn is a good choice, whereas, if you sale products, Facebook might be mpre appropriate platform.
  • If you are using multiple social media platforms, the buyer’s personas can be quite different from one platform to other. In this case you need to optimize the content on the basis of what social media we are using.
  • There need to have a clear measurable and attainable goal. We need to set goal on how many content will be shared, how many  unique visits we want to achieve from social media and how many of visitors we would like to see converted. This will be useful to understand the ROI.
  • The content that will shared in the social media should be consistent towards establishing the brand of the company. Content should be written such a way so that, users recognize the brand at a glance. This will have lasting effect on users and they will come back to the site repeatedly.
  • It was found that content with relevant images get 94% more views than content without relevant images. Images and videos can help you reach to bigger audience. You can use site like Cavana or Pablo to create visual images for your content that you share in the social media.
  • Find the optimum time to publish your posts on the social media. If your audience is teenagers, good time to publish the post maybe after 3 afternoon because that’s when the school breaks. But, if the audience is middle aged people, maybe the best time is evening 7 o’clock.
  • Finally, all social media provides analytics data to understand user engagement. For example, following is a screenshot of analytics data from my Twitter account. You can use data from social media to understand user engagement to your site and contents.

Twitter Analytics

Integration with Social Media

There are three different ways a website can be integrated with a social media platform.

  • Content can be shared by placing social media button on the web page. In this case if the user click on the social media button the content will show up on the wall in the social media site.
  • Site can use social media to authenticate to your website. In this case you can access users social media profile and learn more about their activities in the social media.
  • Most companies have their own social media pages. Users may consider to follow the company in the social media and that way visit to website contents directly from the social media pages.

Sitecore Social Experience

Sitecore currently provides two options to integrate with social media.

  • Komfo – Komfo is a Danish company with Social Media Marketing Suite of products that let you publish, listen, monitor and analyse social media data. Sitecore Komfo connector let you connect to social media using your Komfo accounts and manage and harvest the social media data from within Sitcore. The social media campaigns can be tracked Sitecore Experience Profile. Access of users social activities enable Sitecore to personalize users experience in the website. Based on users activities captured in the experience database, targeted ads can be published to social media through Komfo connection.
  •  Sitecore Social Connect – Sitecore Social Connect is a in-built social media connector in Sitecore that let you communicate with social media platform Facebook, Twitter, LinkedIn and Google+. The API can be used to authenticate to the social media. You can import the user data from social media to Sitecore Experience Database and use that for personalization purpose. You can publish content to social media channels from Sitecore. This is a free option.

Besides the above two options for social integration, Sitecore also integrates with Telligent Community application. But, Telligent is not for mainstream social media platforms, it is to create a social community for customers of a company or employees within a company. Sitecore integration with Telligent let you analyse and personalize the website for you customer or employees.

As mentioned in the last post social media conversation helps with SEO too as user engagement is one of the factors in SEO ranking. So social media staregy is extremely imporatant for lead generation in Inbound Marketing.  Social media is innovating and changing everyday, marketing has to keep up with that. We hope to see innovations in Sitecore too to keep up with social media changes.

References

Sitecore Social Marketing Experience

Posted in Uncategorized | Leave a comment

Inbound Marketing with Sitecore – SEO

The first step of Inbound Marketing Methodology is to attract people to the website or to content they are looking for. How people are going to try to find contents that they are trying to find out? If I ask this question to someone today, most people will say , ‘I will google it’.

Here are some data from my own blog. For the month of September 2016, there were 1024 visits to my blog site. Out of that 1024 visits, 645 came from Search Engines, that is 63% of total visit. It’s also noticeable that most people searched in Google and so if I keep our SEO best practices discussion around Google, we should be able to cover most important topics.

Site Stats

Site Stats

Not to brag about my blog but, this gives us some idea about, how important it is to use SEO properly. Currently search engines reach 67% of the US population and 98% of the US browsing population. Any website with good attention to SEO will show advantages as far as Inbound Marketing is concerned.

In this blog article, I will discuss implementation of SEO for websites built on Sitecore. There will be lots discussion about SEO best practices. Sitecore will be discussed at the end. I will discuss about Sitecore information architecture and Sitecore tools that can help us to  apply the SEO best practices in a Sitecore implementation project.

We should keep in mind that, Google is always changing the search engine algorithms, something relevant today, may not be entirely relevant tomorrow. My focus in this article is to provide the information that will help someone to understand SEO in the context of Inbound Marketing and how to implement those SEO best practices in Sitecore.

What happens when we search in Google? Google algorithm search through the indexed documents and try to find out best possible match for the search criteria. How that works? Here is a short video by Matt Cutts on how Google search works.

In addition to finding the best content, Google also try to present the search data in many interesting ways to intrigue users. As much as it is important to understand how search works, it also important to understand how Google present search results. Each search result Google shows is called a snippet. Understanding snippet will help us to understand where Google find these snippet information and hence we will be using that to intrigue our buyer personas to attract them to our website. Again, here is a video by Matt Cutts where he explained result snippets.

The video is little old, but it is still relevant. Google, since has added many more interesting features to its search presentation. For best SEO result for the Inbound Marketing, there are two things that are most important, 1) achieving high search ranking and 2) achieving high click through rate by proper use of Google’s presentation features. Let’s dive into our journey.

Domain Name Selection

Good strategy for SEO starts from very beginning of the project. What’s going to be the domain name of the website? It is important to put some thought on that, because domain trust is important for SEO. When it comes to choose domain name, consider following

  • The domain can be based on brand name or based on keyword. Google value the brand name. Having the EMD (Exact Match Domain) in the domain name doesn’t affect ranking in Google but, it might help with other search engine. From the SEO perspective it is best bet to establish a brand name for the long run. In the Sitecore world most of the time the implementations are for some sort of business and having a brand name makes sense.
  • What about domain extensions? Google doesn’t give any preference to any domain name extensions but Bing does. In bing .com gets the preference. The .com extension is most popular and most desirable to searchers. Getting a .com may help a bit more than other domain name extensions.
  • Keep your domain name length less than 15 characters. Shorter domain name is easy to remember, easy to share and less chance of typos.
  • Avoid using too many hyphens in the domain name. Sometime using hyphen helps if you are using keyword driven domain name, but in general avoiding keyword in the domain name is a good practice.
  • If  you are looking to register a domain name and you find a domain name that matches with your brand was already register, it might be beneficial if you can acquire that domain name. Old domain name might get a better search ranking because of the trust it already built with the search engine. You can check the trust of the domain using Majestic SEO and power of the domain by using Moz’s Open Site Explorer site rating. I discussed these two tools in later section. Also, it doesn’t make sense to acquire domain name which doesn’t close to your brand. Some sites you can use to check for the old domain name are SEDO, GoDaddy Auction, AfterNic, DomainTools.
  • There are some good domain name generator tools out there which you can use to help you with deciding a domain name. Check out panabee.com, psychicwhois.com.

Content writing for effective SEO

It’s a cliche but, I will say it, Content is the King. It is a misconception that content is the only thing that Google considers for the ranking. What Google’s aim is, to find out how trustworthy the content is and for that it needs to also look at the engagement. We will talk more about this later. But, quality of the content is really important. How do we create quality content?

  • Most Important thing to remember about optimizing content for search engine is that, you are creating your content for the readers and it should be optimized for the readers. If you focus too hard for the good search ranking of your content, you may fail to deliver the message effectively to the target consumer of your content. Being said that, you want your readers or Buyer Personas to find out your content and for that you need to think about how the Buyer Personas will search for the content, what keywords they will use. We will discuss about how to choose good keywords, in the next section.
  • When it comes to quality of content, Google doesn’t look at only one page of the website. Google looks at the whole domain to determine the authority and reputation of the website. What determines Authoritative Content for the search engine? Trust. More the content cites trusted sources, linked by trusted sources, published in trusted sources, written or reviewed by trusted author, more is the authority of the content. Google determines the Reputation of content by measuring the user engagement with the content. Some of the criteria Google looks at are, bounce rate (how much time user is spending on the content), social sharing metrics, website performance, user’s trust on the website etc. Using Magestic SEO, we can measure the Trust Flow and Citation Flow of a website. So before using link to a source website or approach someone to link to your content, the trust can be measured using Magestic SEO. Here is an example of Trust and Citation flow for Wikipedia.com.
    Magestic SEO
  • Use clearly descriptive and concise anchor text so that, user and google understand what page the link is navigating to. Make sure the anchor text can be differentiated from regular text so that, users don’t miss it or accidentally click on it. Use anchor text for linking internal pages too so that, user and google can navigate to different part of the site naturally. Do not go overboard with internal linking. Only relevant internal links should be placed.
  • I mentioned before, Google checks the bounce rates to determine engagement with the content. It is important to write content that can be read easily. Use short sentences. Try to keep in 15 to 20 words. Keep the paragraph short. Use a structured layout for the content. Discuss different topics in different section of the content.

Keyword Research

There is a myth that, keyword research for SEO is useless. It was proven by many case studies that finding out good keywords helps with search ranking. Google will eventually crawl the content but, with so many contents out there, choice of right keyword will help with staying ahead of the competition.

  • Keywords or phrases are search terms that users search to find information they are looking for. Predicting the search term or the keywords, that will be entered by readers of the your contents is extremely important for the search ranking of your web pages or blog posts. Start with a list of 10 keywords for your content and use a Keyword research tool like SERPs Keyword Research Database to see the competition for the keywords in google. You can use rank checker SERPs Keyword Rank Checker to see how the websites are ranking based on the keyword you have used.
  • Instead of using short keywords, use long tailed keywords, which will have more probability to give you better ranking because short keywords will be there in most sites. For example, instead of ‘Carbonator Motor’, use something ‘Carbonator Motor for Soda’ if you are writing about that kind of motor.
  • When it comes to choose keywords for a content, first choose an appropriate Primary Keyword. Then select some supportive keywords. You need supportive keywords for placements in the page. You may want to put the primary keyword in the content and the supportive keywords in the Title of the page and in the URL. Supportive keywords helps to avoid over optimizing contents. Google Adsense is a great tool for finding supportive keywords.
  • There is no need to add keywords in the Meta Keyword tag. Google doesn’t use Meta Keyword at all for ranking.
  • Bolding words using <strong> or <b> element doesn’t help with search ranking. It helps users to read the article, if you want to emphasis certain words in your content. That way it helps with engagement. Same is true for <h1> and other heading tags.
  • Keyword density in a content is something you should be aware of. Using keywords too many time in the content can cause over optimization and that can hurt search ranking. Recommended number of keywords in the page should be between 3 to 7.

Engagements

Search Engine’s ultimate goal is to provide contents that people would like to see. How do the search engine know if people woud like a content? The answer is, by monitoring the conversation. It’s like real life, when we like a book, we talk about it with our friends, spread the word. Similarly more the content reach to more people, via different channels like, blogs, social media, email etc., it indicates more people liking, more conversation. So, quality content is not the only thing that matters for search ranking. How people are engaging with the content and how the content is getting distributed is something that search engine looks at today.

If the content is good and it becomes popular, more people will link to the content. Google search ranking consider this as a factor for search ranking. The dark side of ranking based on links from other sites is that, people try to game the system. Tell bunch of people to write some content and link to their site with the sole purpose to game Google search algorithm. Google doesn’t like it and there are many incidents where Google penalized websites for trying to game the system. You will find some examples here .

Whether you are linking to some source content or someone is linking to your content, it is important that those links have high trust value. A good place to check the trust of a link is to use Majestic SEO website as we discussed before in this article.

Listing the site in the directories can improve the search ranking but you need to be careful about the quality of the directory service and you need to have right strategy to implement this for your website. Here is a nice article about directory listing.

One thing to consider about link building is that, the link building should naturally grow. It’s not natural that we write a content today and hundreds of sites immediately linking to the content. If that happens, Google will consider that as suspicious.

Guest Blogging can help with search ranking but, you need to be careful because, guest blogging is only effective if it helps building the trust. First of all, the content written by guest blogger should be relevant and quality content. You should use guest blogger who has acquired some authoritative trust from Google. If you have a circle of quality blogger writing on the common interest, it will help with engagement for the community, which helps adding popularity for the content. When it comes to distributing the content, it can be distributed through different medium like, infographics, ebook, audio, video etc.

Since search ranking is influenced by the engagement towards the content. Distributing content through social media is important. Always use social sharing icon in the article. Have social networking accounts for the business and make sure the sites are publicly viewable.

Search Result Presentation

Search result presentation is as important as search result ranking. It often happens that user clicks on the third ranked search result because it’s snippet is showing some text that are relevant to the search.

Title

What we add in the <title> tag of the page shows up as the title in the search result.

  • Choose a title of the page that describes the content of the page accurately.
  • Don’t use the exact target keyword in the title. Google penalize websites that tries to over optimizing for search engines. We discussed about the Primary Keyword and Supportive Keywords. It is preferable to use a Supportive Keyword for the title.
  • Don’t use same title for multiple pages in the site. Search engine consider duplicate titles as malformed and penalize.
  • Use short descriptive title. There is a fair chance that title will be truncated after 62 characters. Shorter title has higher click through rates.

Meta Tag Description

Adding text in the meta tag description gives you a chance to show the user what you want to convey about the content. If the text is relevant to what user is searching, there is a fair chance that Google will use that. If there is no meta tag description, Google will look at the content and construct the snippet. Google may also look at the open directory for the snippet text.

  • You can tell google to not to look at open directory by using <meta name=”robots” content=”noodp, noydir”>
  • Accurately describe the page. Meta tag description run about 155 characters. User will look at this snippet and decide whether the actual content has information they are looking for. It is very important to use the words wisely to attract the users to your content.
  • Use unique description for each page. If there are huge number of pages it is better to automate the creation of meta tag description. For example, for a ecommerce site there can be thousands of products. In this case meta tag description of product detail page can be built from product description. This is true for title too.

Structured Data Markup

The Structured Data Markup is an effort by internet community to organize data in a standard structured way to present the data to online visitors. The Structured Data Markup schemas are available in schemas.org. Every website has some sort of structure data. For example, if the website is a travel site, it can provide Structured Data Markup of type ‘Place’. If website provides Structured Data, Google and other search engine might present that data in a interesting way along with the search result. For example, if I search for Norah Jones, along with the Norah Jones’s site link in the search result, Google also show the event information tothe right.

Structure Data are mostly presented  in JSON-LD (JavaScript Object Notation for Linked Data) format. Following is an example of structured Data of type ‘Product’ in JSON-LD format.

{
“@context”: “http://www.schema.org&#8221;,
“@type”: “product”,
“brand”: “Canon”,
“name”: “5D Mark III”,
“image”:             “https://shop.usa.canon.com/wcsstore/24461_1_xl.jpg&#8221;,
“description”: “Great SLR Camera”,
“aggregateRating”: {
“@type”: “aggregateRating”,
“ratingValue”: “4.5”,
“reviewCount”: “456”
}
}

In web page, Structured Data needs to be included in header section within script tag as above example. Structured Data don’t help increasing search ranking but definitely help with the click through rate. To find some examples of Structured Data in Google, you may search for some recipes and you will see the Structured Data about recipes presented with images, ratings etc. To see what Structured Data is included in the site,  use Google’s Structured Data testing tool. Entering the website Url will show the Structured Data in nice format. If the Structured Data is one of the qualifying content type, Google will show them in rich snippets. You can learn more about Structured Data here .

Other Important Topics

There are many other aspects of website either help with the ranking or click through rate directly or indirectly. Let’s discuss them.

URL

  • Simple-to-understand url helps user and search engine to understand the url and return effective result. Google returns the url as part of the search result snippet. If the url is simple, it is easy for the user to remember and increase the probability that user will visit the same page again.
  • Choose Url with words relevant to content. We talked about supporting keywords. Using a supporting keyword is a good idea.
  • Create simple directory structure. For example, all product detail page should show url like, http://example.com/products/skunumber. Avoid deep directory structure and directory name not relevant to the content.
  • Use one version of url in the site. If you have old version of url that users are still using, use 301 (permanent redirect) or 302 redirect to redirect old url to the new url. If you know that the old url will never be used again use 301. If you feel that old url can come back in future use 302.
  • If you have deleted a page completely and there is no alternative page for that, the URL will be broken and the web server will return 404, page not found. If you know the content is deleted forever, you should return 410, that will tell google that this content was deleted and Google will remove that from the index.
  • Use lower case in url. It is easy for users to remember.

Canonical URL

Use Canonical link element when there are more than one version of the same content. The canonical link tells search engine which link to consider for ranking when even the visitor lands to a different version of the page. The canonical element is declared like <link rel=”canonical” href=”http://example.com/canonical-example/”&gt;. Even when there is only one version of the page, we should use canonical element because the same page can be rendered when there different parameters included in the URL. Google also considers self referencing of a URL in the canonical link as the best practice. If there are duplicate pages in the site instead of using canonical link, you should remove the page and use 301 redirect. You should be careful about the canonical link. If the canonical link is not a valid link the search ranking can affect severely.

Site Navigation

  • Navigation should be simple to understand for user and have naturally flowing hierarchy.
  • Use text navigation mostly and avoid image, animation link as much as possible.
  • Create a simple html site map page for user and a XML site map file for search engine.
  • Use custom 404 page to provide friendly message to user in case user come across a link or page that doesn’t exists.

Image Optimization

  • Always use a descriptive alt text for image. This will help your image to be added in the google image search. If the image is used used for linking, alt text will be used like anchor tag.
  • Use distinct name for each image.
  • Store images in one website folder than creating multiple folder hierarchy to store images. In case of Sitecore images are stored in the media library. Make sure the media library path is simple.
  • Use right image type (jpg, png etc.) in the image file name.
  • If there are numerous images in the website, include a image sitemap file. The format of the image similar to XML Sitemap file.

XML Sitemap

A Sitemap is a XML file that describes the structure of the site. Search engines can use it to find out pages/images/videos to crawl. There are some debates if Sitemap file is needed for Google to find out the pages of the site. It is true that Google can find out and crawl pages even if the Sitemap file doesn’t exists but, Google highly recommends to have Sitemap file for several good reason.

  • If the site is too large, it is possible that some of the pages will be overlooked because those pages are not linked from other places in the site.
  • The site is an online ecommerce site with huge number of products. It is quite obvious that Google will not find all the product url and will not index.
  • If the site is new and it is not linked by external site, Google wouldn’t find it.
  • If there are archived pages in the site and if the pages are not naturally linked to each other, Google will overlook those pages.
  • Other than the location of pages, Sitemap also provides meta data information like, when the page was last updated, how often this page changes, what is the importance of the page compared to other pages etc. These information helps Google with crawling and indexing.

There is a limit for the Sitemap file size. A Sitemap file can be at most 50 MB uncompressed and can have less than 50,000 urls. After that you have to create multiple Sitemap files. There are two different ways you can let Google know about the Sitemap:
Submit it to Google using search console Sitemap tool or add the Sitemap file location in the robot.txt like, ‘Sitemap: http://example.com/sitemap_location.xml&#8217;.

Following is an example of a Sitemap that contains only one URL.

Sitemap

Block Content from Search Engine

Sometime you don’t want some content to show up in the search result. Typically we want to exclude content that contains private information of customers or users. There are several ways to prevent content from search crawler.

  • If the site is designed with authentication, Google will not be able to get to the content. If authentication is not there, best way protect content is to password protect the folders.
  • If it is not matter of privacy, but we don’t want the search engine to not crawl certain areas of the application, we can use robot.txt. Typically, we don’t want search engine to crawl files like images, stylesheets, scripts etc. Doing this will save resources for both the website and for the search engine. Remember, excluding files using robot.txt, will not protect files from showing up in the search result. Files can still be crawled, if the files are linked from other places, which were not added in robot.txt. Learn more about robot.txt from Google.
  • NoIndex and NoFollow – noindex is used in the robot meta tag, search engine will drop that link or page from the index. It is a week way to prevent a content because sometime we may forget to add this and as a result content will show up in the search result.
    Setting nofollow will tell google to not to crawl any link in that page. There are times we want to put a link on the site but don’t want to pass the reputation. For example, we are putting some website links which we know are are not quality site. In this case we would like search engine to not follow the link because it might hurt the reputation.
    Here is how we should use nofollow and noindex for all the links in the page,<meta name=”robots” content=”noindex, nofollow”>If you want not to index a specific link in the page you can use NoFollow in the link element like below<a href=”http://example.com/nofollow.html&#8221; rel=”nofollow”>nofollow link</a>

SSL

Does having SSL helps in search ranking? It’s hard measure if it helps, but Google says so.
There are definitely some advantages besides the search ranking.

  • Having https in the site provides a sense of security to visitors and it
    protects visitors’ communication with the site and protects site from the ‘man in the middle’ attack.
  • Without https, when users come to your site from a https site, you will not see the referring site and that is an analytical disadvantage.
  • When you move to https, we should update links in sitemaps, resgister https link in Google webmaster tools and make sure to use 301 redirect to redirect http links to https links.
  • It is preferable to use HTTP Strict Transport Security (HSTS). This will remove the requirement of 301 redirect and speed up the application performance.

Website performance and Uptime

Website performance can hurt the search ranking.  Google devalue website, if performance is bad. There are many ways you can achieve the best performance of the website, one of them is to use caching efficiently. You should also be careful about the javascript used in the website. It is a good idea to include script at the end of the webpage for the efficient loading of the page. Careful about using social button and third party javascript because they can hurt the performance if the sites they connect to have performance issues.

The quality of the website suffers in the eyes of search engine if website crashes or hangs. If pages are moved or deleted, use 301 redirect to appropriate page or use status code 410 to let Google know the page was deleted permanently.

Sitecore Information Architecture Consideration for SEO

One of the biggest challenge of SEO implementation is to constantly  maintain and follow the SEO best practices for the site. A proper Sitecore information architecture can help with this significantly in regards to ease the implementation and enforce the best practices.

SEO Template

To support and enforce SEO for any Sitecore project, I suggest to create a SEO template and include this SEO template as one of the parent templates of the page template. The SEO template can contain following fields.

SEO Template

 

  • The Title contains the title of the page that gets placed between <title> element of the page and shows up in the Google snippets title. You should consider to use a supportive keyword for Title to prevent the page from over optimization.
  • Meta description is the field where you want to add the summary of the content. This will be displayed in the Google snippet summary, if Google finds it suitable.
  • Url field is to add the keywords you want to see in the page Url. By default Sitecore Link Manager generates the Url from the item name. But, as we discussed before, it is good idea to use a supportive keyword for Url to properly optimize the page. It also gives an opportunity to the content editor to change the Url after the items are created. To use this Url field to generate Url of pages, you need to create a custom link Provider. One word of caution about using this separate Url field is that, you should not change the Url field frequently, because, once site goes live, the Url will be indexed by search engine and people will start using it. If you change the Url, the old link will be broken. In case you need to change the Url, you should use 301 redirect for the old Url.
  • I discussed before about the Structured Data Markup and how it helps presenting the result in Google search. If the website presenting content that qualifies the Structured Data Markup types, it is highly recommended to use Structured Data in the SEO items and generate the JSON-LD script to add in the page head section.

SEO Field Validation

Sitecore allows you to apply validation to the fields of a template through field validation rules. There are many validation available in the base product as shown below. You can also create custom validation rules.

Sitecore Validation Rules

You can select a validation rules for the SEO fields to enforce good SEO practices. Here, I selected the required and Max Length 40 for the Title field.

Sitecore Validation Rules

When I create an Item that doesn’t satisfy the validation rule, Sitecore will show the indicator and message that the item has some validation failure. Like below it is showing on the Quick Bar on the left and next to the item field.

Validation Result

Validation rule can also be run from the Review panel in the content editor.

You can create some custom validation rules like, the Title field and Url field cannot contain the same text. This will ensure SEO optimization rules.

Image Optimization for SEO

In Sitecore the images are saved in Media Library. When images are access for a web page Sitecore will render images using ASHX handler. In the Media Library item for a image there several fields you can enter values. One of them is Alt in the Image section for Alt Text. This field has validation and shows red line when no text is entered. Below is an example.

sitecore media image

The Sitemap generator mentioned below can be extended to generate Sitemap XML for all images used in the website.

Sitecore Experience Accelerator (SXA)

Sitecore Experience Accelerator (SXA) is newly added module in the latest version of Sitecore. SXA has some neat features to improve SEO. You can enter the title and meta description for page items. It does have a field for meta keywords, which has no effect on search ranking. The nicest feature in SXA is, you can enter the Sitemap data in the page item and generate the Sitemap file for the website. Learn more  about how to Improve page SEO in SXA.

Sitecore Tools for SEO

There bunch of tools available in Sitecore Marketplace, can be useful for SEO implementation.

301 Redirect Module
There two 301 redirect modules available in Sitecore Marketplace. These modules provide varieties of feature for 301 redirect.

https://marketplace.sitecore.net/Modules/U/Url_Rewrite.aspx?sc_lang=en
https://marketplace.sitecore.net/Modules/301_Redirect_module.aspx?sc_lang=en

Sitemap Generator
Checkout the following Sitemap generator modules.

https://marketplace.sitecore.net/en/Modules/XML_Sitemap_Generator.aspx
https://marketplace.sitecore.net/en/Modules/Sitemap_XML.aspx

Sitecore SEO Toolkit
Sitecore has a free SEO toolkit that can be useful to evaluate SEO related problems in the page content. The SEO toolkit can be integrated with third party APIs for keyword suggestion and content analysis functionality. This tool was not updated recently as per the newer version of Sitecore. You might face some issues if you are using Sitecore version 8.0 or up.

https://sdn.sitecore.net/Products/Seo%20Toolkit.aspx

Final Thoughts

In this article I tried to cover most of the important best practices of SEO. Hopefully, this will help marketers and developers to understand SEO in the context of Inbound Marketing and how to use Sitecore efficiently to achieve the SEO goals. As a platform Sitecore is very flexible and extensible. There are opportunities of creating many more tools to help with SEO implementation for Sitecore projects. I have plans to create some tools and I am looking forward to see more efforts from the community.

Posted in Inbound Marketing, SEO, Sitecore | Tagged , , , | Leave a comment

Inbound Marketing with Sitecore – What is Inbound Marketing

This morning when I woke up it was still dark. I turned on the light on the corridor, the light flickered and everything dark again. This has been happening lately with that light switch. I took a mental note, I need to change this switch today.

I made my first cup of tea and sat on the computer to do some research to find out how to change that faulty light switch. I wouldn’t call an electrician to fix one light switch, it will cost too much. So, I entered “How to replace a light switch” in Google search. Following is the screenshot of first few search results.

Inbound-pic1

I could click on the first result, instead of that I clicked on the second one. Why? The reason is, the second one says that, the video was created by Home Depot, where, I probably will go and buy things that I need to replace the switch. This video very clearly tells me what I need to know before I go to the store and what I need to tell the store assistant if I need help. Home depot won me as a customer.

Inbound Marketing vs Traditional Marketing
The above is an example of Inbound Marketing which is transforming the way world is doing business, a phenomenon that is making the traditional marketing obsolete. Let’s think about how traditional marketing works. The methodology of traditional marketing is to push (I prefer the word shove) the information to us by making cold call, TV Advertising, sending print mails and several other things that we don’t want at all. Think for a moment, how we prefer to get information today. We prefer to find information when we want it and someone sending us the information that we don’t want to hear, that we feel is a disruption. The technology flipped the world of marketing from marketer-centric to customer-centric.

Buyer Personas and Buyer’s Journey
The Inbound Marketing is centered around two very important things, Buyer Personas and Buyer’s Journey. The Buyer Personas define the target customers for the website or business. Understanding Buyer Personas is important because only then we can create the meaningful content to attract right traffic to the site. The Buyer Personas can be defined through research and analysis and finding out more from existing customers. The Buyer’s Journey on the other hand is the path that a Buyer takes to become a customer. There are three different stages of Buyer’s Journey.

Awareness Stage: In this stage, the prospect is having some problem and he/she is trying to understand what the problem is, through some research.

Consideration Stage: In this stage the prospect knows what the problem is and now he/she is looking for available solutions.

Decision Stage: In this stage the prospected is aware of the possible solutions of the problem and he/she is going to select a solution.

Inbound Marketing Methodology
The word Inbound Marketing was first coined by Brian Halligan, the CEO of Hubspot. The Inbound Marketing provides a process to take the Buyer Personas through the Buyer’s Journey with the  help of right content and tools. The following diagram (idea popularized by Hubspot and adjusted for Sitecore here) shows how this happens.

Inbound Methodology

There are four stages of Inbound Marketing Attract, Convert, Close and Delight. In each stage we use some tools to help the prospect to take the Buyer’s Journey. For example, in my case, Home Depot used SEO properly to attract me to watch their video. I started as a stranger and became a visitor of their site and a customer. Once a visitor comes to the site, we can use Call To Action (CTA), Forms (WFFM in Sitecore) etc. to capture more information from the customer. In this way a visitor becomes lead and finally a happy customer who promotes the products or services to people they know. This process adds value to the business and creates a Value Loop that brings more prospects  to the business. In each stage of the process Inbound Methodology uses data analysis and A/B Testing  to increase the conversion rate.

What’s Next?
We haven’t talked about Sitecore at all in this article. Although, if you look at the Inbound Methodology, you can see, Sitecore provides all the tools needed for designing an Inbound Marketing process for a site. In the upcoming blog posts we will unravel how Sitecore can be used to implement Inbound Marketing.

References
Learn Inbound Marketing from Hubspot
Book: Inbound Marketing: Get Found Using Google, Social Media, and Blogs

Posted in Commercce, DMS, Sitecore, Web Forms For Marketers, WFFM | Tagged , , , | Leave a comment

How to fix: Multiple types were found that match the controller named issue in Sitecore Application

This blog post talks about the above mentioned MVC issue for the applications built on Sitecore. If you are here and your application doesn’t have anything to do with Sitecore you probably should look at this stackoverflow post.

In a Sitecore application, a controller gets created for two reasons 1) the controller is declared in the layout rendering and 2) when an action method from controller gets called directly (for example, application is making an ajax call). Let’s look at the following code to understand how Sitecore resolves the controller creation request.

    protected virtual IController CreateControllerInstance(RequestContext requestContext, string controllerName)
    {
      if (Sitecore.Mvc.Extensions.StringExtensions.EqualsText(controllerName, this.SitecoreControllerName))
        return this.CreateSitecoreController(requestContext, controllerName);
      if (TypeHelper.LooksLikeTypeName(controllerName))
      {
        Type type = TypeHelper.GetType(controllerName);
        if (type != (Type) null)
        {
          IController controller = DependencyResolver.Current.GetService(type) as IController ?? TypeHelper.CreateObject&amp;amp;lt;IController&amp;amp;gt;(type);
          if (controller != null)
            return controller;
        }
      }
      return this.InnerFactory.CreateController(requestContext, controllerName);
    }

If the controllerName is SitecoreControllerName (this is set in the Sitecore.Mvc.Config) then, code will call CreateSitecoreController special method to create that controller. If the controllerName is fully qualified type name, then Sitecore will create that type via the DependencyResolver or using TypeHelper, if DependencyResolver was not set. If none of those two conditions apply, Sitecore will pass the control over to the DefaultControllerFactory.

This issue happens when there are more than one namespace with the same controller name in the application. For example, if a third party dll in your application has a controller named AccountController and your application has a controller named AccountController which was added in the layout rendering. Then the conflict will arise because the DefaultControllerFactory would not know which controller to create. This problem can be solved easily if we assign the fully qualified class name in the layout rendering controller field as shown in the following picture.

pic1

Controller Rendering setting

That covers the first scenario, where controllers action method is used for layout rendering. But, when controller action method is used to return JSONResult for an ajax call or a view directly, there is no way to declare the controller with fully qualified name. We are going to talk about the solution for that case now, i.e. scenario 2. In this case you can create a custom route class like below. You have to specifically add the namespaces in the route. This means, you are telling DefaultControllerFactory to resolve controllers only from the namespaces added in the given route.

using Sitecore.Pipelines;
using System.Web.Mvc;
using System.Web.Routing;

namespace MyApp.Extensions
{
    public class CustomRoutes
    {
        public virtual void Process(PipelineArgs args)
        {
            RegisterRoute();
        }
        public static void RegisterRoute()
        {
            var route=RouteTable.Routes.MapRoute(
                name: "MyApp",
                url: "api/sitecore/{controller}/{action}",
                namespaces: new[] { "MyApp.Controllers", "Sitecore.Controllers" });
        }
    }
}

In addition to above code you need to create a patch config file with the following config to add that processor in the Initialize pipeline.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <initialize>
        <processor type="MyApp.Extensions.CustomRoutes, MyApp"
                     patch:after="processor[@type='Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc']"/>
      </initialize>
    </pipelines>
  </sitecore>
</configuration>

In the scenario 2, if the application has a same controller name in the included namespaces, the only way to resolve the conflict is to use unique controller name.

Reference:

Sitecore MVC and Unity

Safe Dependency Injection for MVC and WebApi within Sitecore

Changes to Dependency Injection in Sitecore 8.1

Sitecore MVC – Getting Started

Posted in MVC, Sitecore | Tagged , , , | 1 Comment

Continuous Integration with Gulp and Sitecore Powershell Extensions Part 2 – TeamCity Integration

This blog article is continuation of my earlier blog Continuous Integration with Gulp and Sitecore Powershell Extensions Part 1. In this blog, I will show how we can use TeamCity to build and deploy the code and Sitecore items to a Sitecore instance which resides in a different physical server than the Build Server where TeamCity runs.

QA Server Setup

I am going to deploy the code and Sitecore items in my QA environment for the Cobbler application. As I setup my local environment with Sitecore and Cobbler, I have done the same for the QA environment. I installed Sitecore 8.1 with Powershell using SIM. Then I installed the initial Cobbler package (can be found in Github). I also, created an empty website in IIS for ElfWebApi. My Cobbler website is in C:\Websites\Cobbler and ElfWebApi is in C:\Websites\Elf folder in the QA server. Since these two folders where the code will be deployed by TeamCity from a different physical build server, I had to share the folders over network. I created two shares called ‘Cobbler’ and ‘Elf’ in the QA server. If my QA server name is QAServer, the network path to those two shares are \\QAServer\Cobbler and \\QAServer\Elf. I needed to add these two paths in the gulp-config.js file as follows:

pic1

That’s all for the QA Server setup.

Script Changes

There were not much changes required in the scripts, but I needed to create a new set of scripts for the QA deployment from the original scripts, because the publish folders are changed as highlighted in the above picture. I also had to create a new script to publish Sitecore serialized items in the Cobbler data folder in the QA server. The Deserialization scripts will look into this folder to update Sitecore items. A new deserialization script was also created because the URL for the QA server is different than the local environment. Following are the new scripts:

Publish-Cobbler-QA –> Publishes code to the Cobbler website in the QA Server

Publish-Elf-QA –> Publishes code to the Elf webapi site in the QA Server

Publish-Cobbler-Design-QA –> Publishes design files to Cobbler website in the QA Server

Publish-Cobbler-Items-QA -> Publishes Serialized Sitecore Items to Cobbler data folder in the QA Server. This is the new script.

Deserialize-Cobbler-Items-QA –> Runs DeSerializeItems-qa.ps1

DeployAll-QA –> Runs multiple scripts to deploy files and Sitecore Items to the website in the QA server.

Deploy-Projects-QA –> Publishes only the deployment files. No Sitecore item gets deployed.

An additional change in the Cobbler.Web project was to add the SlowCheetah for the Sitecore.config transformation for the  QA build configuration. The SerializationFolder setting for the QA server is different than Local environment.

<setting name=”SerializationFolder” value=”$(datafolder)/serialization” />

This enables us to deploy the right Sitecore.config to the QA environment.

Build Server Setup

The build server had to setup to run the gulp script. I had to install node.js and gulp in the build server. I downloaded node.js from here. Once node is installed in the build server, I installed gulp in the server using the following command in the command window.

 npm install gulp -g -prefix=”C:\Program Files (x86)\nodejs”

Make sure to open the command prompt in administrator mode. The above command installs gulp in the same directory as where node is installed. As node path is set to environment variable PATH, gulp is also available from any location in the server.

Since the Powershell remote scripts will run from the build sever, I installed SPE Remoting package in the build server. I copied the SPE files in the following folder as build.server is the account that is used to run the TeamCity Build Agent.

C:\Users\build.server\Documents\WindowsPowershell\Modules\SPE

Build Configuration

In TeamCity I created following build steps

pic2

The third build step is the one to run the gulp scripts. This is a custom command line script that TeamCity runs using command prompt. The script first runs npm install. That installs the dependencies in the local node_modules folder. Next, it calls gulp to run my DeployAll-QA. This calls all other gulp script that deploys code and Sitecore items.

pic3

Final Words

With power of Sitecore Powershell Remoting and Gulp I successfully created a Continuous Integration using TeamCity for my QA environment. Developers adding new or modifying Sitecore items can serialize the items by running the Serialize-Cobbler-Items-Local gulp script in their environment and check in the items in the source control. TeamCity build will check out the Sitecore items from the source control and deserialize the items in the QA server or any remote server the build is configured for.

Links

 

Posted in CI, Gulp, Powershell, Sitecore | Tagged , , , | 3 Comments

Sitecore Pipelines and Unity

This is continuation of my earlier blog post Sitecore MVC and Unity. In that post I discussed how with a minimum effort we can use Unity as the DI Framework for the Sitecore MVC application. In this post, I will discuss how we can use Unity to make the Sitecore Pipelines DI enabled and thus make the Pipelines unit testable.

When it comes to DI for the Sitecore Pipelines, there are two approaches we can take.

  1. Use Sitecore’s inbuilt Configuration Factory. This was described in great detail by Mike Reynolds in his blog Leverage the Sitecore Configuration Factory: Inject Dependencies Through Class Constructors.
  2. Create our own Factory class and use DI container to resolve the objects. This was described in the blog post Sitecore pipelines & commands using IoC containers.

I will be taking the second approach because I can use the same Unity Container that I described in earlier post. For the sake of understanding how this approach works let’s define the application as follows.

Say, I have a website that makes Cookies called CookieMaker. In that, I have a Pipeline called CookieMaker.MakeCookies with some processors. One of the processors is GetSomeFlour. Following is the project structure.

Unity3

The Pipeline Processor GetSomeFlour uses FlourService and the FlourService in turns uses FlourRepository. Here are the classes.

GetSomeFlour

Unity4

FlourService

Unity5

FlourRepository

Unity6

Using Unity container all of the above classes will be resolved. For this, I need to create my own Configuration Factory called UnityContainerFactory as below.

Unity8

In the above class, UnityConfig.GetConfiguredContainer() method returns the same container that was mentioned in my earlier post and since I registered classes by naming convention the Service and Repository classes will be resolved automatically.

To use UnityContainerFactory we need add the following in the config file.

Unity7

That’s all we need to do to make Pipelines DI enabled.

Posted in Framework, MVC, Sitecore | Tagged , ,

2015 in review

Wish you a very happy and prosperous 2016. The WordPress.com stats helper monkeys prepared a 2015 annual report for this blog.

Here’s an excerpt:

The concert hall at the Sydney Opera House holds 2,700 people. This blog was viewed about 13,000 times in 2015. If it were a concert at Sydney Opera House, it would take about 5 sold-out performances for that many people to see it.

Click here to see the complete report.

Posted in Uncategorized | Leave a comment

Continuous Integration with Gulp and Sitecore Powershell Extensions Part 1

Sitecore development and code deployment is quite different than normal ASP.Net Web Application development because of the fact that we need to deal with the versioning of Sitecore items. In this regard Team Development for Sitecore (TDS) is a huge help. There are two main things that TDS does, it publishes the files to the application folder and deploys Sitecore items in the application. Actually, TDS does lot more than that, but those two things are most important to me.

Last few days I was contemplating if can I achieve these two deployment functionalities using Gulp and Sitecore Powershell Extensions (SPE), because, Gulp is great for publishing project files and SPE is great for dealing with Sitecore items. So, the journey started and I am happy that it works. This is going to be a blog series. This one is for deployment of Sitecore application in developer’s local environment.

Sitecore Setup

This is easy. I used SIM to install Sitecore 8.1 and 3.3 version of SPE from Sitecore Marketplace. To work on this, I need a real Sitecore application. I named it ‘Cobbler’. For local environment the hostname is cobbler.local. After setup is done, I had to create the templates and items for my application. Below is a screenshot from the content editor. All the items are available in Github along with the source code.

pic1

Only change I made in the default installation, I changed the serialization folder in the Sitecore.config. I did this because I want to version control the serialized Sitecore items. Following line changed

<setting name=”SerializationFolder” value=”C:\Github\Cobbler\data\serialization” />

Project Setup

Following is a screenshot of the Cobbler solution in Visual Studio.

pic2

 

By no means it is a fully working solution. I mean, after setting up everything and do the deployment, a nice website will not be launched. The idea is to show how deployment works. Being said that, I tried to add different kinds of projects in the solution to represent how a real application solution looks like. We have two website projects. Cobbler.Web is the main web application and Elf.WebApi is a restful API project. Cobbler talks Elf via restful API. Cobbler.Design project contains all UI design related files (css, font etc.). I separated it to show that files from project other than the Cobbler.Web can be published in Cobbler website. In real life this is often the case. The Elf website is a separate IIS site and deployment process recognize that and publishes to that website.

Gulp Setup

To use Gulp in Visual Studio solution you first need to install Node and npm. Visit nodejs.org and click on the big green button to download and then install. Npm comes with the Node and separate installation is not needed. After installation you can run following two command in the command prompt window to see if they were installed properly. This will show you the version.

node -v

npm -v

Once Node is installed, open Package Manager Console in the Cobbler Visual Studio solution and run following two commands. Since the solution already has a package.json, all gulp packages used in the gulp scripts will be downloaded.

npm install -g gulp

npm install –save-dev gulp

You will also need to install Task Runner Explorer to run the gulp tasks. You can down load from here. After installing Task Runner Explorer, close of Visual Studio and launch again. I found that the gulp tasks doesn’t show up in Task Runner unless I relaunch again. At this point if you right click on the gulpfile.js and click on Task Runner Explorer, you should see all the gulp tasks on the left.

pic3.png

Sitecore Powershell Extension Setup

Other than installing SPE Package in Sitecore, you need to download Remoting for SPE 3.3 Package from Marketplace. Copy the files in C:\Users\<username>\Documents\WindowsPowershell\Modules\SPE folder. The script Invoke-RemoteScript.ps1 in this folder will be use to run scripts remotely in the Cobbler Sitecore application.

Scripts

That should be all for setup. Let’s look at the scripts.

Powershell Scripts

SerializeItems.ps1
This script reads the items path from the SitecoreItemPath.txt file and serialize the files in the Serialization folder C:\Github\Cobbler\data\serialization. If a line in the SitecoreItemPath.txt marked as -DeployOnce, that item will be skipped if it already exists.


#Change the Powershell Execution Policy so that script can be run from Visual Studio
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
$session = New-ScriptSession -Username &quot;admin&quot; -Password &quot;b&quot; -ConnectionUri &quot;http://cobbler.local&quot;
$RootFolder=&quot;C:\Github\Cobbler\data\serialization\master&quot;
$ItemPaths=Get-Content &quot;C:\Github\Cobbler\SitecoreItemPath.txt&quot;
$ItemExtn=&quot;.item&quot;
foreach($ItemPath in $ItemPaths)
{
$ItemPath=$ItemPath.Trim()
$ItemPath=$ItemPath -replace &quot;/&quot;, &quot;\&quot;
if($ItemPath.Length -gt 0)
{
if(-not (($ItemPath.ToLower().Contains(&quot;-deployonce&quot;)) -and (Test-Path &quot;$($RootFolder)$($ItemPath.ToLower().TrimEnd(&quot;-deployonce&quot;).Trim())$($ItemExtn)&quot;)))
{
if($ItemPath.ToLower().Contains(&quot;-deployonce&quot;))
{
$ItemPath=$ItemPath.ToLower().TrimEnd(&quot;-deployonce&quot;).Trim()
}
Write-Host &quot;Serializing Item: $ItemPath&quot;
$script = {
Get-Item -path $params.Path | export-item -ItemPathsAbsolute -Root $params.RootFolder
}
$args = @{
&quot;Path&quot; = &quot;master:$($ItemPath)&quot;
&quot;RootFolder&quot; = &quot;$RootFolder&quot;
}
Invoke-RemoteScript -ScriptBlock $script -Session $session -ArgumentList $args
}
}
}

DeserializeItems.ps1
This script is opposite to SerializeItems.ps1 script. It reads the items path from the SitecoreItemPath.txt and create or update the items in Sitecore. Similar to the other script, this script also skips the item if the item is marked as -DeployOnce.


#Change the Powershell Execution Policy so that script can be run from Visual Studio
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
$session = New-ScriptSession -Username &quot;admin&quot; -Password &quot;b&quot; -ConnectionUri &quot;http://cobbler.local&quot;
$RootFolder=&quot;C:\Github\Cobbler\data\serialization\master&quot;
$ItemPaths=Get-Content &quot;C:\Github\Cobbler\SitecoreItemPath.txt&quot;
$ItemExtn=&quot;.item&quot;
foreach($ItemPath in $ItemPaths)
{
$IsDeployOnceItem = $FALSE
$ItemPath=$ItemPath.Trim()
#$ItemPath=$ItemPath -replace &quot;/&quot;, &quot;\&quot;
if($ItemPath.Length -gt 0)
{
if($ItemPath.ToLower().Contains(&quot;-deployonce&quot;))
{
$IsDeployOnceItem = $TRUE
$ItemPath=$ItemPath.ToLower().TrimEnd(&quot;-deployonce&quot;).Trim()
}
Write-Host $ItemPath
$script = {
if(Test-Path $params.Path)
{
if(-not ($Params.DeployOnceFlag))
{
Get-Item -path $params.Path | Import-item -ForceUpdate
}
else
{
Write-Log &quot;Skipped&quot;
}
}
else
{
$Path=$params.Path
$ParentPath=$Path.Substring(0,$Path.LastIndexOf(&quot;/&quot;))
Get-Item -path $ParentPath | Import-item -Recurse
}
}
$args = @{
&quot;Path&quot; = &quot;master:$($ItemPath)&quot;
&quot;DeployOnceFlag&quot; = $IsDeployOnceItem
}
Invoke-RemoteScript -ScriptBlock $script -Session $session -ArgumentList $args
}
}

Gulp Scripts

I am not going to paste all the gulp script here but just describe the purpose of the scripts.

Publish-Cobbler-Local –> Publishes code to the Cobbler website

Publish-Elf-Local –> Publishes code to the Elf webapi site

Publish-Cobbler-Design-Local –> Publishes design files to Cobbler website

Serialize-Cobbler-Items-Local –> Runs SerializeItems.ps1

Deserialize-Cobbler-Items-Local –> Runs DeSerializeItems.ps1

DeployAll-Local –> Runs multiple scripts to deploy files and Sitecore Items to the website. Full Deployment.

Deploy-Projects-Local –> Publishes only the deployment files. No Sitecore item gets deployed.

Following scripts runs when solution is launched in Visual Studio and watch changes in the css, javascripi and MVC Views. As soon as file(s) change, they get deployed to the website.

Auto-Publish-Css-Local
Auto-Publish-js-Local
Auto-Publish-Views-Local

Final Word

This is working fine for me in most cases. What this does not provide that I get from TDS is the Sync functionality and interactive way to serialize items in Visual Studio. In the next part, I will integrate this deployment process with Team City and deploy application to remote server.

Links

 

 

 

 

 

Posted in Gulp, Powershell, Sitecore | Tagged , , , | 2 Comments

Social Media, Sitecore and B2B Commerce

In my last blog post I discussed about role of Sitecore in B2B Commerce and how big of an opportunity their to use Sitecore to increase the business revenue. In this blog I will discuss why B2B Commerce needs Sitecore for content generation and distributing the content via different channels to increase the business prospect.

I would like to start with a particular experience I had working with one of our B2B Commerce clients. This was beginning of a project and we were talking about requirements. In the Product Detail mock up there were some social media buttons for Facebook, Twitter etc. Our client thought none of their users will be posting the product link in the their Facebook or Twitter pages. I thought same way too. For example, if I am a Customer Representative and I buy products for customers, why would I post product link in my social media pages? I don’t think I would. But, that incident got me thinking about the role of social media for the B2B Commerce.

Before we discuss, how social media can be used in B2B Commerce, let’s discuss about the difference between a B2B Commerce and B2C Commercce user. In B2C Commerce the user is the customer and buys products for personal use. For B2C commerce user, posting the product link on user’s own social media page makes sense because user owns the product and probably would like to share the purchase with user’s followers. On the other hand in B2B, user often is not the customer. For B2B user the lead time for a purchase is often longer than B2C user. B2B user usually tend to do more research by reading blogs, articles that posted by either the manufacturer or by some independent bloggers. They need to do more research because most cases the B2B products are complex and some time it is configured product. What is important for the B2B Commerce site is, to make these research materials easily available for the users through social media channels and forums. This is where Sitecore can help with content generation and pushing contents using Experience Platform.

Before we talk about how or what Sitecore can do, let’s look at this interesting statistics below about a survey conducted on 2013 to understand how B2B decision makers are using social media.

Forrester-B2B-Decision-Maker-Use-Social-Media-July2013

You can find more about this chart in this article. Although, the chart is two years old the situation has not changed a lot. It is clear that B2B business can do a lot to distribute content about their product via social media.

Blogging using Sitecore WeBlog module

The B2B businesses needs to provide information about their products through blogs, articles either in the eCommerce site itself or via links to independent bloggers. Sitecore Marketplace has a great blogging module called WeBlog and it is free. You can find this module here. With the help of WeBlog, the blogging or Product articles can be added with minimum effort. WeBlog comes with many features like tagging, RSS feed generation, commenting, spam filtering, CAPTCHA etc. What is sweet though, it comes with Social sharing ShareThis or AddThis, and other Facebook and Twitter widgets. By having Sitecore and WeBlog module, the B2B business can easily generate blog contents and distribute those through different media channels.

Sitecore Media Framework

I am a serious hobbyist photographer. When I look for a new photo gear and I need to research about it, I sometime prefer to watch videos about the gear, instead of reading long articles. It is a great idea to add videos in the B2B site to easily communicate the product information to the user. In this regard Sitecore Media Framework can be a great help. Sitecore Media Framework integrates with Brightcove and Ooyala professional video streaming service. The B2B site built on Sitecore can take advantage of these media connectors two manage the videos. Some time back, I wrote a Media Connector for integrating Sitecore with Youtube. This module is available in Sitecore Marketplace. I wrote some blog posts too. You can find more here Sitecore Youtube Connector.

Sitecore Experience Platform

Finally, Sitecore Experience Platform can be a great use for selecting appropriate blogs/articles/videos for the B2B user. Based on the user and customer profile and what kind of products the user is interested in, related blogs/articles/videos/Independent blog links can be presented to the user. Each content will provide user the option to share content in the social media. The distribution of content via social media will attract more customer to the B2B site.

Conclusion

B2B business has yet to use the full potential of social media. With the power Sitecore, an integrated B2B eCommerce platform with Sitecore can achieve this goal very quick and it can add great value to the business.

Posted in Commercce, Sitecore, Uncategorized | Tagged , , , , , | Leave a comment