E-commerce Product Editors

Customer's Canvas provides a powerful API for web-to-print solutions. You can easily integrate this API into any website or e-commerce platform no matter what server technology you use. On the other hand, some tasks - such as integration into e-commerce systems - are routine, and many of our customers have to implement very similar functionality over and over again.

To simplify this process, Aurigma has developed a new technology that helps connect Customer's Canvas with any e-commerce system with minimal effort. From a technical point of view, it is a series of JavaScript applications that we call Product editors. Unlike Customer's Canvas, which operates with PSD templates and images, a Product editor is a higher-level application that works with product options, attributes, variants, etc. It knows as much about the product as your e-commerce system.

Let us see how an e-commerce product editor works.

Obtaining the Latest Product Editors

At the moment, the current Customer's Canvas distribution does not include Product editors. Please contact info@aurigma.com for the actual version of this editor. We will start publishing it on our website soon.

Also, you can download a package containing assets, configuration data, a sample page, and the Customer's Canvas templates used in this sample page.

Getting Started

You can find a fully-working sample in the sample.html file. Note that, to get it working with your Customer's Canvas instance, you should set the customersCanvasUrl property in this file to a URL to your Customer's Canvas instance. Also, if you did not copy our sample designs to your Customer's Canvas folder, make sure that the data\product\simple-business-card.json file refers to an existing PSD template.

JavaScript
{
    "id": 0,
    "sku": "DEFAULT-001",
    "name": "Business Card #1",
    "description": "A default product for demo.",
    "options": [],
    "price": 0.16,
    "attributes": [{
        "id": 0,
        "name": "Template",
        "value": "business-card/simple"
    }]
}

Here, the value property points to the PSD file relative to the cc-data\ProductTemplates\designs folder of your Customer's Canvas instance. Note, you should omit the .psd extension. In other words, it is the same syntax as you use to refer to PSD templates in Customer's Canvas.

Now, let us see how you can create such a webpage from scratch.

Step 1. Prepare

The Product editor is loaded to the page using RequireJS. Code examples in this topic demonstrate how you can use this technology to load the Product editor.

Download RequireJS files from here:
http://requirejs.org/docs/download.html

Put it into a folder on your server where you keep your JavaScript libraries. In addition, you need to put the ecommerce-driver.js file, enclosed with the Product editor package, to the same location.

At last, you must put the folder containing the Product editor files in a designated location (it may be located in the same folder or somewhere else on your server). We release new versions of the editors quite frequently, so it makes sense to organize each version in a separate subfolder of a root folder for all editors.

In our examples, we assume that you are using the following folder structure:

  • \editors\base-<version>\
  • \assets\ecommerce-driver.js
  • \assets\requirejs\require.js
  • \sample.html

Step 2. Configure RequireJS

First, add a link to RequireJS to the page.

<script src="assets/requirejs/require.js"></script>

The following code allows RequireJS to know where to search for the editor modules.

JavaScript
require.config({
    baseUrl: '/assets',
    paths: { "editors": "/editors" }
});

Note, this should be executed before you try to load the editor. A good place to do this is the document load event handler.

After that, you can add some code that loads the editor to the page. It can be located on a button click event handler or just on the page load. The code that loads the editor looks like this:

JavaScript
require(['ecommerce-driver', 'editors/base-1.1.5/editor'], function (driver, editor) {
    // Define the Customer's Canvas URL.
    var settings = {
        customersCanvasUrl: "http://localhost:8181"
    };
    // The order data, which the editor returns.
    var restoreData = null;
    var quantity = 1;

    // Initialize the driver with a product model, editor instance, config,
    // data returned by the editor, and an item's quantity (when it is necessary).
    driver.init(productModel, editor, configParams, settings, restoreData, quantity);

    // Embed the editor into the specified DIV element.
    driver.products.current.renderEditor($("#aurigma-editor-root")[0]);

    // Define a callback, which is called when the user finishes editing.
    // You should insert the code which sends the product order to a shopping cart.
    driver.orders.current.onSubmit = function(data) {
        // This callback returns the hi-res URLs, preview images, and the data
        // used to restore the state of the editor.
        console.log(data);
    };
});

