# Email Dynamic Content in 4.x - working for anyone?

**URL:** <https://forum.mautic.org/t/email-dynamic-content-in-4-x-working-for-anyone/24283>\
**Category:** Product Support\
**Created:** [May 31, 2022, 7:03am UTC](https://forum.mautic.org/t/email-dynamic-content-in-4-x-working-for-anyone/24283 "2022-05-31T07:03:02Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![mikew](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.mautic.org/mikew/32/5156_2.png) [@mikew](https://forum.mautic.org/u/mikew)\
**Post date:** [May 31, 2022, 7:03am UTC](https://forum.mautic.org/t/email-dynamic-content-in-4-x-working-for-anyone/24283/1 "2022-05-31T07:03:03Z")

</div>

**Your software**  
My Mautic version is: 4.2.1, 4.2.2, 4.3.1  
My PHP version is: 7.4  
**Your problem**  
My problem is:  
Dynamic content does not seem to be working for me in any of these versions. Not in HTML or MJML mailers. When I send an email it just comes out Dynamic Content 2, and in 4.3.1 I do not even see the widget of Dynamic content.

So first I am interested in if anyone has it working for them.

---

<div class="post-metadata">

**Author:** ![mikew](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.mautic.org/mikew/32/5156_2.png) [@mikew](https://forum.mautic.org/u/mikew)\
**Post date:** [May 31, 2022, 11:49am UTC](https://forum.mautic.org/t/email-dynamic-content-in-4-x-working-for-anyone/24283/2 "2022-05-31T11:49:30Z")

</div>

@joeyk @silavapi tagging the two of you as I really need some assistance here and just bringing this question to your attention. 🙏

---

<div class="post-metadata">

**Author:** ![silavapi](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.mautic.org/silavapi/32/7424_2.png) [@silavapi](https://forum.mautic.org/u/silavapi)\
**Post date:** [May 31, 2022, 12:44pm UTC](https://forum.mautic.org/t/email-dynamic-content-in-4-x-working-for-anyone/24283/3 "2022-05-31T12:44:12Z")

</div>

Just tested this on Gitpod and I am seeing the same in that the dynamic content is not working, with the following error:

```auto
gitpod /workspace/mautic $ ddev exec bin/console m:c:t
Triggering events for campaign 1
Triggering events for newly added contacts
2 total events(s) to be processed in batches of 100 contacts
 2/2 [============================] 100%PHP Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57

Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57
PHP Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57

Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57

```

However I am getting the default content sent each time. I tried this with the Blank theme just to keep it simple.

---

<div class="post-metadata">

**Author:** ![silavapi](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.mautic.org/silavapi/32/7424_2.png) [@silavapi](https://forum.mautic.org/u/silavapi)\
**Post date:** [May 31, 2022, 12:52pm UTC](https://forum.mautic.org/t/email-dynamic-content-in-4-x-working-for-anyone/24283/4 "2022-05-31T12:52:03Z")

</div>

> <https://github.com/mautic/mautic/issues/11202>
>
> \### Mautic Version
> 
> 4.2.x series
> 
> \### PHP version
> 
> 7.4
> 
> \### What browsers are yo…u seeing the problem on?
> 
> Not relevant
> 
> \### What happened?
> 
> Originally reported on the \[forums\](https://forum.mautic.org/t/email-dynamic-content-in-4-x-working-for-anyone/24283/2):
> 
> \> Dynamic content does not seem to be working for me in any of these versions. Not in HTML or MJML mailers. When I send an email it just comes out Dynamic Content 2, and in 4.3.1 I do not even see the widget of Dynamic content.
> 
> Just tested this on Gitpod and I am seeing the same in that the dynamic content is not working, with the following error when the cron is fired to trigger the campaign:
> 
> \`\`\`
> gitpod /workspace/mautic $ ddev exec bin/console m:c:t
> Triggering events for campaign 1
> Triggering events for newly added contacts
> 2 total events(s) to be processed in batches of 100 contacts
> 2/2 \[============================\] 100%PHP Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57
> 
> Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57
> PHP Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57
> 
> Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57
> \`\`\`
> Guessing this might be the culprit.
> 
> \### How can we reproduce this issue?
> 
> Step 1: Create a segment to send the email to with at least one contact you can filter with (eg country=USA)
> Step 2: Create an email using the blank theme, add dynamic content block and create a filtered variation
> Step 3: Rebuild the campaign with \`bin/console m:c:r\` and then trigger the campaign with \`bin/console m:c:t\` (if on Gitpod, prepend \`ddev exec\` - eg \`ddev exec bin/console m:c:r\`).
> Step 4: Check for error in the output of the cron job, check the emails in Mailhog (port 8027 on Gitpod)
> 
> \### Relevant log output
> 
> \`\`\`shell
> gitpod /workspace/mautic $ ddev exec bin/console m:c:t
> Triggering events for campaign 1
> Triggering events for newly added contacts
> 2 total events(s) to be processed in batches of 100 contacts
> 2/2 \[============================\] 100%PHP Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57
> 
> Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57
> PHP Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57
> 
> Notice: Trying to access array offset on value of type null in /var/www/html/app/bundles/EmailBundle/EventListener/MatchFilterForLeadTrait.php on line 57
> \`\`\`
> \`\`\`
> 
> 
> \### Code of Conduct
> 
> \- \[X\] I confirm that I have read and agree to follow this project's Code of Conduct

Submitted a bug report here!

---

<div class="post-metadata">

**Author:** ![mikew](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.mautic.org/mikew/32/5156_2.png) [@mikew](https://forum.mautic.org/u/mikew)\
**Post date:** [August 16, 2022, 8:07am UTC](https://forum.mautic.org/t/email-dynamic-content-in-4-x-working-for-anyone/24283/5 "2022-08-16T08:07:51Z")

</div>

Hey @silavapi

I went ahead and got our developer to make a quick fix for this. He did not do it inside the Mautic branch as we just wanted it working. So I have two files, one for Mautic 4.0.x - 4.2.x and a second file for 4.3.x and upwards. Maybe it can be used to help fix the issue in GitHub.

Here are the two pieces of code:  
For Mautic 4.0.x - 4.2.x MatchFilterLeadTrait.php

```auto
<?php

namespace Mautic\EmailBundle\EventListener;

/**
 * Trait MatchFilterForLeadTrait.
 */
trait MatchFilterForLeadTrait
{
    /**
     * @return bool
     */
    protected function matchFilterForLead(array $filter, array $lead)
    {
        if (empty($lead['id'])) {
            // Lead in generated for preview with faked data
            return false;
        }
        $groups = [];
        $groupNum = 0;

        foreach ($filter as $data) {
            $isCompanyField = (0 === strpos($data['field'], 'company') && 'company' !== $data['field']);
            $primaryCompany = ($isCompanyField && !empty($lead['companies'])) ? $lead['companies'][0] : null;

            if (!array_key_exists($data['field'], $lead) && !$isCompanyField) {
                continue;
            }

            if(is_null($primaryCompany) && $isCompanyField){
                continue;
            }

            /*
             * Split the filters into groups based on the glue.
             * The first filter and any filters whose glue is
             * "or" will start a new group.
             */
            if (0 === $groupNum || 'or' === $data['glue']) {
                ++$groupNum;
                $groups[$groupNum] = null;
            }

            /*
             * If the group has been marked as false, there
             * is no need to continue checking the others
             * in the group.
             */
            if (false === $groups[$groupNum]) {
                continue;
            }

            /*
             * If we are checking the first filter in a group
             * assume that the group will not match.
             */
            if (null === $groups[$groupNum]) {
                $groups[$groupNum] = false;
            }

            $leadVal = ($isCompanyField ? $primaryCompany[$data['field']] : $lead[$data['field']]);
            $filterVal = $data['filter'];

            switch ($data['type']) {
                case 'boolean':
                    if (null !== $leadVal) {
                        $leadVal = (bool) $leadVal;
                    }

                    if (null !== $filterVal) {
                        $filterVal = (bool) $filterVal;
                    }
                    break;
                case 'datetime':
                case 'time':
                    $leadValCount = substr_count($leadVal, ':');
                    $filterValCount = substr_count($filterVal, ':');

                    if (2 === $leadValCount && 1 === $filterValCount) {
                        $filterVal .= ':00';
                    }
                    break;
                case 'tags':
                case 'multiselect':
                    if (!is_array($leadVal)) {
                        $leadVal = explode('|', $leadVal);
                    }

                    if (!is_array($filterVal)) {
                        $filterVal = explode('|', $filterVal);
                    }
                    break;
                case 'number':
                    $leadVal = (int) $leadVal;
                    $filterVal = (int) $filterVal;
                    break;
                case 'select':
                default:
                    if (is_numeric($leadVal)) {
                        $leadVal = (int) $leadVal;
                        $filterVal = (int) $filterVal;
                    }
                    break;
            }

            switch ($data['operator']) {
                case '=':
                    if ('boolean' === $data['type']) {
                        $groups[$groupNum] = $leadVal === $filterVal;
                    } else {
                        $groups[$groupNum] = $leadVal == $filterVal;
                    }
                    break;
                case '!=':
                    if ('boolean' === $data['type']) {
                        $groups[$groupNum] = $leadVal !== $filterVal;
                    } else {
                        $groups[$groupNum] = $leadVal != $filterVal;
                    }
                    break;
                case 'gt':
                    $groups[$groupNum] = $leadVal > $filterVal;
                    break;
                case 'gte':
                    $groups[$groupNum] = $leadVal >= $filterVal;
                    break;
                case 'lt':
                    $groups[$groupNum] = $leadVal < $filterVal;
                    break;
                case 'lte':
                    $groups[$groupNum] = $leadVal <= $filterVal;
                    break;
                case 'empty':
                    $groups[$groupNum] = empty($leadVal);
                    break;
                case '!empty':
                    $groups[$groupNum] = !empty($leadVal);
                    break;
                case 'like':
                    $filterVal = str_replace(['.', '*', '%'], ['\.', '\*', '.*'], $filterVal);
                    $groups[$groupNum] = 1 === preg_match('/' . $filterVal . '/', $leadVal);
                    break;
                case '!like':
                    $filterVal = str_replace(['.', '*'], ['\.', '\*'], $filterVal);
                    $filterVal = str_replace('%', '.*', $filterVal);
                    $groups[$groupNum] = 1 !== preg_match('/' . $filterVal . '/', $leadVal);
                    break;
                case 'in':
                    $leadValMatched = false;
                    foreach ($leadVal as $v) {
                        if (in_array($v, $filterVal)) {
                            $leadValMatched = true;
                            // Break once we find a match
                            break;
                        }
                    }
                    $groups[$groupNum] = $leadValMatched;
                    break;
                case '!in':
                    $leadValNotMatched = true;

                    foreach ($leadVal as $v) {
                        if (in_array($v, $filterVal)) {
                            $leadValNotMatched = false;
                            // Break once we find a match
                            break;
                        }
                    }

                    $groups[$groupNum] = $leadValNotMatched;
                    break;
                case 'regexp':
                    $groups[$groupNum] = 1 === preg_match('/' . $filterVal . '/i', $leadVal);
                    break;
                case '!regexp':
                    $groups[$groupNum] = 1 !== preg_match('/' . $filterVal . '/i', $leadVal);
                    break;
                case 'startsWith':
                    $groups[$groupNum] = 0 === strncmp($leadVal, $filterVal, strlen($filterVal));
                    break;
                case 'endsWith':
                    $endOfString = substr($leadVal, strlen($leadVal) - strlen($filterVal));
                    $groups[$groupNum] = 0 === strcmp($endOfString, $filterVal);
                    break;
                case 'contains':
                    $groups[$groupNum] = false !== strpos((string) $leadVal, (string) $filterVal);
                    break;
            }
        }

        return in_array(true, $groups);
    }
}

```

And for Mautic 4.3 upwards:

```auto
<?php

namespace Mautic\EmailBundle\EventListener;

use Mautic\LeadBundle\Segment\OperatorOptions;

/**
 * Trait MatchFilterForLeadTrait.
 */
trait MatchFilterForLeadTrait
{
    /**
     * @return bool
     */
    protected function matchFilterForLead(array $filter, array $lead)
    {
        if (empty($lead['id'])) {
            // Lead in generated for preview with faked data
            return false;
        }
        $groups = [];
        $groupNum = 0;

        foreach ($filter as $data) {
            $isCompanyField = (0 === strpos($data['field'], 'company') && 'company' !== $data['field']);
            $primaryCompany = ($isCompanyField && !empty($lead['companies'])) ? $lead['companies'][0] : null;

            if (!array_key_exists($data['field'], $lead) && !$isCompanyField) {
                continue;
            }

            if(is_null($primaryCompany) && $isCompanyField){
                continue;
            }
            /*
             * Split the filters into groups based on the glue.
             * The first filter and any filters whose glue is
             * "or" will start a new group.
             */
            if (0 === $groupNum || 'or' === $data['glue']) {
                ++$groupNum;
                $groups[$groupNum] = null;
            }

            /*
             * If the group has been marked as false, there
             * is no need to continue checking the others
             * in the group.
             */
            if (false === $groups[$groupNum]) {
                continue;
            }

            /*
             * If we are checking the first filter in a group
             * assume that the group will not match.
             */
            if (null === $groups[$groupNum]) {
                $groups[$groupNum] = false;
            }

            $leadVal = ($isCompanyField) ? $primaryCompany[$data['field']] : $lead[$data['field']];

           
            $filterVal = $data['filter'];

            switch ($data['type']) {
                case 'boolean':
                    if (null !== $leadVal) {
                        $leadVal = (bool) $leadVal;
                    }

                    if (null !== $filterVal) {
                        $filterVal = (bool) $filterVal;
                    }
                    break;
                case 'datetime':
                case 'time':
                    $leadValCount = substr_count($leadVal, ':');
                    $filterValCount = substr_count($filterVal, ':');

                    if (2 === $leadValCount && 1 === $filterValCount) {
                        $filterVal .= ':00';
                    }
                    break;
                case 'tags':
                case 'multiselect':
                    if (!is_array($leadVal)) {
                        $leadVal = explode('|', $leadVal);
                    }
                    if (!is_array($filterVal)) {
                        $filterVal = explode('|', $filterVal);
                    }
                    break;
                case 'number':
                    $leadVal = (int) $leadVal;
                    $filterVal = (int) $filterVal;
                    break;
                case 'select':
                    if (!is_array($filterVal)) {
                        $filterVal = explode('|', $filterVal);
                    }
                    break;
                default:
                    if (is_numeric($leadVal)) {
                        $leadVal = (int) $leadVal;
                        $filterVal = (int) $filterVal;
                    }
                    break;
            }

            switch ($data['operator']) {
                case '=':
                    if ('boolean' === $data['type']) {
                        $groups[$groupNum] = $leadVal === $filterVal;
                    } else {
                        $groups[$groupNum] = $leadVal == $filterVal;
                    }
                    break;
                case '!=':
                    if ('boolean' === $data['type']) {
                        $groups[$groupNum] = $leadVal !== $filterVal;
                    } else {
                        $groups[$groupNum] = $leadVal != $filterVal;
                    }
                    break;
                case 'gt':
                    $groups[$groupNum] = $leadVal > $filterVal;
                    break;
                case 'gte':
                    $groups[$groupNum] = $leadVal >= $filterVal;
                    break;
                case 'lt':
                    $groups[$groupNum] = $leadVal < $filterVal;
                    break;
                case 'lte':
                    $groups[$groupNum] = $leadVal <= $filterVal;
                    break;
                case 'empty':
                    $groups[$groupNum] = empty($leadVal);
                    break;
                case '!empty':
                    $groups[$groupNum] = !empty($leadVal);
                    break;
                case 'like':
                    $filterVal = str_replace(['.', '*', '%'], ['\.', '\*', '.*'], $filterVal);
                    $groups[$groupNum] = 1 === preg_match('/'.$filterVal.'/', $leadVal);
                    break;
                case '!like':
                    $filterVal = str_replace(['.', '*'], ['\.', '\*'], $filterVal);
                    $filterVal = str_replace('%', '.*', $filterVal);
                    $groups[$groupNum] = 1 !== preg_match('/'.$filterVal.'/', $leadVal);
                    break;

                case OperatorOptions::IN:
                    $groups[$groupNum] = $this->checkLeadValueIsInFilter($leadVal, $filterVal, false);
                    break;
                case OperatorOptions::NOT_IN:
                    $groups[$groupNum] = $this->checkLeadValueIsInFilter($leadVal, $filterVal, true);
                    break;
                case 'regexp':
                    $groups[$groupNum] = 1 === preg_match('/'.$filterVal.'/i', $leadVal);
                    break;
                case '!regexp':
                    $groups[$groupNum] = 1 !== preg_match('/'.$filterVal.'/i', $leadVal);
                    break;
                case 'startsWith':
                    $groups[$groupNum] = 0 === strncmp($leadVal, $filterVal, strlen($filterVal));
                    break;
                case 'endsWith':
                    $endOfString = substr($leadVal, strlen($leadVal) - strlen($filterVal));
                    $groups[$groupNum] = 0 === strcmp($endOfString, $filterVal);
                    break;
                case 'contains':
                    $groups[$groupNum] = false !== strpos((string) $leadVal, (string) $filterVal);
                    break;
            }
        }

        return in_array(true, $groups);
    }

    /**
     * @param mixed $leadVal
     * @param mixed $filterVal
     */
    private function checkLeadValueIsInFilter($leadVal, $filterVal, bool $defaultFlag): bool
    {
        $leadVal = !is_array($leadVal) ? [$leadVal] : $leadVal;
        $filterVal = !is_array($filterVal) ? [$filterVal] : $filterVal;
        $retFlag = $defaultFlag;
        foreach ($leadVal as $v) {
            if (in_array($v, $filterVal)) {
                $retFlag = !$defaultFlag;
                // Break once we find a match
                break;
            }
        }

        return $retFlag;
    }
}

```

For those that would like to apply the patch you can do the following:

1. cd /var/www/mautic/app/bundles/EmailBundle/EventListener/
2. Make a copy of the file MauticFilterForLeadTrait.php → MauticFilterForLeadTrait.php.orig
3. Download the relevant files above and put it inside this directory.

No need to delete cache. Dynamic Content in html email is now working.

---

<div class="post-metadata">

**Author:** ![silavapi](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.mautic.org/silavapi/32/7424_2.png) [@silavapi](https://forum.mautic.org/u/silavapi)\
**Post date:** [August 16, 2022, 10:50am UTC](https://forum.mautic.org/t/email-dynamic-content-in-4-x-working-for-anyone/24283/6 "2022-08-16T10:50:26Z")

</div>

Great, thanks!

If they can make a PR against the 4.4 branch that is where the next bugfix release will be coming from.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex020/uploads/mautic/original/1X/43c63600fe51440378769136903f1fa2a9a34102.png) [@system](https://forum.mautic.org/u/system)\
**Post date:** [August 17, 2022, 10:51pm UTC](https://forum.mautic.org/t/email-dynamic-content-in-4-x-working-for-anyone/24283/7 "2022-08-17T22:51:09Z")

</div>

This topic was automatically closed 36 hours after the last reply. New replies are no longer allowed.
