Skip to main content
add info on image browsing and config
Source Link
Adam Seabridge
  • 9.4k
  • 1
  • 33
  • 73

I got asked recently If I ever solved this in an elegant way. The simple answer is unfortunately not. I had to duplicate the image field and add in my service to resolve the paths and also over-ride the Choose image dialog in experience editor (similar to this post: https://sitecoreoverload.blogspot.com/2018/09/adding-dynamic-image-source-for-multi.html). Below isare the changes I made and code I ended up with for 8.2 u7 but thisthe code may differ slightly for 9.x and above so please double check it against your version:

MultisiteImage.cs

/// <summary>
/// Copy of out of the box image field to support resolving Multisite Image paths
/// this is now used for all components with images as it needs to be referenced instead of the out of the box one in order to achieve this
/// </summary>
public class MultiSiteImage : Image
{
    public IMultisiteService MultisiteService { get; set; }
    
    public MultiSiteImage()
    {
           IMultisiteService = LocatorContainerManager.Current.Resolve<IIMultisiteService>(); 
    }

    protected new void BrowseImage(ClientPipelineArgs args)
    {
        Assert.ArgumentNotNull((object) args, nameof (args));
      
        if (!args.IsPostBack)
        {
            //default image path
            string path = StringUtil.GetString(this.Source, "/sitecore/media library");

            //resolve Image Field DataSource Path here with some kind of service
            var imagePath = IMultisiteService.GetImageFieldDatasourcePath(path, args, this);

            if(!string.IsNullOrEmpty(imagePath)){
                Source = imagePath;
            }
        }
        //check the path exists
        if (!string.IsNullOrEmpty(Source)){
            Item sourceItem = Client.ContentDatabase.GetItem(Source);
            if(sourceItem == null){
                throw new ClientAlertException($"The source of this Image field points to an item that does not exist: {Source}."); 
            }
        }
        base.BrowseImage(args);
    }

}

note: please replace the Multisite Service and methods with your own.

Core DB Update

Ensure you update the out of the box image field in the Core database to use the new class above instead of the out of the box image field: /sitecore/system/Field types/Simple Types/Image

MultisiteChooseImage.cs

/// <summary>
/// override out of the box image browser in experience editor to support resolving Multisites Image paths
/// </summary>
class MultisiteChooseImage : ChooseImage
{
    protected static void Run(ClientPipelineArgs args)
    {
        Assert.ArgumentNotNull((object)args, nameof(args));
        Item itemNotNull = Client.GetItemNotNull(args.Parameters["itemid"], Language.Parse(args.Parameters["language"]));
        itemNotNull.Fields.ReadAll();
        Field field = itemNotNull.Fields[args.Parameters["fieldid"]];
        Assert.IsNotNull((object)field, "field");
        ImageField imageField = new ImageField(field, field.Value);
        string parameter = args.Parameters["controlid"];
        string xml = args.Parameters["fieldValue"];
        if (args.IsPostBack)
        {
            if (!(args.Result != "undefined"))
                return;
            string empty;
            if (!string.IsNullOrEmpty(args.Result))
            {
                MediaItem mediaItem = (MediaItem)Client.ContentDatabase.GetItem(args.Result);
                if (mediaItem != null)
                {
                    imageField.SetAttribute("mediaid", mediaItem.ID.ToString());
                    if (xml.Length > 0)
                    {
                        XmlValue xmlValue = new XmlValue(xml, "image");
                        string attribute1 = xmlValue.GetAttribute("height");
                        if (!string.IsNullOrEmpty(attribute1))
                            imageField.Height = attribute1;
                        string attribute2 = xmlValue.GetAttribute("width");
                        if (!string.IsNullOrEmpty(attribute2))
                            imageField.Width = attribute2;
                    }
                }
                else
                    SheerResponse.Alert("Item not found.");
                empty = imageField.Value;
            }
            else
                empty = string.Empty;
            SheerResponse.SetAttribute("scHtmlValue", "value", WebEditImageCommand.RenderImage(args, empty));
            SheerResponse.SetAttribute("scPlainValue", "value", empty);
            SheerResponse.Eval("scSetHtmlValue('" + parameter + "')");
        }
        else
        {
            string str = StringUtil.GetString(field.Source, "/sitecore/media library");

            //service for multisite path resolution
            var MultisiteService = LocatorContainerManager.Current.Resolve<IMultisiteService>();

            //only continue if in Multisite context
            if (MultisiteService.IsMultisiteContext(itemNotNull.Paths.FullPath))
            {
                var siteName = MultisiteService.GetSiteName(itemNotNull.Paths.FullPath);
                var MultisitePath = MultisiteService.GetMultisiteComponentFolderPath(str, siteName, "");

                //check folder exists 
                var MultisitePathItem = itemNotNull.Database.GetItem(MultisitePath);
                if (MultisitePathItem != null)
                {
                    str = MultisitePath;
                }
                else
                {
                    //return the parent folder instead
                    str = MultisiteService.GetParentFolderPath(MultisitePath);
                }
            }

            if (xml.Length > 0)
                xml = new XmlValue(xml, "image").GetAttribute("mediaid");
            string path = xml;
            if (str.StartsWith("~", StringComparison.InvariantCulture))
            {
                if (string.IsNullOrEmpty(path))
                    path = StringUtil.Mid(str, 1);
                str = "/sitecore/media library";
            }
            Language language = itemNotNull.Language;
            MediaBrowserOptions mediaBrowserOptions = new MediaBrowserOptions();
            Item obj1 = Client.ContentDatabase.GetItem(str, language);
            if (obj1 == null)
                throw new ClientAlertException("The source of this Image field points to an item that does not exist.");
            mediaBrowserOptions.Root = obj1;
            mediaBrowserOptions.AllowEmpty = true;
            if (!string.IsNullOrEmpty(path))
            {
                Item obj2 = Client.ContentDatabase.GetItem(path, language);
                if (obj2 != null)
                    mediaBrowserOptions.SelectedItem = obj2;
            }
            SheerResponse.ShowModalDialog(mediaBrowserOptions.ToUrlString().ToString(), "1200px", "700px", string.Empty, true);
            args.WaitForPostBack();
        }
    }
}

note: please replace the Multisite Service and methods with your own.

Config Patch:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <commands>
      <command name="webedit:chooseimage" type="MyWebsite.Custom.Pipelines.MultisiteChooseImage, MyWebsite.Custom" />
    </commands>
  </sitecore>
</configuration>

The article linked above has a config patch for the field type as well but as the reference is directly changed in the Core DB it should work without a config patch.

I got asked recently If I ever solved this in an elegant way. The simple answer is unfortunately not. I had to duplicate the image field and add in my service to resolve the paths (similar to this post: https://sitecoreoverload.blogspot.com/2018/09/adding-dynamic-image-source-for-multi.html). Below is the code I ended up with for 8.2 u7 but this may differ slightly for 9.x and above:

/// <summary>
/// Copy of out of the box image field to support resolving Multisite Image paths
/// this is now used for all components with images as it needs to be referenced instead of the out of the box one in order to achieve this
/// </summary>
public class MultiSiteImage : Image
{
    public IMultisiteService MultisiteService { get; set; }
    
    public MultiSiteImage()
    {
           IMultisiteService = LocatorContainerManager.Current.Resolve<IIMultisiteService>(); 
    }

    protected new void BrowseImage(ClientPipelineArgs args)
    {
        Assert.ArgumentNotNull((object) args, nameof (args));
      
        if (!args.IsPostBack)
        {
            //default image path
            string path = StringUtil.GetString(this.Source, "/sitecore/media library");

            //resolve Image Field DataSource Path here with some kind of service
            var imagePath = IMultisiteService.GetImageFieldDatasourcePath(path, args, this);

            if(!string.IsNullOrEmpty(imagePath)){
                Source = imagePath;
            }
        }
        //check the path exists
        if (!string.IsNullOrEmpty(Source)){
            Item sourceItem = Client.ContentDatabase.GetItem(Source);
            if(sourceItem == null){
                throw new ClientAlertException($"The source of this Image field points to an item that does not exist: {Source}."); 
            }
        }
        base.BrowseImage(args);
    }

}

I got asked recently If I ever solved this in an elegant way. The simple answer is unfortunately not. I had to duplicate the image field and add in my service to resolve the paths and also over-ride the Choose image dialog in experience editor (similar to this post: https://sitecoreoverload.blogspot.com/2018/09/adding-dynamic-image-source-for-multi.html). Below are the changes I made and code I ended up with for 8.2 u7 but the code may differ slightly for 9.x and above so please double check it against your version:

MultisiteImage.cs

/// <summary>
/// Copy of out of the box image field to support resolving Multisite Image paths
/// this is now used for all components with images as it needs to be referenced instead of the out of the box one in order to achieve this
/// </summary>
public class MultiSiteImage : Image
{
    public IMultisiteService MultisiteService { get; set; }
    
    public MultiSiteImage()
    {
           IMultisiteService = LocatorContainerManager.Current.Resolve<IIMultisiteService>(); 
    }

    protected new void BrowseImage(ClientPipelineArgs args)
    {
        Assert.ArgumentNotNull((object) args, nameof (args));
      
        if (!args.IsPostBack)
        {
            //default image path
            string path = StringUtil.GetString(this.Source, "/sitecore/media library");

            //resolve Image Field DataSource Path here with some kind of service
            var imagePath = IMultisiteService.GetImageFieldDatasourcePath(path, args, this);

            if(!string.IsNullOrEmpty(imagePath)){
                Source = imagePath;
            }
        }
        //check the path exists
        if (!string.IsNullOrEmpty(Source)){
            Item sourceItem = Client.ContentDatabase.GetItem(Source);
            if(sourceItem == null){
                throw new ClientAlertException($"The source of this Image field points to an item that does not exist: {Source}."); 
            }
        }
        base.BrowseImage(args);
    }

}

note: please replace the Multisite Service and methods with your own.

Core DB Update

Ensure you update the out of the box image field in the Core database to use the new class above instead of the out of the box image field: /sitecore/system/Field types/Simple Types/Image

MultisiteChooseImage.cs

/// <summary>
/// override out of the box image browser in experience editor to support resolving Multisites Image paths
/// </summary>
class MultisiteChooseImage : ChooseImage
{
    protected static void Run(ClientPipelineArgs args)
    {
        Assert.ArgumentNotNull((object)args, nameof(args));
        Item itemNotNull = Client.GetItemNotNull(args.Parameters["itemid"], Language.Parse(args.Parameters["language"]));
        itemNotNull.Fields.ReadAll();
        Field field = itemNotNull.Fields[args.Parameters["fieldid"]];
        Assert.IsNotNull((object)field, "field");
        ImageField imageField = new ImageField(field, field.Value);
        string parameter = args.Parameters["controlid"];
        string xml = args.Parameters["fieldValue"];
        if (args.IsPostBack)
        {
            if (!(args.Result != "undefined"))
                return;
            string empty;
            if (!string.IsNullOrEmpty(args.Result))
            {
                MediaItem mediaItem = (MediaItem)Client.ContentDatabase.GetItem(args.Result);
                if (mediaItem != null)
                {
                    imageField.SetAttribute("mediaid", mediaItem.ID.ToString());
                    if (xml.Length > 0)
                    {
                        XmlValue xmlValue = new XmlValue(xml, "image");
                        string attribute1 = xmlValue.GetAttribute("height");
                        if (!string.IsNullOrEmpty(attribute1))
                            imageField.Height = attribute1;
                        string attribute2 = xmlValue.GetAttribute("width");
                        if (!string.IsNullOrEmpty(attribute2))
                            imageField.Width = attribute2;
                    }
                }
                else
                    SheerResponse.Alert("Item not found.");
                empty = imageField.Value;
            }
            else
                empty = string.Empty;
            SheerResponse.SetAttribute("scHtmlValue", "value", WebEditImageCommand.RenderImage(args, empty));
            SheerResponse.SetAttribute("scPlainValue", "value", empty);
            SheerResponse.Eval("scSetHtmlValue('" + parameter + "')");
        }
        else
        {
            string str = StringUtil.GetString(field.Source, "/sitecore/media library");

            //service for multisite path resolution
            var MultisiteService = LocatorContainerManager.Current.Resolve<IMultisiteService>();

            //only continue if in Multisite context
            if (MultisiteService.IsMultisiteContext(itemNotNull.Paths.FullPath))
            {
                var siteName = MultisiteService.GetSiteName(itemNotNull.Paths.FullPath);
                var MultisitePath = MultisiteService.GetMultisiteComponentFolderPath(str, siteName, "");

                //check folder exists 
                var MultisitePathItem = itemNotNull.Database.GetItem(MultisitePath);
                if (MultisitePathItem != null)
                {
                    str = MultisitePath;
                }
                else
                {
                    //return the parent folder instead
                    str = MultisiteService.GetParentFolderPath(MultisitePath);
                }
            }

            if (xml.Length > 0)
                xml = new XmlValue(xml, "image").GetAttribute("mediaid");
            string path = xml;
            if (str.StartsWith("~", StringComparison.InvariantCulture))
            {
                if (string.IsNullOrEmpty(path))
                    path = StringUtil.Mid(str, 1);
                str = "/sitecore/media library";
            }
            Language language = itemNotNull.Language;
            MediaBrowserOptions mediaBrowserOptions = new MediaBrowserOptions();
            Item obj1 = Client.ContentDatabase.GetItem(str, language);
            if (obj1 == null)
                throw new ClientAlertException("The source of this Image field points to an item that does not exist.");
            mediaBrowserOptions.Root = obj1;
            mediaBrowserOptions.AllowEmpty = true;
            if (!string.IsNullOrEmpty(path))
            {
                Item obj2 = Client.ContentDatabase.GetItem(path, language);
                if (obj2 != null)
                    mediaBrowserOptions.SelectedItem = obj2;
            }
            SheerResponse.ShowModalDialog(mediaBrowserOptions.ToUrlString().ToString(), "1200px", "700px", string.Empty, true);
            args.WaitForPostBack();
        }
    }
}

note: please replace the Multisite Service and methods with your own.

Config Patch:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <commands>
      <command name="webedit:chooseimage" type="MyWebsite.Custom.Pipelines.MultisiteChooseImage, MyWebsite.Custom" />
    </commands>
  </sitecore>
</configuration>

The article linked above has a config patch for the field type as well but as the reference is directly changed in the Core DB it should work without a config patch.

Source Link
Adam Seabridge
  • 9.4k
  • 1
  • 33
  • 73

I got asked recently If I ever solved this in an elegant way. The simple answer is unfortunately not. I had to duplicate the image field and add in my service to resolve the paths (similar to this post: https://sitecoreoverload.blogspot.com/2018/09/adding-dynamic-image-source-for-multi.html). Below is the code I ended up with for 8.2 u7 but this may differ slightly for 9.x and above:

/// <summary>
/// Copy of out of the box image field to support resolving Multisite Image paths
/// this is now used for all components with images as it needs to be referenced instead of the out of the box one in order to achieve this
/// </summary>
public class MultiSiteImage : Image
{
    public IMultisiteService MultisiteService { get; set; }
    
    public MultiSiteImage()
    {
           IMultisiteService = LocatorContainerManager.Current.Resolve<IIMultisiteService>(); 
    }

    protected new void BrowseImage(ClientPipelineArgs args)
    {
        Assert.ArgumentNotNull((object) args, nameof (args));
      
        if (!args.IsPostBack)
        {
            //default image path
            string path = StringUtil.GetString(this.Source, "/sitecore/media library");

            //resolve Image Field DataSource Path here with some kind of service
            var imagePath = IMultisiteService.GetImageFieldDatasourcePath(path, args, this);

            if(!string.IsNullOrEmpty(imagePath)){
                Source = imagePath;
            }
        }
        //check the path exists
        if (!string.IsNullOrEmpty(Source)){
            Item sourceItem = Client.ContentDatabase.GetItem(Source);
            if(sourceItem == null){
                throw new ClientAlertException($"The source of this Image field points to an item that does not exist: {Source}."); 
            }
        }
        base.BrowseImage(args);
    }

}