Word Smart Documents

BS Word Smart Documents combines the standard Smart Document Engine with Microsoft Word Documents. Templates can be configured in Microsoft Word, uploaded to Contentserv, and be used in a Smart Preset. Writing PHP code is generally not required (although custom enhancements with custom PHP templates are possible).

 

Installation & License

  • Word Smart Documents require PHP Tidy.

  • Word Smart Documents are supported on SaaS and can be installed together with BS Office

  • For local or on-premises installations please follow the general installation instructions to install the alani and alanioffice modules.

  • Activate BS Office in Settings → BS → License

     

  • Configure the license key for the phpdocx library in Settings → BS → Office. On SaaS, we are providing the required license key. If you are planning to use Smart Documents with an on-premises installation please contact us in advance. If you are using Smart Word Documents without a license (for example for testing or demo purposes) the documents will render with a watermark in them.

Gettings Started

We’re going to start off with a basic example of a template that renders to a Word document with the label, the description (a Multi-line Formatted Text attribute), and the image of a product. After that, you could go on and create a simple datasheet by enhancing the content and layout of the template.

Creating a TEMPLATE.docx in Microsoft Word

Word Smart Documents are Smart Documents generated from Microsoft Word (.docx) templates.

Let’s start with a simple template. The Label of our context items will dynamically replace the ${Label} template variable. The same goes for ${Description} which is a Multi-line Formatted Text attribute in the PIM. Context variables can reference PIM attributes both by their Label or their ID. Image attributes are used by placing them in the Alt Text of a placeholder image.

Template variables are always placed between “${“ and “}”. W can also use them in the header, footer, footnotes, endnotes, or comments of the document.

Creating a Word Smart Preset in Contentserv

We upload the TEMPLATE.docx to Contentserv and create a new Smart Preset. In the General settings, we select Word as Smart Template and Microsoft Word as File Format. In Products, we select a sample context.

Next, we select our template in the Word Settings tab.

Finally, we render our sample document. The image is fitted in the frame of the placeholder image. The Label of our sample context replaced the label. It was replaced as inline text. It kept the style of the ${Label} template variable (in this case, the Heading 1 paragraph style).

The {$Description} template variable was replaced by the HTML of the Description Multi-line Formatted Text. By default, HTML is inserted as block content. Here the bold paragraph More power, more range, another paragraph, and an unordered list with three bullet points. We’ll cover later how we can assign specific Word styles to HTML content.

