Field Validators on Experience Editor

On Sitecore 8 I added few fields validators.
Everything works perfectly on Content Editors but not on Experience Editor.

On config files we have next setting:


<!--
  WEB EDIT ENABLE VALIDATION
            If true, the Page Editor will execute item and field validation rules whenever a user tries to save items in the Page Editor.
            Only 'Critical' and 'Fatal' validators are evaluated, and item validation rules are executed for the current context item only.
            Field validation rules are only executed for fields that the current user can modify in the Page Editor.
            Default value: true
      
-->
<setting name="WebEdit.EnableValidation" value="true" patch:source="Sitecore.ExperienceEditor.config"/> 
 

but is ignored on Experience Editor.

I found a new solution switching Experience Editor from Speak UI to Sheer UI.
How to switch it :

Modify on App_Config\Include\Sitecore.ExperienceEditor.config
mvc.renderPageExtenders pipeline

1. Comment out the following line in the:

<pageextender type="Sitecore.ExperienceEditor.Speak.Ribbon.PageExtender.RibbonPageExtender, Sitecore.ExperienceEditor.Speak.Ribbon" />
[/soucecode]
2. Uncomment the following lines:
 
<pageextender type="Sitecore.Layouts.PageExtenders.PreviewPageExtender, Sitecore.ExperienceEditor" />
<pageextender type="Sitecore.Layouts.PageExtenders.WebEditPageExtender, Sitecore.ExperienceEditor" />
<pageextender type="Sitecore.Layouts.PageExtenders.DebuggerPageExtender, Sitecore.ExperienceEditor" />
 

If you have a Mvc Solution you need to change Sitecore.MvcExperienceEditor.config
1. Uncomment the page extenders below and comment the “SPEAK-based” Experience Editor ribbon processors to switch to old SheerUI-based Experience Editor ribbon.

 
        <processor type="Sitecore.Mvc.ExperienceEditor.Pipelines.RenderPageExtenders.RenderPageEditorExtender, Sitecore.Mvc.ExperienceEditor"></processor>
        <processor type="Sitecore.Mvc.ExperienceEditor.Pipelines.RenderPageExtenders.RenderPreviewExtender, Sitecore.Mvc.ExperienceEditor"></processor>
        <processor type="Sitecore.Mvc.ExperienceEditor.Pipelines.RenderPageExtenders.RenderDebugExtender, Sitecore.Mvc.ExperienceEditor"></processor>
    

2. Comment next pipeline

   <processor type="Sitecore.Mvc.ExperienceEditor.Pipelines.RenderPageExtenders.SpeakRibbon.RenderPageEditorSpeakExtender, Sitecore.Mvc.ExperienceEditor"></processor>
   
Advertisements

Goals in a multisite solution

Yesterday it was a question on Community how to implement Goals in a multisite solution: https://community.sitecore.net/developers/f/9/t/1913

And if I write few blog posts about multisite I said to write also a blogpost about implementing goals in a multisite solution.

My site structure is :

Countries

My goals structure is :

Step 1 :

Modify site definition like. I added a new property to sites “goalsFolder”

  <site name="countrythree" patch:before="site[@name='website']" hostName="countrythree.sitecoredemo.com" inherits="sitecoremvc-base" rootPath="/sitecore/content/countrythree" startItem="/" dictionaryDomain="{D8BC2E0C-36C5-4128-8F29-352B55E86676}" language="en" goalsFolder="countrythree" />

  <site name="countrytwo" patch:before="site[@name='website']" hostName="countrytwo.sitecoredemo.com" inherits="sitecoremvc-base" rootPath="/sitecore/content/countrytwo" startItem="/" dictionaryDomain="{D8BC2E0C-36C5-4128-8F29-352B55E86676}" language="en" goalsFolder="countrytwo" />


  <site name="countryone" patch:before="site[@name='website']" hostName="countryone.sitecoredemo.com" inherits="sitecoremvc-base" rootPath="/sitecore/content/countryone" startItem="/" dictionaryDomain="{D8BC2E0C-36C5-4128-8F29-352B55E86676}" language="de-de" goalsFolder="countrytwo" />

  <site name="sitecoremvc-base" patch:before="site[@name='website']" hostName="*" enableTracking="true" virtualFolder="/" physicalFolder="/" rootPath="/sitecore/content" 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" />
  