You can find descriptions of productModel and configParams in the following paragraphs. In this code, after loading the e-commerce driver and editor itself, the Product editor goes through the following basic steps:

  1. Initializing the driver with the Customer's Canvas link, product model (including product options and attributes), and the editor configuration. In reality, you retrieve the model and configuration from your e-commerce database.
  2. Embedding the editor into a webpage. You can provide an empty DIV element on either a visible area, hidden page, or modal dialog.
    <div id="aurigma-editor-root"></div>
  3. Processing the results returned to the onSubmit callback, which is called by the editor when the user finishes the product editing. In our example, we just display the data in the console, but in the real life application, it is the right place to create an order and attach this data to the user's shopping cart.

Now, let us see how these new objects can be operated: the e-commerce driver, product model, and editor configuration.

The E-commerce Driver

The Product editor works with entities from your e-commerce system. If there were a single e-commerce system, then the editor could work with the data structure of this system directly. Since there is a number of e-commerce systems, and we did not want to create a separate editor for each of them, we designed an abstraction layer called e-commerce driver. This is similar to the other drivers that were designed to handle different devices in operating systems. Just how Windows does not work with a mouse directly and uses a driver to communicate with it, the Product editor talks with your Magento, WooCommerce, or Shopify through the e-commerce driver.

From the point of view of a developer integrating the Product editor with an e-commerce system, the role of the e-commerce driver is mainly to convert such entities like a product, options (or variants), specification attributes, order, etc. to the model supported by the Product editor.

In our example, the product model comes from a JSON file stored at data\product\simple-business-card.json. In your application, you might want to replace it with the data gathered from your e-commerce system. You just prepare a JSON structure, which we will describe in the next section, and pass it to the driver.init method as shown in the previous example.

Now, let us describe this JSON object in detail.

The Product Model

The product editor accepts product models in the following form.

JavaScript
productModel = {
    id: 1234, // A unique identifier from your e-commerce system.
    sku: "P01234-172", // An alphanumeric code of the product.
    name: "Invitation 0001234", // A display name.
    price: 5.3, // A non-negative number specifying the product price.
    description: "...", // Information about the product.
    options: [
        // An array of options.
    ],
    attributes: [
        // An array of attributes.
    ]
}

These fields are pretty common and typically found in any e-commerce system. You may omit most of them. However, you may wonder what the difference between options and attributes is.

The attributes may also be referred to as specification attributes or custom fields in e-commerce systems. These are product properties, which cannot be changed by the user. For example, if you sell mobile phones, these properties can be the manufacturer name and phone model. In this case, the attributes array may look as follows:

JavaScript
attributes = [{
    id: 0, // The numeric ID of the attribute.
    name: "Make", // An attribute name.
    value: "Apple" // An attribute value.
},
{
    id: 0,
    name: "Model",
    value: "iPhone X"
}]

The options are order parameters, which the user is supposed to change (typically selected from a list of predefined values). For the example of mobile phones, they can be a phone color and add-ons like protective glass or a memory card. These user choices should be included into orders and may affect the order price. An object representing the options looks as follows:

JavaScript
options = [{
    id: 123, // The numeric ID of an option from your database.
    title: 'Color', // The option title used to refer to it in configs, etc.
    prompt: 'Choose a phone color', // The information for a customer, appears in UI.
    description: 'detailed description', // A more detailed description.
    required: true, // Whether the user must select some value to proceed.
    type: "color", // One of list | radio | checkbox | text | textarea | color | image.
    values: [
     // For list | radio | color | image | checkbox you pass a list of possible values.
    ],
    defaultValue: '' // For text and textarea you can pass a default value here.
}]

The text and textarea options take a single value and the default. Other options take the result from selecting from a list of the following objects.

JavaScript
{
    id: 12, // The number of the option value in the list.
    name: 'Silver', // A display name.
    price: 100, // A value changing the resulting price, can be negative.
    preselected: true // Whether this value is preselected.
}

