Episerver Commerce: Creating a new block
Refer to this blog post: https://world.optimizely.com/blogs/david-harlow/dates/2018/3/extending-commerce---content-area-functionality/
By default, content areas in Episerver commerce items such as products and variants don't display the option for creating a new block, and only allows for blocks to be dragged in, as seen below.
However, an extremely simple solution to change this default behavior is to inherit from IResourceable on your product/variant which will require the interface member ContentAssetsID to be declared which can simply be scaffolded to false, and this will be all the code required to display the content area as expected!
But there could be issue with permission when another user is not an administrator try to create a block:In the developer tools there's an error (500 or 403) when sending POST to /EPiServer/cms/Stores/contentdata/. There's nothing interesting in the response as error handling causes it to just say "something went wrong"
By default, content areas in Episerver commerce items such as products and variants don't display the option for creating a new block, and only allows for blocks to be dragged in, as seen below.
However, an extremely simple solution to change this default behavior is to inherit from IResourceable on your product/variant which will require the interface member ContentAssetsID to be declared which can simply be scaffolded to false, and this will be all the code required to display the content area as expected!
public class FashionProduct : ProductContent, IResourceable
{
[Editable(false)]
[ScaffoldColumn(false)]
public virtual string ProductContentAssetId { get; set; }
[Ignore]
public Guid ContentAssetsID
{
get { return !string.IsNullOrEmpty(ProductContentAssetId) ? new Guid(NodeContentAssetId) : Guid.Empty; }
set { ProductContentAssetId = value.ToString(); }
}
[CultureSpecific]
[Display(Name = "Test content area", Order = 2)]
[AllowedTypes(new[] { typeof(IContentData) })]
public virtual ContentArea TestContentArea { get; set; }
}
But there could be issue with permission when another user is not an administrator try to create a block:
EPiServer.Core.AccessDeniedException: Access was denied to content 623. The required access level was "Create, Publish".
at EPiServer.Core.Internal.DefaultContentRepository.CheckSufficientAccess(ContentProvider provider, ContentReference contentLink, AccessLevel access)
at EPiServer.Core.Internal.DefaultContentRepository.Save(IContent content, SaveAction action, AccessLevel access)
at EPiServer.Cms.Shell.Service.Internal.ContentService.Save(IContent content, SaveAction saveAction, AccessLevel accessLevel)
at EPiServer.Cms.Shell.Service.Internal.ContentService.Save(IContent content, SaveAction saveAction)
at EPiServer.Cms.Shell.UI.Rest.ContentChangeManager.CreateContent(ContentReference parentLink, Int32 contentTypeId, Nullable`1 resourceFolderId, Boolean createAsLocalAsset, String name, IDictionary`2 properties, SaveAction saveAction)
at EPiServer.Cms.Shell.UI.Rest.ContentChangeManager.CreateContent(ContentReference parentLink, Int32 contentTypeId, Nullable`1 resourceFolderId, Boolean createAsLocalAsset, String name, IDictionary`2 properties, Boolean autoPublish)
at EPiServer.Cms.Shell.UI.Rest.ContentChangeManager.Create(ContentReference parentLink, Int32 contentTypeId, Nullable`1 resourceFolderId, Boolean createAsLocalAsset, String name, IDictionary`2 properties, Boolean autoPublish)
at EPiServer.Cms.Shell.UI.Rest.Internal.ContentDataStore.Post(PostContentModel entity)
If you check that content in the database, it's Content Assets Folder with content type id is 4
As Quan Mai pointed out, it became clear that products (and entries in general) do not have their own ACL settings but inherit from their direct parents. To solve this problem, we would need to implement IContentSecurable to the entries and return the node's security descriptor:
public class FashionProduct : ProductContent, IContentSecurable
{
public IContentSecurityDescriptor GetContentSecurityDescriptor() => this.GetParentNode().GetContentSecurityDescriptor();
}
public static class EntryContentBaseExtensions
{
public static NodeContent GetParentNode(this EntryContentBase entryContentBase)
{
return ServiceLocator.Current.GetInstance<IContentLoader>().Get<NodeContent> (entryContentBase.ParentLink);
}
}
Comments
Post a Comment