1

I'm trying to use the json_decode twig filter from Craft to decode an array of entry objects that got encoded in a macro.

In the macro, the array of entry objects gets encoded by json_encode and echoed:

{{ orderedFutureEvents|json_encode }}

This is how the macro value gets set in the template:

{% set events = craft.entries()
        .section('eventPost')
        .all() %}
{% import "_macros/events.html" as eventsMacro %}
{% set futureEvents %}
    {{ eventsMacro.futureEvents(events)|json_decode }}
{% endset %}

When loading the page it's used on, I get a syntax error:

Invalid Argument – yii\base\InvalidArgumentException

Syntax error.

The specific lines that trows the error:

yiisoft/yii2/helpers/BaseJson.php at line 133

yiisoft/yii2/helpers/BaseJson.php at line 107

Compiled template line:

$context["test"] = craft\helpers\Json::decode((isset($context["futureEvents"]) || array_key_exists("futureEvents", $context) ? $context["futureEvents"] : (function () { throw new RuntimeError('Variable "futureEvents" does not exist.', 19, $this->source); })()));

What's causing this error?

Full macro:

{% macro futureEvents(events) %}
    {% set today = "now"|date('d/m/Y') %}
    {% set now = "now"|date('U') %}
    {% set futureEvents = [] %}
    {% for event in events %}
        {% for block in event.calendar.level(1).all() %}
            {% switch block.type.handle %}
                {% case 'periodOfDays' %}
                    {% if block.endDate|date('d/m/Y') > today  %}
                        {% if block.startDate|date('d/m/Y') < today %}
                            {# Ongoing event #}
                            {% set futureEvents = futureEvents|merge([{'date': today, 'event': event}]) %}
                        {% else %}
                            {# Future event #}
                            {% set futureEvents = futureEvents|merge([{'date': block.startDate|date('d/m/Y'), 'event': event}]) %}
                        {% endif %}
                    {% endif %}
                {% case 'specificDates' %}
                    {% set tempEvent = [] %}
                    {% set break = false %}
                    {% set empty = false %}
                    {% for child in block.children.all() if not break %}
                        {% if child.dateAndTime|date('U') > now %}
                            {# Future event #}
                            {% set tempEvent = [{'date': child.dateAndTime|date('d/m/Y'), 'event': event}] %}
                            {% set break = true %}
                            {# Break because event is found #}
                        {% elseif (child.dateAndTime|date('U') + child.duration*60) > now %}
                            {# Ongoing event #}
                            {% set tempEvent = [{'date': today, 'event': event}] %}
                            {% set break = true %}
                            {# Break because event is found #}
                        {% endif %}
                        {% else %}
                            {% set empty = true %}
                    {% endfor %}
                    {% if tempEvent is same as([]) and empty %}
                        {# Fallback on default #}
                    {% elseif tempEvent is not same as([]) %}
                        {% set futureEvents = futureEvents|merge(tempEvent) %}
                    {% endif %}
            {% endswitch %}
        {% else %}
            {% if event.dateAndTime|date('U') > now %}
                {# Future event #}
                {% set futureEvents = futureEvents|merge([{'date': event.dateAndTime|date('d/m/Y'), 'event': event}]) %}
            {% elseif (event.dateAndTime|date('U') + event.duration*60) > now %}
                {# Ongoing event #}
                {% set futureEvents = futureEvents|merge([{'date': today, 'event': event}]) %}
            {% endif %}
        {% endfor %}
    {% endfor %}
    {% set orderedFutureEvents = [] %}
    {% for key in futureEvents|sort((a, b) => a <=> b)|column('date', 'event')|keys %}
        {% set orderedFutureEvents = orderedFutureEvents|merge([futureEvents[key].event]) %}
    {% endfor %}
    {{ orderedFutureEvents|json_encode|raw }}
{% endmacro %}
  • That last bit looks wrong: })())); I think you need to fix the paranthesis. – CraftN00b Oct 23 '20 at 20:48
  • Just trying to follow along... orderedFutureEvents is an array of entries that you JSON encode into a string. Is events in your macro the same JSON encoded orderedFutureEvents that gets passed into the macro? – Brad Bell Oct 26 '20 at 3:13
  • @BradBell the events parameter is an array of entry objects. The macro filters out specific entries to return a new array of entry objects. I'll update my post to make it a bit more clear. – Joorren Oct 26 '20 at 14:36
0

Guessing if you change your macro to this, it'll work:

{{ orderedFutureEvents|json_encode|raw }}

The reason being that Twig will return a Markup class that wraps the JSON content when returning from the macro that json_encode doesn't know what to do with.

Passing the contents through |raw returns the original JSON.

  • Unfortunately, adding the raw tag to the macro variable didn't solve the issue. When I dump what the macro returned, it's still a Markup object. object(Twig\Markup)#8733 (2) { ["content":"Twig\Markup":private]=> string(22297) " [{"sectionId":"5","typeId":"5", ... – Joorren Oct 26 '20 at 21:03
  • Can you share the full macro? – Brad Bell Oct 27 '20 at 2:16
  • I've added the full macro to the question. (I know it's a really bad way to handle this kind of stuff) – Joorren Oct 28 '20 at 10:10
  • Hrm... I'm out of ideas. Are you comfortable with xDebug and PHPStorm? Could debug the compiled templates to get some additional insights. – Brad Bell Oct 28 '20 at 20:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.