The color and image options have additional properties, color (in CSS format) and imageUrl, correspondingly.

So, to make a product model, you need to retrieve the information related to a product from your e-commerce system and convert this information into a JSON object as described in the previous examples. Then, pass this object to the e-commerce driver.

What if a product model of your e-commerce system cannot be defined by this structure? For example, some systems use variants instead of options. These variants may represent all possible combinations of product options. In this case, you have to develop another e-commerce driver in the same way as we developed the Shopify driver, for example.

The Editor Configuration

Along with the product model, the driver.init method accepts configParams, the editor's configuration. While the productModel describes the data from your e-commerce system, configParams defines the settings of the Product editor (and, in particular, Customer's Canvas).

Currently, Aurigma provides the base-editor. You can implement other Product editors, including, for example, pure Customer's Canvas, multipage editors, or an editor integrating the Web API of a photo uploader. Each Product editor has its own config structure.

Furthermore, in this topic, we explain the structure of the base-editor. Unless otherwise noted, the Product editor refers to the base-editor.

Let us describe configParams of the base-editor. This configuration has the following group of settings.

JavaScript
{
    productDefinition: {...}, // Product templates loaded into the editor.
    editorConfig: {...}, // The Customer's Canvas configuration.
    attributeNames: [], // The list of product attributes.
    conditions: [], // The association of options with actions to be performed when users switch the options.
    steps: {
        editor: {
            optionNames: [], // The option list you want to enable in the editor.
        }, 
        approve: {
            ...
        }    
    }, // The sequence of editing steps.
    language: 'en' // The localization language.
}

The productDefinition and editorConfig are the same structures that you pass to the Customer's Canvas Iframe API (to the loadEditor method). Other objects are explained in the following sections.

References to a Product Model from the Configuration

Now, you can say "Ok, it is clear, I just need to define a configuration for a single product and pass a PSD template name with other product properties into this configuration." Actually, if you just hardcode a PSD filename to your configuration, it may become too cluttered because you have to create many similar JSON files. In addition, this can be hard to support if you need to add a property to a config because you have to update all your configs.

The Product editor allows you to have one configuration for a group of products, say, for a product category, and get the required data from your product model. This is implemented through product shortcuts. To use a shortcut, enclose a property or attribute in the % symbols.

JavaScript
productDefinition: {
    surfaces: ['%product.attributes.Template%']
}

When the editor processes this configuration, it gains the value of the Template attribute and replaces the string enclosed in the % symbols with this attribute value.

Note, you can use spaces and even non-ASCII symbols in shortcuts - just use the value you put in the name property of your Attribute object in the product model.

'%product.attributes.Front Template%'

In the same way, you can refer to the other elements of a product model from the editorConfig section. For example, if you have the sku_placeholder text field in your design and want to paste a product SKU into this field, pass the shortcut to userData as follows:

JavaScript
editorConfig: {
    autoLoadUserInfo: true,
    userData: {
        'sku_placeholder': '%product.sku%'
    }
}

The attributeNames Section

The previous example illustrated how you can refer to product attributes using shortcuts, like %product.attributes.AttributeName%. However, this method has a shortcoming. Say, when you rename an attribute, you need to change this attribute name in every occurrence. To avoid this, add the attributeNames section to configParams, which allows for defining attributes as follows:

JavaScript
"attributeNames": {
    "frontTemplate": {
        "name": "CoolTemplate_Front",
        "settings": {
            "type": "design"
        }
    }
}

After that, you can refer to this attribute as follows:

"%product.attributes.#attributeNames.frontTemplate#%"

If you decide to rename such an attribute, you only have to do this in the attributeNames section.

Another purpose of this section is keeping the attribute's metadata. It may be useful if you build an admin panel for editing product attributes based on a config (like it is implemented in our nopCommerce plugin).

The Customer's Canvas Configuration

If you are familiar with the Customer's Canvas API, you can skip this section. Otherwise, refer to the Configuring Products topics and Configuration Files. As a quick reminder, you can refer to the use cases in this section.

The Product Definition

