Skip to content
Advertisement

timber/twig how to pass `posts` php-object to JavaScript? Some values are lost

When I’m trying to pass the information contained in {{posts}} I cannot retrieve all of it, at least not the post.link information

  {% for post in posts %}
    <script>
      var t = JSON.parse('{{post|json_encode(constant('JSON_HEX_APOS'))|e('js')}}')
      t.link = '{{post.link}}'
      console.log(t)
    </script>
  {% endfor %}

Without manually adding the link, it doesn’t show up

Why is this happening and how could I workaround this?

EDIT: related https://github.com/timber/timber/issues/1434

Advertisement

Answer

You shouldn’t encode your whole post object. You should encode all the values you need separately.

The link for your post doesn’t show up, because link is not a property, but a method of the TimberPost object. This might be a little bit confusing, because in Twig we use {{ post.link }}. It looks like it’s a property or maybe an array item. But we could also use {{ post.link() }}, which is the same as {{ post.link }}. You can read more about this in the Variables section in Twig for Template Designers.

So what I would do is build a new array with the data you need and encode it to JSON in PHP with wp_json_encode().

PHP

$posts_json = [];

foreach ( $posts as $post ) {
    $posts_json[] = wp_json_encode( [
        'title' => $post->title(),
        'link' => $post->link(),
    ] );
}

$context['posts_json'] = $posts_json;

By only adding the data you need, you keep the output in the frontend small. Otherwise, you would end up with a lot of data that you will never and that only increases the page size unnecessarily.

And then in Twig, you could do it like this:

{% for post in posts_json %}
    <script>
      var t = {{ post }}
      console.log(t)
    </script>
{% endfor %}
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement