Loop through a list of items

If you have an advanced integration setup that is sending data in an array or JSON object, you can setup loops in your document to print that information. Examples include line items on an invoice or a list of items for a report.

From a technical standpoint, your data will look like this for HTTP POST (name/value pairs)



{"items": [{"Name":"Shirt", "Quantity":"2", "Price":"19.95", "Total":"39.90"},{"Name":"Jeans", "Quantity":"3", "Price":"89.99", "Total":"269.97"}]}

Create a Simple List

If you have a list of items that you would just like to print in your document, you can use the following {foreach} code

{foreach from=$items item=_row}
{$_row.Quantity} x {$_row.Name} = ${$_row.Price|number_format:2}

Create a Table

If you're generating an invoice, you're probably looking to create a table that loops through each of the line items and prints them on a new row in the table.  No problem!  We've added a new "tablerow" tag that you can use and it tells our system to treat the table row as a loop.  The tag works exactly like a "foreach" loop, so all you need to do is use "tablerow" instead of "foreach" and we'll handle the rest.

Here's an example:

Name Quantity Price Total
{tablerow from=$products item=_product}{$_product.Name} {$_product.Quantity} {$_product.Price} {$_product.Total}{/tablerow}

The data that you send through to a table row loop needs to be an array (ie and array of products) that can be easily looped through.  The part after the dot in the variable name is the individual property for that element in the array.

If you'd like to skip items in the list, you can use an if statement in your table like this:

Name Quantity Price Total
{tablerow from=$products item=_product}{tableif $_product.Type == 'shirt'}{$_product.Name} {$_product.Quantity} {$_product.Price} {$_product.Total}{/tableif}{/tablerow}


Create a Bulleted/Numbered List

You can also use special "listrow" code to loop through items in a list to create a bulleted list.  Like this:

  • {listrow from=$products item=_product}{$_product}{/listrow}


Sort Your List

If you would like to sort your items based on a certain "key" you can do so using the "sort" modifier in this format "|sort:[KEY]:[asc or desc]" (asc is default). For example:

{foreach from=$items|sort:"Name" item=_row}
{$_row.Quantity} x {$_row.Name} = ${$_row.Price|number_format:2}

To sort by price in descending order:

{foreach from=$items|sort:"Price":"desc" item=_row}
{$_row.Quantity} x {$_row.Name} = ${$_row.Price|number_format:2}


Sort By Multiple Fields

If you would like to sort your items based on multiple keys, you can do so using the "multisort" modifier in this format "|multisort:[KEY1]:[asc or desc]:[KEY2]:[asc or desc]" (asc is default). For example: 

