Skip to content

added loop email tokens for CustomObjectsBundle which helps to send e…#382

Open
Ravi-topchunks wants to merge 2 commits intoacquia:5.xfrom
TopChunks:email-token-loop
Open

added loop email tokens for CustomObjectsBundle which helps to send e…#382
Ravi-topchunks wants to merge 2 commits intoacquia:5.xfrom
TopChunks:email-token-loop

Conversation

@Ravi-topchunks
Copy link

@Ravi-topchunks Ravi-topchunks commented Mar 12, 2026

…mails with the list of custom items from an Object

Q A
Bug fix? (use the a.b branch) [ ]
New feature/enhancement? (use the a.x branch) [ ]
Deprecations? [ ]
BC breaks? (use the c.x branch) [ ]
Automated tests included? [ ]
Related user documentation PR URL mautic/mautic-documentation#...
Related developer documentation PR URL mautic/developer-documentation#...
Issue(s) addressed Fixes #...

Description:

DOCS

Custom object loop tokens

Custom items can be rendered in emails (or other content) using loop tokens.

Basic syntax

{custom-object-loop object=product-views | where=segment-filter | order=latest | limit=10}
  {custom-object-loop-value object=product-views | field=name | default=jhon}
{/custom-object-loop}
  • {custom-object-loop ...}: Opens the loop and defines which custom items to load.
  • {/custom-object-loop}: Closes the loop. Everything between the opening and closing tags is repeated for each matching custom item.
  • HTML inside the loop: You can place any HTML (or other tokens) between the loop tags; that block will be repeated.

Loop parameters (custom-object-loop)

  • object: Custom object name (e.g. product-views). Required.
  • where:
    • Only segment-filter is implemented so far (and it is the default if omitted).
    • It takes the first segment of a segment email, or the first campaign source segment of a campaign email.
    • All custom-object-related filters from that segment are converted into WHERE conditions.
  • order:
    • Only latest is supported (and is the default if omitted).
    • Items are ordered from newest to oldest by their creation date.
  • limit:
    • Default is 1 if not provided.
    • If greater than 1, multiple items are rendered.

Loop-value parameters (custom-object-loop-value)

  • object: Must match the object used in the surrounding custom-object-loop. If it does not match, it is ignored.
  • field: Field alias of the custom object whose value should be rendered (for example name, price, color).
  • default: Fallback value if the field is empty (for example default=Unknown).

Examples

List product names bought by the contact:

{custom-object-loop object=product-views | where=segment-filter | order=latest | limit=3}
  {custom-object-loop-value object=product-views | field=name | default=Unknown product}<br>
{/custom-object-loop}

Rendered example:

Mautic T-shirt<br>
Mautic Hoodie<br>
Mautic Cap<br>

Render a small HTML block per product:

{custom-object-loop object=product-views | where=segment-filter | order=latest | limit=2}
  <div class="product">
    <strong>{custom-object-loop-value object=product-views | field=name | default=Unknown}</strong><br>
    Price: {custom-object-loop-value object=product-views | field=price | default=0}<br>
    Color: {custom-object-loop-value object=product-views | field=color | default=Unknown}
  </div>
{/custom-object-loop}

Rendered HTML (for 2 products):

<div class="product">
  <strong>Mautic T-shirt</strong><br>
  Price: 123<br>
  Color: Blue
</div>
<div class="product">
  <strong>Mautic Hoodie</strong><br>
  Price: 153<br>
  Color: Red
</div>

Warnings and limitations

  • Multiple segments: If multiple segments are used for segment emails or campaign sources, each segment must have identical custom object filters. Only the filters of the first segment are used during token replacement when sending emails.
  • No OR conditions: Do not use OR conditions in the source segments for custom object filters.
  • No include/exclude membership filters: Do not use include/exclude segment membership filters when relying on these tokens. Token replacement only considers filters on the root segment, not on all included/excluded segments.

Steps to test this PR:

  1. Open this PR for testing locally (see docs on testing PRs here)

…mails with the list of custom items from an Object
@Ravi-topchunks
Copy link
Author

this PR contains email tokens which provides loop tokens this helps to add top products into the email with LIMIT. Please have a look at emailtokens.md

@@ -0,0 +1,86 @@
## Custom object loop tokens
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this md file into the PR description under # DOCS heading. If this gets merged we'd copy that docs part into https://github.com/acquia/mc-cs-plugin-custom-objects/wiki

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done..!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file should be removed from the PR.

Copy link
Contributor

@escopecz escopecz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'm commenting on the same things as our CI will. I let it run first.

Comment on lines +14 to +46
/**
* @var string
*/
private $token;

/**
* @var int
*/
private $limit = 1;

/**
* @var string
*/
private $where = '';

/**
* @var string
*/
private $order = 'latest';

/**
* @var string
*/
private $customObjectAlias = '';

private $loopContentTokens = [];

private $loopContent = '';

public function __construct(string $token)
{
$this->token = $token;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* @var string
*/
private $token;
/**
* @var int
*/
private $limit = 1;
/**
* @var string
*/
private $where = '';
/**
* @var string
*/
private $order = 'latest';
/**
* @var string
*/
private $customObjectAlias = '';
private $loopContentTokens = [];
private $loopContent = '';
public function __construct(string $token)
{
$this->token = $token;
}
private int $limit = 1;
private string $where = '';
private string $order = 'latest';
private string $customObjectAlias = '';
/**
* @var string[]
*/
private array $loopContentTokens = [];
private string $loopContent = '';
public function __construct(private string $token)
{
}

Not sure what types are stored in the loopContentTokens array.

*
* {custom-object=product:sku | where=segment-filter |order=latest|limit=1 | default=Nothing to see here | format=or-list}
*/
class LoopToken
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class LoopToken
final class LoopToken

return $this->loopContentTokens;
}

public function addLoopContentToken($loopContentToken, $contentTokenParams): void
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

param types are missing

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now fixed the bugs and removed .md file

@@ -0,0 +1,86 @@
## Custom object loop tokens
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file should be removed from the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants