Group-Office has a flexible template system supporting variables with filters and structural blocks. They are used for newsletters, reports, invoice templates etc.



By default some variables are already present:

  • {{now|date:Y-m-d}} The current date time object. In this example a date filter is used.

  • {{system.title}} The title configured at System Settings -> General

  • {{system.url}} The URL to Group-Office configured at System Settings -> General

A variable is written like this:


Custom fields

A custom field can be accessed like this:


Some custom fields are stored with an ID. Like a select field for example. You can get the text like this:



Arrays can be written like this:


You can also iterate arrays using an [each] block:

[each address in contact.addresses]
  [if {{address.type}} == "billing"]

And filter arrays by property and only write first match using “eachIndex”:

[each emailAddress in contact.emailAddresses | filter:type:"billing"]
    [if {{eachIndex}} == 1]


But this is probably the best way to handle the case where you prefer a type of address but just use the first if that’s not found. It uses [assign] to create a new variable. If it’s empty it will use the first address:

[assign address = contact.addresses | filter:type:"postal" | first]
[if !{{address}}]
[assign address = contact.addresses | first]

Finding a contact with id = 1 using the “entity” filter with parameter “Contact” (Available entities in your instance can be found in the core_entity database table):

[assign contact = 1 | entity:Contact]

Find the first linked contact:

[assign firstContactLink = someEntityVar | links:Contact | first]

Using [assign] to do some basic math

Note that inside the [each] block we access total with parent.total:

[assign total = 0]

[each invoice in invoices]
   <td align="right">{{business.finance.currency}} {{invoice.totalPrice|number}}</td>
   <td align="right">{{business.finance.currency}} {{invoice.paidAmount|number}}</td>
   [assign balance = {{invoice.totalPrice}} - {{invoice.paidAmount}} ]
   [assign parent.total = {{parent.total}} + {{balance}}]
   <td align="right">{{business.finance.currency}} {{balance|number}}</td>

{{business.finance.currency}} {{total|number}}

More examples

An advanced example for printing a custom salutation (Just an example. You can use {{contact.salutation}}):

Dear [if {{contact.prefixes}}]{{contact.prefixes}}[else][if !{{contact.gender}}]Ms./Mr.[else][if {{contact.gender}}=="M"]Mr.[else]Ms.[/if][/if][/if] {{contact.lastName}}

A simple example template:

Hi {{contact.salutation}},

Best regards,


Attachment field with photo’s in e-mail template:

[each photo in contact.customFields.Photos]
<img src="{{photo.blobId|blobUrl}}" alt="{{photo.name|htmlEncode}}" style="max-width:100%"><hr>

Or photo’s from the entity’s files folder:

[each photo in document|entityFiles]
<img src="{{photo.blobId|blobUrl}}" alt="{{photo.name|htmlEncode}}" style="max-width:100%"><hr>


You can use filters to format data. They can be used with a “|” char followed by the filter name. Optionally the filter can take arguments separated by a “:”.

  • date(format as in PHP):

  • number(decimals,decimal separator,thousands separator:

  • multiply(multiplier): Multiply a number:

  • add(number): Add to a number:

  • entity(type, id): Fetch an entity by ID:

    [assign contact = 1 | entity:Contact]
  • links(entityName, properties (comma separated): gets the linked entities:

    [assign firstContactLink = someEntityVar | links:Contact | first]
  • prop(property) get a property from an object or array by name:

    [assign formattedAddress = contact.addresses | sort:type:"postal" | first | prop:formatted]
  • nl2br: Change line breaks to HTML <br> tags

  • empty: returns true if empty or false if not

  • dump: For debugging only. Dumps the variable type and value.

  • filter(property, value): Filters the array by property values:

    {{contact.addresses | filter:type:"postal" | first}}
  • sort(property, value?) or rsort:

    [assign formattedAddress = contact.addresses | sort:type:"postal" | first | prop:formatted]
  • count

  • first: Grab the first item of the array

  • prop(property): change the array to a sub property of all items.

  • implode(glue = ‘, ‘): Implode an array of strings:

    {{contact.emailAddresses | prop:email | implode}}