To define a one-page design:

JavaScript
productDefinition = {
    surfaces: ["%product.attributes.#attributeNames.Template#%"]
};

To define a two-page design:

JavaScript
productDefinition = {
    surfaces: ["%product.attributes.Side 1%", "%product.attributes.Side 2%"]
};

To define a product with mockups:

JavaScript
productDefinition = {
    surfaces: [{
        printAreas: [{
            designFile: "%product.attributes.Template%"
        }],
        mockup: {
            // Set a foreground mockup, "RoundedCorners.psd".
            up: "RoundedCorners"
        }
    }]
};

Note, we have referred to a template through the attribute while the mockup is hardcoded. It is often convenient when you have the same mockup for all your products. If you would rather set different mockups for different products, a good idea would be to create a separate attribute for that.

To define mockups for 3D preview:

JavaScript
productDefinition = {
    surfaces: [{
        printAreas: [{
            designFile: "blank-design"
        }],
        mockup: {
            up: "%product.attributes.#attributeNames.Model#%/case-up",
            down: {
                previewMockupFiles: [
                    "%product.attributes.#attributeNames.Model#%/case-front-white",
                    "%product.attributes.#attributeNames.Model#%/case-3-4-white",
                    "%product.attributes.#attributeNames.Model#%/case-3d-white"
                ],
                mockupFile: "%product.attributes.#attributeNames.Model#%/case-white"
            }
        }
    }]
}

The scenarios this example shows are a bit different - if you have the same design file for all products (for example, a blank image), you can hardcode it rather than creating a separate attribute for it. However, our mockups depend on the phone model. We created the Model attribute and use it as a part of the path (for example, as a folder name). So you don't have to specify separate attributes for different perspectives of your preview images (as long as you follow the certain naming conventions of your mockup files).

The Editor Configuration

editorConfig configures the editor for a single product. If all your products are the same, you can use the clientConfig.json file of your Customer's Canvas instance instead. However, in practice, you may need to fine-tune Customer's Canvas for each product category. Let us consider a number of configuration examples.

To enable the simple edit mode allowing for changing only the content of design elements:

JavaScript
editorConfig = {
    initialMode: "SimpleOnly"
};

To enable watermarks and display the ObjectInspector on the right side of the editor:

JavaScript
editorConfig = {
    watermark: {
        text: {
            text: "watermark",
            opacity: 0.5
        },
        visibility: {
            proof: true,
            canvas: true
        }
    },
    widgets: {
        ObjectInspector: {
            position: "Right"
        }
    }
};

To enable the Logos, Backgrounds, and My Files tabs in the Gallery and add the Image and Background buttons to the LeftToolbar:

JavaScript
editorConfig = {
    initialMode: "Advanced",
    widgets: {
        LeftToolbar: {
            buttons: [
                "ToggleObjectInspector",
                "Text",
                {
                    "translationKey": "LeftToolbar.ADD_IMAGE",
                    "translationKeyTitle": "LeftToolbar.TITLE_ADD_IMAGE",
                    "iconClass": "cc-icon-add-image",
                    "action": "Image",
                    "tabs": ["Logos", "My Files"]
                },
                {
                    "translationKey": "LeftToolbar.CHANGE_BACKGROUND",
                    "translationKeyTitle": "LeftToolbar.TITLE_CHANGE_BACKGROUND",
                    "iconClass": "cc_icon_background",
                    "action": "Background",
                    "tabs": ["Backgrounds", "My Files"]
                }
            ]
        },
        GalleryDialog: {
            "publicFolderName": "business-card",
            "defaultTab": "public",
            "tabs": [
                {
                    "name": "Backgrounds",
                    "type": "public",
                    "subFolderName": "business-card\\Backgrounds",
                    "categoriesEnabled": false,
                    "canEdit": false
                },
                {
                    "name": "Logos",
                    "type": "public",
                    "subFolderName": "business-card\\Logos",
                    "categoriesEnabled": false,
                    "canEdit": false
                },
                {
                    "name": "My Files",
                    "type": "user",
                    "categoriesEnabled": true,
                    "canEdit": true,
                    "canUpload": true
                }
            ]
        }
    }
};