{foreach from=$items|multisort:"Name":"asc":"Price":"desc" item=_row}
{$_row.Quantity} x {$_row.Name} = ${$_row.Price|number_format:2}
Was this article helpful?
10 out of 11 found this helpful


  • Hi Phillip,

    We now support the {tablerow} code in Excel templates!

  • Hi Mark,

    The loops don't work in a fillable PDF (since the contact is static). But you can use the Field Map (https://support.webmerge.me/hc/en-us/articles/206526086-Field-Map) to set the value of each field using the static merge field for the value in the loop like this:

    {$products.0.price} or {$products.1.name}

  • Hi Belinda,

    Yes, you can now use {tablerow} inside of Excel :)

  • Hi Aaron,

    Sorry, my instructions were for entering the JSON in the box under the "products" label. If you're entering the JSON into the JSON box (using JSON for all fields in your merge) then you need to do this:

    {"products":[{"Name":"Shirt", "Quantity":"2", "Price":"19.95", "Total":"39.90"},{"Name":"Jeans", "Quantity":"3", "Price":"89.99", "Total":"269.97"}]}

  • Hi Jeremy,

    I got it!

    Thank you very much for your help!!

  • Hi Jeremy,

    Do you see the example towards the top of this help article? It shows you exactly how it works inside of a table (it's all in 1 row). There's an actual table in the help article :)

    If that did not work for you, then that probably means we're not receiving an array (list) of items that we can loop through in the table. The "from" part of that tablerow code tells the system what merge field to pull the list from. The "item" part is the local merge field to use inside of the tablerow loop so you can print out the individual fields from that item in the list.

    Please check on those things for me and if you're still having trouble, please create a support ticket and we can help you!


  • Hi David,

    Yes, you can do that. Setup your table in your doc (using the examples above) then you can turn on Debug Mode (https://support.webmerge.me/hc/en-us/articles/206526126-Debug-Mode) so you can see the data coming over from Salesforce and see what subfields to use inside the table. When you match up the loop field in Salesforce, you'll match it up to the Child Relationship for your attendees. Here's an example using line items for an invoice (process is the same): https://www.webmerge.me/blog/generate-an-invoice-from-an-opportunity-won-in-salesforce

    If you have any more questions, please create a support ticket and we'll help you from there!


  • Hi Carlos,

    Unfortunately, we don't have a way to dynamically add sheets. We'll add this to our feature request list and let you know when it hits the roadmap!

    Thanks :)

  • Hi Jeremy,

    it's possible to use stristr, or !stristr with tableif ?

    another question :
    I have a test on the firstnames, without accent is ok, with accent, the test does not work anymore, how to do?

    {tablerow from=$ACTIVITES item=_row}{tableif $_row.Owner.Name != "Jerome"} -->OK

    {tablerow from=$ACTIVITES item=_row}{tableif $_row.Owner.Name != "Jérôme"} -->KO

    I have a test on the subject email, without quote is ok, with quote, the test does not work anymore, how to do?

    subject = "Information" -->detected OK

    subject = "Votre demande d'information" -->detected KO



  • Dan, im not sure i understand the steps; would you mind emailing me privately in more detail? wgreenberg1@me.com. thank you.

  • Hi Jeremy,

    I have my data coming from a JotForm InfiniteList via Zapier. It looks like this in Zapier:

    prevEmploy: [{"Employer":"Employer 1","Title":"Title 1","Location":"Location 1"},{"Employer":"Employer 2","Title":"Title 2","Location":"Location 2"}]

    The loop {listrow from=$prevEmploy item=row} {$row.Employer} {$row.Title} {$row.Location} {/listrow} should print out the Employer, Title and Location but just prints "[ ["

    I'm unsure why this is not working, any help will be greatly appreciated.

  • ah! this works perfectly. Thank you so much for the help.

  • Hi Sergio,

    Yes, it's possible, but you need to program your Flow to send over a JSON object with the rows of data (as an array in the JSON). Unfortunately, we don't have any good documentation on how to do that in Microsoft Flow, but their support team can hopefully point you in the right direction!


  • Hi Sergio,

    You'll want to put the JSON in the "products" field in Flow and you'll only want to put the specific piece for the products. IE [{product 1 fields},{product 2 fields}]

    One other thing you'll probably have to do is use the Field Map (https://support.webmerge.me/hc/en-us/articles/206526086-Field-Map) to convert the JSON into an array like this:

    {if !is_array($products)}{$products}{/if}

    Our system will detect the JSON in {$products} and convert it to an array.

  • Do you support nested loops?

  • Hi Jeremy,
    I'm trying to use the {tableif} tag within a {tablerow} and followed your example above but it isn't pulling in any data that meets the criteria. If I remove that tag, the table fills out with all the data as expected.
    I have a 6 column table. My first column in my table starts shows this:
    {tablerow from=$PartnerRoles item= _Partner_Role__c}{tableif $_Partner_role__c.Partner_Role__c == “Employee”}{$_Partner_Role__c.Contact__c.Name}

    The last column closes the table row tag with {/tablerow} (there is no closing of the {tableif} tag shown in example so assume that isn't needed. Partner_Role__c is the name of the Custom object and there is also a field in that object Partner_Role__c that is the picklist field, thus why Partner_Role__c is repeated in the TableIF tag. Thanks for any insight!

  • What is the key to send the JSON data

  • Hi Jeremy, I read that you support the {tablerow} code in Excel templates. Is it possible to loop through an array and create one excel sheet per element?

  • Hello,

    Please see this help article for Salesforce Child Relationships: https://support.webmerge.me/hc/en-us/articles/206527196-Working-with-Child-Relationships

  • Hi Jeremey!

    Is there a chance to see an example of a syntax for {tablerow} with 'if' condition and 'sort'?

  • Hi Rafaela, Sorry, I mispoke - you need to use the {tableif} tag like in the example table in the article above.
  • Hi Radek,

    Yes, you can do nested loops:

    {foreach from=$products item=product}
    {foreach from=$product.sizes item=size}

  • In Podio I have an array (a single field) that is a preset list of choices. You can select multiple choices. Each choice has a set value that comes over in the array (i.e. {$fitness_competition_within_5_minute_drive.0} would be the first one; .1 is the second and so on). I want the merge to list all of the selected ones in my document. Is there a way to do this without just inserting a merge field for each one so that if I add other selections in the future I dont have to update the merge document? Code I tried is below:
    {foreach from=$fitness_competition_within_5_minute_drive item=$fitness_competition_within_5_minute_drive}

  • Hi! is it possible to get data for looping items from Excel or Sharepoint? I've created a Microsoft flow, when a JotForm is completed, searchs for a item in a Sharepoint and I want to create a PDF with a table... is it possible?

  • I have tried to follow the table rows approach - what I did was create a table with the required 3 columns and then entered the following into the columns:


    {tablerow from=$projectHoursItems item=projectHoursItem}{$projectHoursItem.dateused}

    Column 2


    Column 3

    $projectHoursItem.hours {/tablerow}

    This is what the example above looks like you need to do but it gives the following error:

    There is an error in your document: Syntax Error in template "string:" on line 6 "
    " - Unexpected "/"

    Where am I going wrong??


  • These examples seem to be only for JSON or HTML query string inputs.
    For Salesforce integration, how can I loop through a list of custom objects related to a Opportunity object with a lookup relationship?

  • Can you please write for me the example in this article but using if?
  • Hi John,

    Yes, but you'll need to send over all the data in the same JSON request (you'll have multiple arrays inside your JSON)

  • Hi Jeremy,

    I can't seem to get the sorting feature working for me in a word document. My code is: {tablerow from=$Lineitems|sort:”POS.” item=_lineitem}{$_lineitem.position__c} and my first column is called "POS.". When I merge the docx and have it also output as docx I can open it and then have the list sort by the POS. column with no problem.

    Any idea how I can get your server to do this for me? Anything wrong with my code?

    Thank you for your help,

  • Hi Robby,

    Correct, the {tableif} is used if your want to include/exclude an entire row.


Please sign in to leave a comment.