Convert Existing Documents to Products via Kentico CMS API
Introduction
A very common request that my team and I receive at BizStream revolves around adding on a new chunk of functionality to a web site. This request can come in the form of social media integration or a customer feedback form, but 9 times out of 10 it has to do with adding e-commerce functionality to an existing site. This type of work is very common for sites that have been around for awhile or previously acted as just a brochure type site.
These sites commonly already had product pages defined, but were only intended to serve out information about each product or service a company offers. As a web site grows, the logical next steps are to add the infamous “Buy Now” button, configure e-commerce store settings, hook up a payment gateway, and start collecting more revenue (hopefully).
The above steps are all easy to do if the site is built with content management system like Kentico, but what if the site has 100, 500, or even 1,000 products that already exist? I sure would not want to create those SKUs by hand. This scenario is a perfect time to use some automation to solve the problem. Below is an example code snippet that used the Kentico CMS API to accomplish this task.
The Code
The code below does two main things. It first correctly maps a Document Type in Kentico to a Product Document type. In essence the code handles the field mapping of what field in your custom object should be the SKU’s name, price, description of the product, and image. The second main function of the code is to traverse through the content tree and find any documents of that Document Type or class, and convert them to be a product SKU. After the code is done running you should then have products showing up on your E-Commerce tab in CMSDesk. You can throw this code on a new web form inside of ~/CMSPages directory and it should run in your instance of Kentico CMS.
using System; using System.Data; using CMS.Ecommerce; using CMS.CMSHelper; using CMS.SettingsProvider; using CMS.GlobalHelper; using CMS.SiteProvider; using CMS.DocumentEngine; using CMS.EventLog; using TreeNode = CMS.DocumentEngine.TreeNode; public partial class ConvertDocTypeToProduct : System.Web.UI.Page { private TreeProvider _tree = null; protected void Page_Load(object sender, EventArgs e) { ConvertDocumentTypes(); } private void ConvertDocumentTypes() { // Get our Tree Provider from user info UserInfo ui = UserInfoProvider.GetUserInfo("Administrator"); if (ui != null) { _tree = new TreeProvider(ui); } else { _tree = new TreeProvider(); } //Query all Document Types in the Kentico Site DataSet dsClasses = DataClassInfoProvider.GetAllDataClass(); // Get product default department DepartmentInfo defaultDepartment = GetDefaultDepartment(); //Iterate through each Documnent Type and if name starts with matching token, convert it to product doc type // You could do just one if you want instead of all foreach (DataRow dr in dsClasses.Tables[0].Rows) { if (!dr.IsNull("ClassName")) { if (dr["ClassName"].ToString().Contains("MyCustomProductNamePrefix")) { DataClassInfo docType = new DataClassInfo(dr); try { //optional step to make sure Document Type is marked as Product, and key fields are mapped to SKU fields ConvertDocumentTypeToProductDocumentType(docType); //The real work starts here, converts all documents, in the content tree of a given document type, to products in SKU table CreateProductSKUFromDocumetNode(docType, defaultDepartment); } catch (Exception ex) { EventLogProvider.LogException("CustomScript", "ERROR", ex); } } } } } private void ConvertDocumentTypeToProductDocumentType(DataClassInfo DocumentType) { if (DocumentType == null) return; if (!DocumentType.ClassIsProduct) { //Set Document Type to Product Document Type DocumentType.ClassIsProduct = true; DocumentType.ClassIsCoupledClass = true; DocumentType.ClassCreateSKU = true; //Start mapping fields, the field names on the right are what your custom document type fields are DocumentType.SKUMappings["SKUName"] = "ProductName"; DocumentType.SKUMappings["SKUShortDescription"] = "ShortDescription"; DocumentType.SKUMappings["SKUDescription"] = "Description"; DocumentType.SKUMappings["SKUPrice"] = "Price"; DocumentType.SKUMappings["SKUImagePath"] = "MainImage"; //Save changes DataClassInfoProvider.SetDataClass(DocumentType); } } private void CreateProductSKUFromDocumetNode(DataClassInfo ProductDocumentType, DepartmentInfo DefaultDepartment) { if ((DefaultDepartment == null) || (ProductDocumentType == null)) { throw new Exception("Unable to create products, some information missing"); } else { // Fill dataset with documents that match given path DataSet documents = _tree.SelectNodes(CMSContext.CurrentSiteName, "/Products/%", "en-us", false, ProductDocumentType.ClassName); if (!DataHelper.DataSourceIsEmpty(documents)) { // Loop through all documents foreach (DataRow documentRow in documents.Tables[0].Rows) { // Create a new Tree node from the data row TreeNode doc = TreeNode.New(documentRow, documentRow["ClassName"].ToString(), _tree); //if there is no product continue adding a new one if (doc.NodeSKUID <= 0) { // Create new product object SKUInfo newProduct = new SKUInfo(); // Set the properties, map from original custom fields, field names on right are what your custom document type fields are newProduct.SKUName = doc.DocumentName; newProduct.SKUPrice = ValidationHelper.GetDouble(doc.GetValue("Price"), 0); newProduct.SKUDescription = ValidationHelper.GetString(doc.GetValue("Description"), string.Empty); newProduct.SetValue("SKUShortDescription", ValidationHelper.GetString(doc.GetValue("ShortDescription"), string.Empty)); newProduct.SKUImagePath = ValidationHelper.GetString(doc.GetValue("MainImage"), string.Empty); newProduct.SKUEnabled = true; //set the default department if (DefaultDepartment != null) { newProduct.SKUDepartmentID = DefaultDepartment.DepartmentID; } //associate product to site newProduct.SKUSiteID = CMSContext.CurrentSiteID; // Create the product SKUInfoProvider.SetSKUInfo(newProduct); //associate product to document doc.NodeSKUID = newProduct.SKUID; //save document changes doc.Update(); } } } } } ////// Ensures default department exists. /// private DepartmentInfo GetDefaultDepartment() { // Try to get default department DepartmentInfo defaultDepartment = DepartmentInfoProvider.GetDepartmentInfo("DefaultDepartment", CMSContext.CurrentSiteName); // If default department doesnt exist, create new one if (defaultDepartment == null) { defaultDepartment = new DepartmentInfo(); defaultDepartment.DepartmentDisplayName = "Default department"; defaultDepartment.DepartmentName = "DefaultDepartment"; defaultDepartment.DepartmentDefaultTaxClassID = 0; defaultDepartment.DepartmentSiteID = CMSContext.CurrentSiteID; DepartmentInfoProvider.SetDepartmentInfo(defaultDepartment); } return defaultDepartment; } }
Conclusion
There you have it. Remember, this code snippet is really meant to be a simple example of how to do this. Please don’t copy and paste and run it exactly as is in a production environment.