Brian McKeiver's Blog

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.