Step2:
Change type of command with name “anylitics:opengoals” from Sitecore.Analytics.config
into:

  <command name="analytics:opengoals" type="Sitecore.Analytics.OpenGoals,SitecoreDemo" patch:source="Sitecore.Analytics.config"/>

Step3:
Create a new class OpenGoals:

    using Sitecore;
    using System;
    namespace SitecoreDemo.Analytics
    {
      [Serializable, UsedImplicitly]
      public class OpenGoals : OpenTrackingField
      {
        // Methods
        protected override string GetUrl()
        {
            return "/sitecore/shell/~/xaml/Sitecore.Shell.Applications.Analytics.TrackingField.Goals.aspx";
        }
       }
    }
    

4. Create a new xaml file name it Goals.xaml and add it to folder: /Sitecore/Shell/Override

      <?xml version="1.0" encoding="UTF-8" ?>
<xamlControls xmlns:x="http://www.sitecore.net/xaml" xmlns:ajax="http://www.sitecore.net/ajax" xmlns:rest="http://www.sitecore.net/rest" xmlns:r="http://www.sitecore.net/renderings" xmlns:xmlcontrol="http://www.sitecore.net/xmlcontrols" xmlns:p="http://schemas.sitecore.net/Visual-Studio-Intellisense" xmlns:asp="http://www.sitecore.net/microsoft/webcontrols" xmlns:html="http://www.sitecore.net/microsoft/htmlcontrols" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <Sitecore.Shell.Applications.Analytics.TrackingField.Goals x:inherits="SitecoreDemo.Analytics.GoalsPage,SitecoreDemo">

    <Sitecore.Controls.DialogPage runat="server" Header="Goals" Text="Select the goals that you want to associate with the selected item.">
      <AjaxScriptManager runat="server"/>
      <ContinuationManager runat="server" />
      <Script runat="server" Src="/sitecore/Shell/Applications/Analytics/TrackingField/TrackingField.js" />


<Style runat="server">
        #GoalsList table tr > td {
          padding: 0 0 10px 0;
        }
      </Style>




<table width="100%" height="100%" cellpadding="0" cellspacing="0" border="0">


<tr>


<td height="100%">
            <GridPanel Width="100%" Height="100%" runat="server" Background="White">

              <Border runat="server" GridPanel.Style="height:100%" Height="100%">
                <Scrollbox id="GoalsList" runat="server" Height="100%" Padding="0px"/>
              </Border>
            </GridPanel>
          </td>


        </tr>


      </table>


        
        
    </Sitecore.Controls.DialogPage>
  </Sitecore.Shell.Applications.Analytics.TrackingField.Goals>


</xamlControls>

    

5. Create a new class GoalsPage

using Sitecore;
using Sitecore.Analytics;
using Sitecore.Analytics.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Extensions.XElementExtensions;
using Sitecore.Shell.Applications.Analytics.TrackingField;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Sheer;
using Sitecore.Xml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using System.Xml.Linq;
using SitecoreDemo.Util;

