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.