Jump to Content
Blog Archive
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.
newtelligence dasBlog 2.2.8279.16125
Email Me (Tim Gaunt)
© 2013 Tim Gaunt.
Sign In
uCommerce is a great e-commerce engine for Umbraco and high on our list of options when evaluating new e-commerce projects at The Site Doctor.
One thing that has always bugged me however is the lack of extensibility on the admin backend. This is something I've discussed with Søren in the past and I believe is on the cards to be resolved in the upcoming v3 release but we wanted to see if there was a way we could get it working in the current release. Thanks to Dan's digging we've found it is (ish).
Skip to the downloads.
Before I dive into the code and overview how you should get it all wired up, I think it's worth understanding how uCommerce is structured out of the box:
As we plan to alter the product details edit functionality, we'll need to make a few changes to EditProductBaseProperties.ascx. It's worth taking a quick look around the file if you've not before as we've re-ordered the boxes, added classes and hidden the SKU field before, all of which is often useful. You'll notice at the end of the file there's a repeater "ProductPropertyRepeater" -this is where uCommerce outputs the various custom properties you've setup.
Have you ever felt limited by the options of Text/Boolean/Enum/Image/Number and RichText and wished you could implement your own cool control like an image cropper or checkbox list? What about driving that control with data from Umbraco or another data source? If you have, this is the blog post for you as it handles all those scenarios.
If you don't want to know how to do this yourself you can click here to skip to the downloads and get started straight away.
Caution: If you want a CheckBoxList or your own custom control, you need to be running v2.6 as it adds IWebControlAdapter. As of v2.6 I'm not convinced IWebControlAdapter is fully implemented as it allows you to retrieve the value from the control but we will need to override the UserControl which outputs the control which feels hacky.
Unless you want a fairly standard control (TextBox, CheckBox, DropDownList or ContentPickerUCommerce) you'll need to create a control which uses the IWebControlAdapter interface. This will mean uCommerce is able to get the value from it. You will need to implement two methods:
namespace TheSiteDoctor.Web.uCommerce.Admin.UI { using System.Web.UI; using System.Web.UI.WebControls; using System.Linq; using UCommerce.Presentation.Web.Controls; public class UCommerceUmbracoDrivenCheckboxList : CheckBoxList, IWebControlAdapter { public bool Adapts(Control control) { return control is UCommerceUmbracoDrivenCheckboxList; } public object GetValue(object control) { var li = (UCommerceUmbracoDrivenCheckboxList)control; var values = (from ListItem listitem in li.Items where listitem.Selected select listitem.Value).ToList(); return string.Join(",", values); } } }
uCommerce uses DataTypeControlFactory to determine what control to render in the editor so you'll need to override the default implementation because it doesn't look for IWebControlAdapters at the moment.
This is simple enough, it needs to accept a Page (the page you'll be adding the control to) and the work out what control it should output e.g.:
public class CustomDataTypeControlFactory : DataTypeControlFactory { Page _page; public CustomDataTypeControlFactory(Page page) : base(page) { _page = page; } public Control CreateCustomControl(IProductProperty productProperty) { if (productProperty == null) throw new ArgumentNullException("productProperty"); return CreateCustomControl(productProperty.ProductDefinitionField, productProperty.Value); } private Control CreateCustomControl(ProductDefinitionField productDefinitionField, string value) { var fieldType = productDefinitionField.DataType.TypeName; if (fieldType.StartsWith("Something")) return base.CreateControl(productDefinitionField, value); // Some logic to work out whether you should be creating the control return customControl; } }
Now you'll need to create your own ProductPropertyEditor.ascx which calls your new DataTypeControlFactory:
public partial class CustomUcommerceProductPropertyEditor : ProductPropertyEditor { protected new void Page_Load(object sender, EventArgs e) { InitializeControl(); } public override void DataBind() { base.DataBind(); } private void InitializeControl() { Controls.Clear(); Control child = CreateControlToRender(); Controls.Add(child); } private Control CreateControlToRender() { if (ProductProperty == null) { throw new InvalidOperationException("Cannot create control, ProductProperty not set."); } var factory = new CustomDataTypeControlFactory(Page); return factory.CreateCustomControl(ProductProperty); } }
You may notice that we're clearing the controls in the InitializeControl which is called from Page_Load whereas uCommerce makes the same call from DataBind(); this is intentional. I've not yet figured out why but if you don't do it from Page_Load, uCommerce still outputs a TextBox.
To get this all outputting, you now need to replace the call to ProductPropertyEditor in EditProductBaseProperties.ascx with a reference to your own ASCX file, you can do this by updating this line:
<%@ Register Src="~/Umbraco/UCommerce/Controls/ProductPropertyEditor.ascx" TagPrefix="commerce" TagName="ProductPropertyEditor" %>
<%@ Register Src="~/Umbraco/UCommerce/Controls/[YourFileNameHere].ascx" TagPrefix="commerce" TagName="ProductPropertyEditor" %>
At this point if you were to load up your uCommerce backend you'd find that it outputs as intended but when you saved the file you'd either get an error or the value doesn't save. The reason for this is although you've replaced the display aspect of the editor, uCommerce is still looking at it's old "GetValue" implementation instead of your new control.
Open /umbraco/ucommerce/configuration/presenters.config and add a reference to your control which implements the IWebControlAdapters interface:
<component id="UCommerceUmbracoDrivenCheckboxList" service="UCommerce.Presentation.Web.Controls.IWebControlAdapter, UCommerce.Presentation" type="Your.Custom.uCommerce.Namespace.ControlName, Your.Custom.uCommerce.AssemblyName" lifestyle="PerWebRequest"/>
That's it, you're done, you can now add your own controls to the backend of uCommerce.
To make life easier I've packaged the files up into an Umbraco package and have also added the source:
Download the source code with references (C#) - 800KB
Download the Umbraco Package - 12KB
If you download the source code you may have noticed we're doing some funky things with the DataTypeName. The idea behind the control is that it allows us to output a DropDownList or CheckBoxList containing values based on a Document Type and start node purely from the name of the DataType.
I can go into more detail about how we're doing this if it's of interest, just leave me a comment below but to start using it straight away you will need to use the following naming convention for your DataType's name:
Example: if you wanted a list of checkboxes for ShapeType (as above) then your name would be: TSD_chkl_1234_ShapeType and a DropDownList would be: TSD_ddl_1234_ShapeType
This is something we're using more and more in uCommerce these days as it allows us to use the power of Umbraco to power uCommerce which is allowing us to do some really interesting things. Although we'll only be developing it as we need it at the moment we do have plans to add support for:
Don't forget to follow me on Twitter.
Remember Me