namespace SitecoreDemo.Analytics
{
   [UsedImplicitly]
public class GoalsPage : TrackingFieldPageBase
{
    // Methods
    protected override void OK_Click()
    {
        Packet packet = new Packet("tracking", new string[0]);
        base.AddIgnoreFlag(packet);
        base.AddExistingProfiles(packet);
        base.AddExistingCampaigns(packet);
        if (HttpContext.Current != null)
        {
            List<PageEventItem> pageEventDefinitions = new List<PageEventItem>(from item in Tracker.DefinitionItems.PageEvents.Concat<PageEventItem>(Tracker.DefinitionItems.Goals)
                where item.IsDeployed
                select item);
            base.AddExistingNoneGoals(packet, pageEventDefinitions);
            CheckBoxList checkBoxList = this.GoalsList.Controls[0] as CheckBoxList;
            if (checkBoxList != null)
            {
                TrackingFieldPageBase.GetEvents(packet, pageEventDefinitions, checkBoxList);
            }
            SheerResponse.SetDialogValue(packet.ToString());
            base.OK_Click();
        }
    }

    protected override void OnLoad(EventArgs e)
    {
        Assert.ArgumentNotNull(e, "e");
        Assert.CanRunApplication("Content Editor/Ribbons/Chunks/Analytics - Attributes/Goals");
        base.OnLoad(e);
    }

    protected override void Render(XDocument doc)
    {
        Assert.ArgumentNotNull(doc, "doc");
        this.RenderGoals(doc);
    }

    private void RenderGoals(XDocument doc)
    {
        Assert.ArgumentNotNull(doc, "doc");
        List<string> selected = new List<string>();
        foreach (XElement element in doc.Descendants("event"))
        {
            selected.Add(element.GetAttributeValue("name"));
        }
        CheckBoxList child = new CheckBoxList {
            ID = "GoalsCheckBoxList"
        };
        this.GoalsList.Controls.Add(child);
        System.Web.UI.Page page = TrackingFieldPageBase.GetPage();

        var site = ItemUtil.GetSiteContextForItem(ItemUtil.GetItem(Sitecore.Context.Request.QueryString["id"]));
        var goalsFolder = site.Properties["goalsFolder"];
        if ((page != null) && !page.IsPostBack)
        {
            IOrderedEnumerable<PageEventItem> query;
            if (!string.IsNullOrEmpty(goalsFolder) && Sitecore.Context.ContentDatabase.GetItem(Tracker.DefinitionItems.Goals.Path+"/"+goalsFolder)!=null)
            {
                query = from e in Tracker.DefinitionItems.AllPageEvents
                        where e.InnerItem.Parent.Key.Equals(goalsFolder, StringComparison.InvariantCultureIgnoreCase) && (e.IsDeployed && e.IsGoal) && !e.IsSystem
                        orderby e.DisplayName
                        select e;
            }
            else
            {
                query = from e in Tracker.DefinitionItems.AllPageEvents
                        where(e.IsDeployed && e.IsGoal) && !e.IsSystem
                        orderby e.DisplayName
                        select e;
            }
            TrackingFieldPageBase.RenderCheckBoxList(child, query, selected);
        }
    }

    


    // Properties
    [UsedImplicitly]
    protected Scrollbox GoalsList { get; set; }
}
}

Step6. Create a new class OpenTrackingField

    using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Shell.Framework.Commands;
using Sitecore.Text;
using Sitecore.Web;
using Sitecore.Web.UI.Sheer;
using Sitecore.Web.UI.WebControls;
using System;
using Sitecore.StringExtensions;

namespace SitecoreDemo.Analytics
{
    [Serializable, UsedImplicitly]
    public class OpenTrackingField : Sitecore.Shell.Applications.Analytics.TrackingField.OpenTrackingField
    {
        CommandContext context;
        // Methods
        public override void Execute(CommandContext context)
        {
            this.context = context;
            base.Execute(context);
        }

        protected virtual string GetUrl()
        {
            return "/sitecore/shell/~/xaml/Sitecore.Shell.Applications.Analytics.TrackingField.aspx";
        }

