Three-step workflow
- Last updated on April 27, 2024
- •
- 6 minutes to read
Let's consider the example that your product is business cards, and you want customers to personalize it. Customers can select horizontal, vertical, or square format, and two types of style.
For this, you may create a three-step workflow. First, customers select a product variant, edit a design in Design Editor, and then approve the result.
Let's see how this workflow looks.

In this tutorial, you will learn how to create a three-step PIM workflow.
Planning
Let's start from planning your workflow. For this, you need to decide the quantity of steps and what widgets you need.
Steps
This workflow contains three steps:
The
Variant Selectorstep. Here, a customer selects a product variant.The
Editorstep. In this step, a customer edits a design in the Design Editor.The
Approvalstep. A customer approves the personalization result.
"steps": [
{
"name": "Variant Selector"
},
{
"name": "Editor"
},
{
"name": "Approval"
}
]
Widgets
Let's consider what widgets you need for this workflow:
design-editorfor customizing a design.variant-selectorfor selecting a product variant.orderfor creating an order.finish-groupfor defining buttons and checkboxes at theApprovalstep.stepsfor hiding theFinishbutton in the Navigation panel.sliderfor representing a personalization result.
"widgets": [
{
"name": "editor",
"type": "design-editor",
"params": {...}
},
{
"name": "variant-selector",
"type": "variant-selector",
"params": {...}
},
{
"name": "order",
"type": "order",
"params": {...}
},
{
"name": "finish",
"type": "finish-group",
"params": {...}
},
{
"name": "steps",
"type": "steps",
"params": {...}
},
{
"name": "preview",
"type": "slider",
"params": {...}
}
]
Vars
Let's define variables for your workflow. The following syntax allows you to get a product ID, a product version ID, and a product filter ID from BackOffice.
"vars": {
"pimProductId": "{| Product.id |}",
"pimProductVersionId": "{| Product.productVersionId |}",
"pimProductFilterId": "{| Product.productFilterId |}"
}
Defining steps
Variant selector
The Variant Selector step is the first step in this workflow. At this step, customers select a product variant by filters. For this, use the variant-selector widget and embed it in the mainPanel.

The variant-selector widget shows both product variants and design variants. This widget uses the defined vars and obtains the data about a product, variants, and filters.
{
"name": "variant-selector",
"type": "variant-selector",
"params": {
"productId": "{{ vars.pimProductId }}",
"productVersionId": "{{ vars.pimProductVersionId }}",
"productFilterId": "{{ vars.pimProductFilterId }}"
}
}
Editor
The Editor step is the second step in this workflow file. At this step, customers personalize a design in the design-editor widget. It is embedded in the mainPanel.
Add the onActivate event to show the preloader while loading the design-editor and the design selected at the Variant selector step.

{
"name": "Editor",
"mainPanel": {
"name": "editor"
},
"onActivate": [
"{{ #function main.showPreloader(true) }}",
"{{ #function $['editor'].commands.initial.execute($['editor'].params.initial) }}",
"{{ #function main.showPreloader(false) }}"
]
}
Design Editor
The design-editor widget allows customers to personalize a design. Let's consider the basic settings.
The initial command gets a selected design in the productDefinitionproperty from the variant-selectorwidget. The editorConfig property configures the editor and gets fonts from your tenant. In the rendering object, you will define the output resolution, file format, and color space and enable safety lines.
{
"name": "editor",
"type": "design-editor",
"params": {
"initial": {
"autoCompile": false,
"showPreloader": true,
"productDefinition": "{{ $['variant-selector'].selectedVariant.designId}}",
"editorConfig": {
"initialMode": "Advanced",
"restoreProductOnReloadEnabled": false,
"fontList": {
"appFonts": [
"*"
]
},
"rendering": {
"hiResOutputDpi": 300,
"hiResOutputFileFormat": "pdf",
"hiResOutputColorSpace": "cmyk",
"proofImageSafetyLinesEnabled": false
}
}
}
}
}
Approval
At the Approval step, customers approve the personalization result, and then create an order. For this, define the slider and finish-group widgets. Then, embed slider in the mainPanel and finish group in the bottomPanel.