To disable toolbars, rulers, and the ObjectInspector:

JavaScript
editorConfig = {
    initialMode: "SimpleOnly",
    canvas: {
        rulers: {
            "enabled": false
        }
    },
    widgets: {
        LeftToolbar: {
            buttons: []
        },
        BottomToolbar: {
            "snapLinesCheckboxEnabled": false,
            "gridCheckboxEnabled": false
        },
        ObjectInspector: {
            "isHidden": true
        },
        FinishButton: {
            "mode": "Disabled"
        }
    }
};

For more examples and the description of the Customer's Canvas Iframe API, you can refer to the corresponding topics.

Product Options

Options make the base-editor more than just a handy Customer's Canvas wrapper. By using them, the ordering process becomes more interactive. For example, users can select the shape of the product's edges and the editor immediately overlays a mockup visualizing such edges. Also, users can select a color theme and the product design automatically applies this color.

You can find a product and config example that illustrate working with product options in the data\product\business-card-options.json and data\config\business-card-options.json files. In this topic, you can find details on how to create them yourself.

The first thing you should do is pass the necessary options to the product model as explained above.

However, the base-editor does not use all these options by default. You may want to prevent Customer's Canvas from showing certain options in its interface. That's why it is necessary to explicitly list the options you want to show.

To do this, use the steps.editor.optionNames section. It holds the names of the options that are available in the product model. For example, to display the Paper Type and Cut Corners options, list their names in this array.

JavaScript
"steps": {
    "editor": {
        "optionNames": [ "Paper Type", "Cut Corners" ]
    }
}

You can find more details about the steps object further in this topic.

Now, if you reload the webpage containing these options, you can see that they are displayed, but when you switch these options, nothing happens. To define what actions base-editor should perform, you have to configure conditions. You can set up conditions and actions as follows:

JavaScript
conditions: [{
    // It will trigger only when the Paper Type is changed (ignores Cut Corners). 
    // If you want to trigger it for both options, list both option names here. 
    watch: ['Paper Type'],
    // Use an optional condition to filter out options values not listed below.
    condition: "'Paper Type'='Linen' OR 'Paper Type'='Kraft'", 
    // Run this action based on the watch and condition.
    action: 'change-mockup',
    // The mockup filename can be linen.png, kraft.png, or other,
    // depending on the selected option.
    arguments: {
        "mockup": {
            "down": {
                "mockupFile": "business-card/{Paper Type}"
            }
        },
        "surface": "current"
    } 
}]

These actions represent filenames of JS files. You can find the predefined actions in the editors\base-<version>\actions folder. To implement your custom actions, refer to the readme.md file in the same folder.

Note, in the argument names you may refer to current values of options using the curly brackets. This way, if you give the same names for your mockups as the option names, you can easily configure switching mockups when the user changes the option value.

Editing Steps

The Product editor allows you to split the editing procedure into a sequence of screens, or steps. For example, in the base-editor, there are two steps - the editor and approve. You can configure them as follows:

JavaScript
"steps": {
    "editor": {
        "showPrice": false,
        "optionNames": [
            "Color"
        ],
        "buttons": {
            "finish": "Finish"
        }
    },
    "approve": {
        "buttons": {
            "continue": "Continue editing",
            "approve": "Approve design"
        },
        "preview": {
            "width": 216,
            "height": 360
        }
    }
}

In the editor step, the showPrice property hides the price box from this page; optionNames enables the Color option in the editor; buttons only enables the Finish button. In the approve step, the editor displays two buttons and proof images of 216 x 360 points.

Languages

The user interface of Product editors can be multilingual. The file containing all text strings is located in the editors\base-<version>\locales.json file. It already includes some default languages such as en, nl, de, fr, and ru. To add a new language, such as Spanish, add the es key, paste all string resources from another language into it, and then translate them.

To specify the desired language, add this line to the config:

language: 'es'

See Also

Manual

IFrame API Reference

Downloads