        [UsedImplicitly]
        protected void Run(ClientPipelineArgs args)
        {
            Assert.ArgumentNotNull(args, "args");
            Item item = base.DeserializeItems(args.Parameters["items"])[0];
            if (SheerResponse.CheckModified())
            {
                string str = args.Parameters["fieldid"];
                if (string.IsNullOrEmpty(str))
                {
                    str = "__Tracking";
                }
                if (args.IsPostBack)
                {
                    if (args.HasResult)
                    {
                        using (new StatisticDisabler(StatisticDisablerState.ForItemsWithoutVersionOnly))
                        {
                            item.Editing.BeginEdit();
                            item[str] = args.Result;
                            item.Editing.EndEdit();
                        }
                        if (AjaxScriptManager.Current != null)
                        {
                            AjaxScriptManager.Current.Dispatch("analytics:trackingchanged");
                        }
                        else
                        {
                            Context.ClientPage.SendMessage(this, "analytics:trackingchanged");
                            Context.ClientPage.SendMessage(this, "item:refresh(id={0})".FormatWith(new object[] { item.ID.ToString() }));
                        }
                    }
                }
                else if (item.Appearance.ReadOnly)
                {
                    SheerResponse.Alert("You cannot edit the '{0}' item because it is protected.", new string[] { item.DisplayName });
                }
                else if (!item.Access.CanWrite())
                {
                    SheerResponse.Alert("You cannot edit this item because you do not have write access to it.", new string[0]);
                }
                else
                {
                    UrlString urlString = new UrlString(this.GetUrl());
                    urlString.Add("id", context.Items[0].ID.ToShortID().ToString());
                    UrlHandle handle = new UrlHandle();
                    handle["tracking"] = item[str];
                    handle.Add(urlString);
                    this.ShowDialog(urlString.ToString());
                    args.WaitForPostBack();
                }
            }
        }
    }
}
     

Step7.
I am on countryone site and I want to add a new goal to a page.
Is showing me just the goals from countryone folder.

OpenGoalCountry

This code was tested on Sitecore 8.1.

 

Configuring indexes in a multisite solution

In the previous blogpost I wrote about aliases and how to inherit sites from a base site.
Also for the lucene indexes is posible to do it.

We have a Sitecore solution with 3 country sites that have same structure.
(please see below picture)

Countries

We need to create elegant solution for creating indexes for every country.

First step is create base configuration, I create a config file (Sitecore.ContentSearch.Lucene.Index.ZZZConfiguration.config ) that I add into a “ZZZ” folder to be the last in configuration file.

    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <contentSearch>
      <configuration type="Sitecore.ContentSearch.ContentSearchConfiguration, Sitecore.ContentSearch">
        <indexTemplates hint="skip">
          <searchIndexTemplate id="$(1)" type="Sitecore.ContentSearch.LuceneProvider.SwitchOnRebuildLuceneIndex,Sitecore.ContentSearch.LuceneProvider">
            <param desc="name">$(1)</param>
            <param desc="folder">$(1)</param>
            <!-- This initializes index property store. Id has to be set to the index id -->
            <param desc="propertyStore" ref="contentSearch/indexConfigurations/databasePropertyStore" param1="$(id)" />
            <strategies hint="list:AddStrategy">
              <!-- NOTE: order of these is controls the execution order -->
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/rebuildAfterFullPublish" />
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/onPublishEndAsync" />
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/remoteRebuild" />
            </strategies>
            <commitPolicyExecutor type="Sitecore.ContentSearch.CommitPolicyExecutor, Sitecore.ContentSearch">
              <policies hint="list:AddCommitPolicy">
                <policy type="Sitecore.ContentSearch.TimeIntervalCommitPolicy, Sitecore.ContentSearch" />
              </policies>
            </commitPolicyExecutor>
            <locations hint="list:AddCrawler">
              <crawler type="Sitecore.ContentSearch.SitecoreItemCrawler, Sitecore.ContentSearch">
                <Database>$(2)</Database>
                <Root>$(3)</Root>
              </crawler>
            </locations>
            <configuration ref="contentSearch/configuration/defaultIndexConfiguration | contentSearch/configuration/DefaultIndexConfiguration | contentSearch/indexConfigurations/defaultLuceneIndexConfiguration">
              <documentBuilderType>Sitecore.ContentSearch.LuceneProvider.LuceneDocumentBuilder, Sitecore.ContentSearch.LuceneProvider</documentBuilderType>
              <IndexAllFields>true</IndexAllFields>
              <exclude hint="list:ExcludeTemplate">
                <patch:delete />
              </exclude>
                <include hint="list:IncludeTemplate">
                 <!--add here your templates --> 
              </include>
              <fields hint="raw:AddComputedIndexField">
                 <!--add here your computed index field --> 
              </fields>
 
             </configuration>
          </eventIndexTemplate>
        </indexTemplates>
      </configuration>
    </contentSearch>
  </sitecore>