Supported attribute types

  • PIM attributes referencing an image should be placed in a placeholder image. The placeholder image can be a normal image in the template. The Alt Text of the image has to reference the attribute id or its label: ${ATTRIBUTE_ID} or ${ATTRIBUTE_LABEL}. Using Media Presets for the inserted images is not supported yet.

  • Attributes that hold text-like (non-HTML) content, like Singe-line text, numbers (with units), dates, etc. can be placed in the document with the same syntax. By default, they are replaced as inline content (we could change this by setting the mode to block: ${TEMPLATE_VARIABLE +m block}. The inserted content keeps the style of the placeholder. If the content of the attribute value is empty (or the attribute doesn’t exist) the template variable will also be removed as an inline element.

  • Attributes that return HTML as their formatted value (Multi-line Formatted Text, Flex Tables, …) are also supported. The HTML is parsed and each HTML tag is mapped to a specific representation in Microsoft Word. There’s a default conversion. For example, bold text will be bold, <p> tags set to the Normal paragraph style, headers are mapped to headers and lists have a default List Paragraph. We can overwrite the defaults with a specific style mapping in the configuration of the Smart Preset and map HTML tags to Word styles from the template. HTML content is inserted as a block element. We can change this by setting the mode to inline with ${TEMPLATE_VARIABLE +m inline}.

Template variables can also be placed in the header, footer, footnotes, endnotes, or comments of the document.

Mapping HTML Tags to Word Styles

Paragraph Styles

HTML tags that typically wrap text paragraphs (e.g. <p>, <h1>) can be mapped to a paragraph style in Word. The paragraph styles defined in the template show up in the HTML Style Mapping tab of the Smart Preset configuration. There’s already a default mapping of those styles. You can configure a default mapping for all template variables or set up a specific mapping for individual template variables. By default, we offer only a few HTML tags for the mapping. Additional tags (and also classes) can be added to the mapping table if you are using a custom PHP template. A practical way for setting up the correct styles and style mapping is to render the document for a sample document, configure the styles in the generated document, perform the same style adjustments in the template document (and set up the style mapping in the Smart Preset).

Character Styles

HTML tags that typically represent inline text (e.g. <span>) can be mapped to character styles in Microsoft Word.

You can create a new character style in Microsoft Word by setting the type of the style to Character:

Linked Styles

A linked style in Microsoft Word is a style that links to a character style. It works both as a paragraph style and as a linked style. When you are mapping an HTML tag that can only be mapped to paragraph styles (e.g. <p>) you can also map it to a linked style. When you are mapping an HTML tag that can only be mapped to a character style (e.g. <span>) you can also map it to the character style that a linked style is linking to.

HTML Lists

Assigning list styles to <li> tags

A list in Word typically consists of a paragraph style (that defines font, font-size, font-color, line-height, …) and bullets, a numbering, or a multilevel list style that defines how the bullets look like. To assign a different style to our HTML lists, we can map the <li> tag to a paragraph style. The bullets (and all other properties of a list style, like indentation of the items) used by the paragraph will also be applied to our list items.

To show an example we will use two different attributes with HTML lists.

In the template, we prepare two paragraph styles: ‘List Paragraph' and 'customList’. We assign different bullet styles to them.

In the HTML Style Mapping tab of the presets the styles show up. We use 'ListParagraph' as the default style in the General section. For USPs, we set a different style for our lists.

When we render the document different bullets are used for the two lists. Note that we have changed the font to italic in the paragraph style for the second list.

Styling ordered lists works in the same fashion.

Nested lists

The method of mapping styles to <li> tags does not work well for styling nested HTML lists, because the same level would be assigned for the inner and for the outer lists. If you are dealing with nested lists it is generally better not to use a custom style mapping for <li> tags.
If you have the possibility to add classes to the <ul> tags (in that case you are probably using function template variables or other content created by a developer) you can also map nested lists to (custom) list styles. We’ll explain how to do that in the section on custom implementations.

HTML Tables

Suppose we have the following Flex Table in Contentserv and want to add it to our document.

We first add the label (or ID) of the attribute to a template placeholder in the template.

Then we render the document with our sample context to see how the output looks like. Please note that the output depends on the table. Some HTML properties of the table are parsed automatically and considered for the layout of the Word document (like the width for individual columns). If you want to go deep into details about these properties you can read more in the documentation of the phpdocx library we are using to render the word documents (for example here: https://www.phpdocx.com/documentation/snippets/fixed-table-widths-HTML). In our example, the table has no particular styles applied to it.

Next, we create a custom table style (named BikesTable). We want our table to look similar to the original Flex Table layout in the PIM: White and bold font on dark background for the header row, bold font for the Total row (that’s how the last row is called in Microsoft Word tables), and alternating background colors for the rows.
We also want to use a smaller font size. All that can be defined in Microsoft Word table styles, but with regards to the font size we have to consider the following:

For the font size of a table style to be applied correctly, you have to set the font size of the ‘Normal’ paragraph style to 10. Otherwise, Microsoft Word does not handle the priority of the font size as expected. This is the way Word works and has nothing to do with Word Smart Documents.

When we are satisfied with the way the table looks we have to add the same table style to our template file.

We can then add the table style to the HTML style mapping.

The document finally looks like this:

Adding a style to the Microsoft Word template

When you comparing the options in the style mapping settings of the Smart Preset and the styles in the Styles Pane in Microsoft Word, you will see that not all styles available in the Microsoft Word application are included in the document.

The best approach to add a style to the document is adding content with that style to the document (and then saving it). You can also use the “Add to template” or “Add to the styles gallery” option when creating new styles, or overwrite the default base template to add specific styles as default.

Parameters for Template Variables

There are several parameters for overwriting the default behavior of template variables. They are added with {TEMPLATE_VAR +p SETTING} where p stands for the parameter we want to overwrite. You can use multiple parameters for a template variable (for example ${TEMPLATE_VAR +m inline +t html +l DE}). The order of the parameters does not matter.

Overwriting the context language

With +l LANGUAGE_SHORT_NAME (lowercase L) we can overwrite the context language defined in the Smart Preset settings. For example, we could use this to add a second language to the template.

 

Overwriting the mode (inline or block)

Content can be inserted as inline or as a block element. By default, texts are inserted as inline elements and HTML is inserted as a block. You can overwrite this and for example, insert some HTML paragraph as an inline element. Another use-case could be that you want to use a block-element in Microsoft Word (like a heading) as an inline element. The syntax for this is {TEMPLATE_VAR +m inline} or {TEMPLATE_VAR +m block}.

Setting the type (html or text)

As we’ve already discussed, both HTML and text-like content is supported for placeholder variables. In many cases, the correct type is determined automatically. If that doesn’t work you can explicitly overwrite the type with the ${TEMPLATE_VAR +t html} or ${TEMPLATE_VAR +t text} syntax. If you encounter a case where an attribute usually returns HTML content and the type is not recognized correctly automatically, you can also ask us to fix this.

Overview of Template Variable Parameters

Parameter

Description

Parameter

Description

+m MODE

Sets the insertion mode to either inline or block. When the value for the template variable is empty, the mode is also important, because then it will either be removed as inline or as block element.
Example: ${ATTRIBUTE_ID +m inline}

+l LANGUAGE

Overwrites the context language for that template variable.
Example: ${ATTRIBUTE_LABEL +l EN}

+t TYPE

Sets the content type to either text or html
Example: ${@PRESET_PLACEHOLDER +t html}

Preset Template Variables

Preset template variables can be defined with the ${@PRESET_TEMPLATE_VARIABLE} syntax.
They show up in the Preset Template Variables tab of the Smart Preset configuration as an editor field. You can then set the content in that editor field. If you add the + html parameter to the template variable, you will get a rich text editor instead of a simple text field. You can also define a style mapping for the generated content.

Let’s illustrate this with an example by adding a preset template variable for the footer:

Settings Overview

General (Preset configuration)

Setting

Description

Setting

Description

Name

Standard Smart Document setting (applies to all Smart Document Presets and is not specific to Word Smart Documents)

Label

Standard setting

Description

Standard setting

Smart Template

The (PHP) template used for the preset. Use Word if you are not using a custom PHP template, otherwise use your custom template.

Products

Standard setting, a sample context for the Smart Preset. Use this when you are defining your templates.

Allow Access by

Standard setting

Save documents

Standard setting

Disabled

Standard setting

Split documents

Standard setting

Language

The context language. Current language is the default here. You can also set a specific language or the default language of the environment.

File format

The file format of the generated documents. Currently we only generate Microsoft Word (.docx) files.

Download documents

Standard setting

Word Settings (Preset configuration)

Setting

Description

Setting

Description

Word Template

The Microsoft Word (.docx) template from which the documents are created.

Convert to PDF

The document can be converted to PDF via https://convertapi.com
Other methods of conversion may be added in the future and then this setting may change.

Context Selection

If you are rendering the Smart Document for a folder this setting defines if only the folder or the end-nodes / children of the folder are added to the document.

Page break between products

If the Context Selection setting allows for multiple products being inserted in one document, this settings defines if a new page is started for each product.

Continue page numbering

If the Context Selection setting allows for multiple products being inserted in one document, this setting defines if the page numbering in the document (if you are using one) is restarted after each product.

Converting Documents to PDF

We support converting the Microsoft Word output to PDF via https://convertapi.com

You can read more on this here: https://contentserv.atlassian.net/wiki/spaces/DOCU/pages/1277231252

Custom PHP Smart Templates & Function Template Variables

How to create a custom PHP template

To create a custom PHP template we first create a new file:

plugins/smart/CustomWordSmartTemplate/CustomWordSmartTemplate.php

CustomWord is the name of the template that shows up in the UI, SmartTemplate is the naming convention for Smart Templates. The plugins folder can be placed in the project folder or inside a module.

We add the following code to CustomWordSmartTemplate.php

1 2 3 4 5 6 7 <?php CS::includeFile(CSAlaniOffice::getModuleBaseDirectory() . 'api/BSWordSmartTemplate.php'); class CustomWordSmartTemplate extends BSWordSmartTemplate { }

The template is now available for the Smart Presets. It does not implement any extra functionality.

Adding HTML tags and classes to the style mapping

1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php CS::includeFile(CSAlaniOffice::getModuleBaseDirectory() . 'api/BSWordSmartTemplate.php'); class CustomWordSmartTemplate extends BSWordSmartTemplate { // Adds HTML tags or classes to the style mapping protected function addStyleMapping() { return array( 'Default' => array('article', '.MyClass') ); } }

The previous snippet adds the <article> tag and the MyClass class to the Default style mapping.

If a class name contains the word ‘table’ (like MyTable), the mapping table will provide the table styles from the template (instead of the paragraph styles).

Function Template Variables

Another thing we can do in a custom PHP template is to implement functions that return custom text or HTML content and use them in Word templates.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?php CS::includeFile(CSAlaniOffice::getModuleBaseDirectory() . 'api/BSWordSmartTemplate.php'); class CustomWordSmartTemplate extends BSWordSmartTemplate { protected function addStyleMapping() { return array( // Adding two selectors to the %MyFunction function template variable '%MyFunction' => array('article', '.MyClass') ); } /** * Sample implementation of a function template variable * * @param CSSmartPreset $oPreset The Smart Document Preset * @param CSItemApiItem $oItem The context item * @param int $iLanguageID Context language ID * * @return string */ protected function executeMyFunction($oPreset, $oItem, $iLanguageID) { return '' . '<article>' . '<p>Our item is named ' . $oItem->getLabel() . '</p>' . '<p class="MyClass">Second paragraph with a class</p>' . '<p>Third paragraph</p>' . '</article>'; } }

To add a function template variable in the PHP template we define the function as execute followed by the name of the function template variable (without the percent sign).

The function has three parameters: the Smart Preset object (from which we can read configuration values with getValue()), the context item, and the context language. They can be used to read and process data from the PIM product. The function has to return a string or an HTML string.

We can now use the function template variable in the Word Template. The syntax for this is ${%FUNCTION_TEMPLATE_VARIABLE}. We have to add a percent sign before the name of the function.

The output looks like this:

Finally can use the style mapping to assign different styles to the <tag> and to the paragraph with the MyClass class.

Note that we have multiple <p> tags within an article. By using a class (<p class=”MyClass”) for one of the paragraphs we can assign a different style to it.

Function Template Variables and nested HTML Lists

When mapping list styles, the paragraph style for the list in Word has to be assigned to the <li> tags in the style mapping. You can also use classes with <li> tags and map paragraph styles to the classes (if you add the classes to the style mapping with the addStyleMapping() method)).

Assigning a paragraph style to <ul> tags does not work.

The list style (bullet points) that is used with the paragraph style in the Word template is automatically assigned to the list items then.

However, this does not work if you are working with nested lists, because all list items would get the style of the first level. Let’s set up an example that illustrates the problem first and then look at a solution.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 protected function executeMyFunction($oPreset, $oItem, $iLanguageID) { return '' .'<ul class="customList">' // -> this is critical for assigning the list style .'<li>' . 'Item 1' .'<ul>' .'<li>Item 1a</li>' .'<li>Item 1b</li>' .'</ul>' .'</li>' .'<li>' . 'Item 2' .'<ul>' .'<li>Item 2a</li>' .'<li>Item 2b</li>' .'<li>Item 2c</li>' .'</ul>' .'</li>' .'</ul>'; }

Without any style mapping applied to %MyFunction the output looks like this:

If we map the <li> tags to the customList paragraph style, the levels of the list style are not applied as expected:

What we will do now in order to fix this is

  • Adding the name of the paragraph style to the outer <ul> tag (capitalization does matter here). We’ve already done this in the previous code snippet.

  • Adding the class to the class-mapping with addStyleMapping(). You can do this both for the function template variable or for the ‘Default’ style mapping.

  • Assigning the class to the paragraph style with the same name in the Preset Configuration. Note that we are assigning the name of the paragraph style to the class of the <ul> tag, not the name of the list style that is used with the paragraph style.

  • The name of the paragraph style must contain the string ‘list’ within its name (like in customList). Capitalization does not matter here. The occurrence of the substring list triggers some important functionality (making the list style available and making sure that there are no issues with the priority the list style is applied in Microsoft Word).

  • The same concept applies to character styles. If you are mapping an HTML tag that can only be mapped to character styles (e.g. <span>) you have to map it to a character style. For tags and classes that are added with addStyleMapping(), both style types (paragraph and character) are offered in the dropdown menu. You have to select a style with a compatible style type, otherwise, the style cannot be applied.

That way the numbering style can be assigned with the correct priority in the word document and we get the paragraph style and the list we are expecting for our list.

Function Template Variables and HTML Tables

If you are using classes to assign table styles, the class name must contain the substring ‘table’.

We can also map styles for elements nested inside a table. For example, we can put the nested list we used in the previous example inside a table. We can then assign a table style to the table and a paragraph style to the list inside the table. Here is how we would do that:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 <?php CS::includeFile(CSAlaniOffice::getModuleBaseDirectory() . 'api/BSWordSmartTemplate.php'); class CustomWordSmartTemplate extends BSWordSmartTemplate { protected function addStyleMapping() { return array( '%MyFunction' => array('.customList', '.customTable') ); } /** * A nested list inside a table * * @param CSSmartPreset $oPreset The Smart Document Preset * @param CSItemApiItem $oItem The context item * @param int $iLanguageID Context language ID * * @return string */ protected function executeMyFunction($oPreset, $oItem, $iLanguageID) { $sHtmlList = '' . '<ul class="customList">' . '<li>' . 'Item 1' . '<ul>' . '<li>Item 1a</li>' . '<li>Item 1b</li>' . '</ul>' . '</li>' . '<li>' . 'Item 2' . '<ul>' . '<li>Item 2a</li>' . '<li>Item 2b</li>' . '<li>Item 2c</li>' . '</ul>' . '</li>' . '</ul>'; return '' . '<table class="customTable" width="60%">' . '<tr>' . '<th width="30%">Column 1</th>' . '<th width="70%">Column 2</th>' . '</tr>' . '<tr>' . '<td>' . $sHtmlList . '</td>' . '<td>' . $oItem->getFormattedValue('Teaser') . '</td>' . '</tr>' . '</table>'; } }

The result looks like this:

Hot to prevent tables from breaking across multiple pages

If you want to prevent tables from breaking across multiple pages you can do so with the ‘Keep lines together’ and ‘Keep with next’ options in the ‘Line and Page Breaks’ option of the table’s paragraph settings in the Word Template.