{
"name": "3. Approval",
"mainPanel": {
"name": "preview"
},
"bottomPanel": {
"name": "finish"
}
}
Slider
The Slider widget displays the personalization result. For this, slider gets proof images from the design-editor widget, and then creates columns to show design pages. You can also define style settings for this widget, for example, the background color and paddings.
{
"name": "preview",
"type": "slider",
"params": {
"style": {
"--au-widget-background": "#eee",
"--au-widget-padding": "8px"
},
"direction": "tile",
"rows": 1,
"columns": "{{Math.min(2,$['editor'].proofImageUrls.length)}}",
"containerColor": "#eee",
"images": {
"{{#each $['editor'].proofImageUrls.map(s=>s[0]) as imageUrl }}": {
"url": "{{imageUrl}}"
}
}
}
}
Finish group
This finish-group widget represents the confirmation checkbox and the Add to cart button. When the user clicks this button, the widget saves the personalization result and renders hi-res images.
{
"name": "finish",
"type": "finish-group",
"params": {
"checkboxPrompt": "I have reviewed and approve my design.",
"value": false,
"checkboxEnabled": true,
"checkboxVisible": true,
"buttonText": "Add to cart",
"buttonClassStyle": "primary",
"onClick": [
"{{#function main.showPreloader(true, 'Creating print files...')}}",
"{{#function $['editor'].getHiResImages()}}",
"{{#function new Promise(res=> setTimeout(res,1000)) }}",
"{{#function main.showPreloader(false)}}"
]
}
}
Steps widget
The steps widget allows you to hide the Finish button in the Navigation panel, which appears by default.
{
"name": "steps",
"type": "steps",
"params": {
"finishButton": {
"visible": "false"
}
}
}
Connecting steps
When you go from the Editor step to the Approval step, the workflow will render proof images and clear the confirmation checkbox. It is used for the situations when you decide to go back to the Editor step to correct the result.
"onActivate": [
"{{#function $['editor'].getProofImages(800,800)}}",
"{{#function $['finish'].value = false}}"
]
Creating order
The order widget creates an order in the e-commerce system, creates a project in Customer's Canvas, and finishes the personalization process. This widget passes high resolution images, SKU, and other related information.
{
"name": "order",
"type": "order",
"params": {
"data": {},
"sku": "{{ $['variant-selector'].selectedVariant?.storefrontProductVariantId || '' }}",
"props": {
"_stateId": [
"{{ $['editor'].stateId }}"
],
"_userId": "{{ $['editor'].userId }}",
"_hidden": {
"snapshot": "{{ main.editorState }}",
"images": "{{ $['editor'].proofImageUrls.map(u=>u[0]) }}",
"downloadUrls": "{{ $['editor'].hiResUrls }}",
"sku": "{{ $['variant-selector'].selectedVariant?.storefrontProductVariantId || '' }}",
"originalProductId": "{{ product.id.toString() }}",
"productVersionId": "{{ vars.pimProductVersionId }}"
}
}
}
}
Result
Let's consider how this three steps workflow looks.
{
"showSaveProjectButton": true,
"showOpenSavedProjectsButton": true,
"vars": {
"pimProductId": "{| Product.id |}",
"pimProductVersionId": "{| Product.productVersionId |}",
"pimProductFilterId": "{| Product.productFilterId |}"
},
"showSteps": true,
"widgets": [
{
"name": "editor",
"type": "design-editor",
"params": {
"initial": {
"autoCompile": false,
"showPreloader": true,
"productDefinition": "{{ $['variant-selector'].selectedVariant.designId}}",
"editorConfig": {
"initialMode": "Advanced",
"restoreProductOnReloadEnabled": false,
"fontList": {
"appFonts": [
"*"
]
},
"rendering": {
"hiResOutputDpi": 300,
"hiResOutputFileFormat": "pdf",
"hiResOutputColorSpace": "cmyk",
"proofImageSafetyLinesEnabled": false
}
}
}
}
},
{
"name": "steps",
"type": "steps",
"params": {
"finishButton": {
"visible": "false"
}
}
},
{
"name": "variant-selector",
"type": "variant-selector",
"params": {
"productId": "{{ vars.pimProductId }}",
"productVersionId": "{{ vars.pimProductVersionId }}",
"productFilterId": "{{ vars.pimProductFilterId }}"
}
},
{
"name": "order",
"type": "order",
"params": {
"data": {},
"sku": "{{ $['variant-selector'].selectedVariant?.storefrontProductVariantId || '' }}",
"props": {
"_stateId": [
"{{ $['editor'].stateId }}"
],
"_userId": "{{ $['editor'].userId }}",
"_hidden": {
"snapshot": "{{ main.editorState }}",
"images": "{{ $['editor'].proofImageUrls.map(u=>u[0]) }}",
"downloadUrls": "{{ $['editor'].hiResUrls }}",
"sku": "{{ $['variant-selector'].selectedVariant?.storefrontProductVariantId || '' }}",
"originalProductId": "{{ product.id.toString() }}",
"productVersionId": "{{ vars.pimProductVersionId }}"
}
}
}
},
{
"name": "finish",
"type": "finish-group",
"params": {
"checkboxPrompt": "I have reviewed and approve my design.",
"value": false,
"checkboxEnabled": true,
"checkboxVisible": true,
"buttonText": "Add to cart",
"buttonClassStyle": "primary",
"onClick": [
"{{#function main.showPreloader(true, 'Creating print files...')}}",
"{{#function $['editor'].getHiResImages()}}",
"{{#function new Promise(res=> setTimeout(res,1000)) }}",
"{{#function main.showPreloader(false)}}"
]
}
},
{
"name": "preview",
"type": "slider",
"params": {
"style": {
"--au-widget-background": "#eee",
"--au-widget-padding": "8px"
},
"direction": "tile",
"rows": 1,
"columns": "{{Math.min(2,$['editor'].proofImageUrls.length)}}",
"containerColor": "#eee",
"images": {
"{{#each $['editor'].proofImageUrls.map(s=>s[0]) as imageUrl }}": {
"url": "{{imageUrl}}"
}
}
}
}
],
"steps": [
{
"name": "1. Variant Selector",
"mainPanel": {
"name": "variant-selector"
}
},
{
"name": "2. Editor",
"mainPanel": {
"name": "editor"
},
"onActivate": [
"{{ #function main.showPreloader(true) }}",
"{{ #function $['editor'].commands.initial.execute($['editor'].params.initial) }}",
"{{ #function main.showPreloader(false) }}"
]
},
{
"name": "3. Approval",
"mainPanel": {
"name": "preview"
},
"bottomPanel": {
"name": "finish"
},
"onActivate": [
"{{#function $['editor'].getProofImages(800,800)}}",
"{{#function $['finish'].value = false}}"
]
}
]
}