</configuration>
    

Now we need to create index config file that inherit from above configuration

 <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
      <contentSearch>
         <configuration type="Sitecore.ContentSearch.ContentSearchConfiguration, Sitecore.ContentSearch">
        <!--searchj-->
        <indexes hint="list:AddIndex">
          <index ref="contentSearch/configuration/indexTemplates/searchIndexTemplate" param1="country1" param2="web" param3="/sitecore/content/countryone" />
          <index ref="contentSearch/configuration/indexTemplates/searchIndexTemplate" param1="country2" param2="web" param3="/sitecore/content/countrytwo" />
	  <index ref="contentSearch/configuration/indexTemplates/searchIndexTemplate" param1="country3" param2="web" param3="/sitecore/content/countrythree" />
        </indexes>
      </configuration>
    </contentSearch>
  </sitecore>
      </configuration>
   

 
You can see I replace $(1),$(2),$(3) from first config file with parameters from second config file.
These are indexes for web database, if we want to create also for master database we need to modify strategy section
Above is the result of our configuration:

Sitecoreindexes

Configuring Aliases in a multi site solution

On the last Sitecore solution I have worked I needed to add aliases for every site.

Default aliases are shared for all sites from the solution.

To acomplish requirements we create under the item  /sitecore/system/Aliases folders for every site.

SitecoreAliases

On site definition for every site we add a new property named alias

<site name=”countrytwo” patch:before=”site[@name=’website’]”
hostName=”countrytwo.sitecoredemo.com”
inherits=”sitecoremvc-base”
rootPath=”/sitecore/content/countrytwo”
startItem=”/”
dictionaryDomain=”{D8BC2E0C-36C5-4128-8F29-352B55E86676}”
language=”en”
alias=”countrytwo”
mvcArea=”countrytwo”

/>

We rewrite AliasResolver to map aliases to sites .

We need to rewrite the entire class Sitecore.Pipelines.HttpRequest.AliasResolver because the methods are private.

   
///<summary>
/// Custom Alias Resolver
/// </summary>


public class AliasResolver : HttpRequestProcessor
{
     ///<summary>
     /// Processes the specified args.
     /// </summary>
     /// <param name="args">The args.</param>
     public override void Process(HttpRequestArgs args)
     {
        Assert.ArgumentNotNull(args, "args");
        //check if aliases are active
        if (!Settings.AliasesActive)
        {
          Sitecore.Diagnostics.Log.Warn("Aliases are not active.",this);
          return;
         }
         Database database = Context.Database;
         if (database == null)
          {
            Sitecore.Diagnostics.Log.Warn("Context database is null",this);
            return;
          }

          if (database.Aliases.Exists(MainUtil.DecodeName('/' +                     Context.Site.Properties["alias"] + '/' + args.LocalPath)) &&                   !this.ProcessItem(args))
           {
              this.ProcessExternalUrl(args);
           }
       }

        ///<summary>
       /// Processes the external URL.
       /// </summary>
       /// <param name="args">The arguments.</param>
        private void ProcessExternalUrl(HttpRequestArgs args)
        {
          string targetUrl = Context.Database.Aliases.GetTargetUrl('/' +    Context.Site.Properties["alias"]+'/' +                                         args.LocalPath);
          if (targetUrl.Length > 0)
            {
              this.ProcessExternalUrl(targetUrl);
            }
         }

         ///<summary>
         /// Processes the external URL.
         /// </summary>
         /// <param name="path">The path.</param>
         private void ProcessExternalUrl(string path)
            {
              if (Context.Page.FilePath.Length > 0)
               {
                 return;
               }
                Context.Page.FilePath = path;
             }

          ///  <summary>
          /// Processes the item.
          /// </summary>
          /// <param name="args">The arguments.</param>
          /// <returns></returns>
          private bool ProcessItem(HttpRequestArgs args)
           {
             ID targetID = Context.Database.Aliases.GetTargetID(MainUtil.DecodeName('/'  + Context.Site.Properties["alias"]                     + '/' + args.LocalPath));
               if (!targetID.IsNull)
                {
                  Item item = args.GetItem(targetID);
                  if (item != null)
                   {
                    this.ProcessItem(args, item);
                   }
                   return true;
                  }
               return false;
             }

          ///<summary>
          /// Processes the item.
          /// </summary>
          /// <param name="args">The arguments.</param>
          /// <param name="target">The target.</param>
           private void ProcessItem(HttpRequestArgs args, Item target)
            {
              if (Context.Item == null)
              {
                 Context.Item = target;
               } 
                    }
       }

We replace default AliasResolver with new one, using a patch file:

   <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"     xmlns:set="http://www.sitecore.net/xmlconfig/set/">
      <sitecore>
         <pipelines>
          <httpRequestBegin>
             <processor type="Sitecore.Pipelines.HttpRequest.AliasResolver, Sitecore.Kernel">
              <patch:attribute name="type">Namespace.AliasResolver,Assembly</patch:attribute>
            </processor>
           </httpRequestBegin>
          </pipelines>
      </sitecore>
  </configuration>   
  

Next blog will be about how to create lucene indexes in a multisite solution.

How to set up a multi site solution in sitedefinition

This blog post is the start for a series o blog posts about implementing multisite solution with Sitecore.

Starting from version 6.4 in web.config we have a new attribute for sites in site definition

inherits: Indicates that the attributes should be inherited from another site. To enable inheritance, you must specify the name of the source site.
Attributes that are explicitly specified overwrite the attributes that are inherited from the source site.

We have a solution with 3 sites like in below picture:

Countries

For a multi site solution we are defining a base website and we inherit from it.

First declare base website

<site name=”sitecoremvc-base”
patch:before=”site[@name=’website’]”
hostName=”*”
enableTracking=”true”
virtualFolder=”/”
physicalFolder=”/”
rootPath=”/sitecore/content”
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” />

and now we need to declare country sites:

<site name=”countrythree” patch:before=”site[@name=’website’]”
hostName=”countrythree.sitecoredemo.com”
inherits=”sitecoremvc-base”
rootPath=”/sitecore/content/countrythree”
startItem=”/”
dictionaryDomain=”{D8BC2E0C-36C5-4128-8F29-352B55E86676}”
language=”en”
alias=”countrythree”
mvcArea=”countrythree”
/>

<site name=”countrytwo” patch:before=”site[@name=’website’]”
hostName=”countrytwo.sitecoredemo.com”
inherits=”sitecoremvc-base”
rootPath=”/sitecore/content/countrytwo”
startItem=”/”
dictionaryDomain=”{D8BC2E0C-36C5-4128-8F29-352B55E86676}”
language=”en”
alias=”countrytwo”
mvcArea=”countrytwo”

/>
<site name=”countryone” patch:before=”site[@name=’website’]”
hostName=”countryone.sitecoredemo.com”
inherits=”sitecoremvc-base”
rootPath=”/sitecore/content/countryone”
startItem=”/”
dictionaryDomain=”{D8BC2E0C-36C5-4128-8F29-352B55E86676}”
language=”de-de”
alias=”countryone”
mvcArea=”countryone”
/>

In my site definition  I have alias attribute for everysite, I will write about it “How to set up aliases in a multisite solution.

Assign workflow through Sitecore Item Web Api

The Sitecore Item Web API allows developers to manipulate Sitecore content items through HTTP requests. The API allows access to content via items paths, IDs, and Sitecore queries. The service produces output in JSON format and is both highly customizable and optimized to support a minimum number of requests.

Sitecore Item Web Api doesn’t provide out of the box functionality for assigning workflow through Sitecore Item Web Api.

To create an item, you can use the HTTP POST method in an Item Web API request.
The required query string parameters are:
 template — specifies the template that the new item is based on.
This parameter accepts the following values:
o The template ID
o The relative template path, for example, Sample/MyTemplate
o The branch ID
 name — specifies the name of the item being created.
It must be a valid Sitecore item name.

Creating an Item from a Template
To create an item called MyItem that is based on the Sample Item template in the master database,
use a URL in the following format:
http://<host_name>/-/item/v1/sitecore/Content/Home?name=MyItem&template=Sample/Sample Item&sc_database=master

To create items, you must add Content-Type=x-www-form-urlencoded HTTP Header to request.

To have such a feature we need to do small changes:

Create a new class :

using Sitecore.Configuration;
using Sitecore.ItemWebApi.Pipelines.Create;

namespace Sitecore.WebApi
{
    /// <summary>
   /// UpdateWorkflow 
   /// </summary>
   public class UpdateWorkflow : CreateProcessor
   {
    /// <summary>
   /// Processes the specified arguments.
   /// </summary>
   /// <param name="arguments">The arguments.</param>
    public override void Process(CreateArgs arguments)
    {
     foreach (var currentItem in arguments.Scope)
     {
      //get default workflow id for created item
      var workflowId = currentItem.Fields["__Default workflow"].Value;
      var workflow = Factory.GetDatabase("master").WorkflowProvider.GetWorkflow(workflowId);
      // start the workflow
      workflow.Start(currentItem);
      }
    }
 }
}

Also we need to add this new processor to config files .

In Sitecore.ItemWebApi.config we will add this new processor

 <itemWebApiCreate>
 <processor type="Sitecore.ItemWebApi.Pipelines.Create.CreateItem, Sitecore.ItemWebApi" />
 <processor type="Sitecore.ItemWebApi.Pipelines.Create.TryUpdate, Sitecore.ItemWebApi" />
 <processor type="Sitecore.WebApi.UpdateWorkflow,Sitecore.WebApi"/>
 <processor type="Sitecore.ItemWebApi.Pipelines.Create.SetResult, Sitecore.ItemWebApi" />
</itemWebApiCreate>

For testing Sitecore Web Api I found a Chrome extension  :https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm/related  that is really cool and easy to use for restfull service.

SVG files in Sitecore Media Library

Unfortunately, Sitecore CMS does not support SVG images out of the box.
If you upload a SVG image, Sitecore will not process it as an image, but processes as a common media file. Thumbnails generation also does not work for a SVG image.
However, in most cases it should work fine if you try to render a SVG image on a front-end web site.
To have svg files into media library you need to add media type for svg :
Please try use the following media type definition for SVG type:
<mediaType name=”SVG image” extensions=”svg”>
  <mimeType>image/svg+xml</mimeType>
  <forceDownload>false</forceDownload>
  <sharedTemplate>system/media/unversioned/image</sharedTemplate>
  <versionedTemplate>system/media/versioned/image</versionedTemplate>
  <mediaValidator type=”Sitecore.Resources.Media.ImageValidator”/>
  <thumbnails>
    <generator type=”Sitecore.Resources.Media.ImageThumbnailGenerator, Sitecore.Kernel”>
      <extension>png</extension>
    </generator>
    <width>150</width>
    <height>150</height>
    <backgroundColor>#FFFFFF</backgroundColor>
  </thumbnails>
 </mediaType>