13

I've created a view for a node which shows the content as rendered entity. Among others, I output the body field in the twig template:

{{ content.field_body }}

Now, I'd like to limit the text to 200 characters and put three dots. I've tested three different ways to do that, but nothing has worked. The problem is, that each way counts and trims the HTML characters too.

1: I've added the format "Trimmed" in "Manage display" => The text is limited but not correct. And I do not have the three dots.

2: I've trimmed the text in the twig template. But to count the text I have to render it first. Thereby, twig outputs the text as HTML (I see HTML tags on my page!)

{% set text = content.field_body|render %}
{{ text|length > 200 ? text|slice(0, 200) ~ '...' : text }}

3: I've tried to solve the problem in template_preprocess_node(). Here I have the same problem with counting the HTML markup too.

$body_text = $node->get('field_body')->getValue()[0]['value'];
$trimmed_text = substr($body_text, 0, 200) . '...';

How can I trim my text right?

Thank you very much for your help!

5 Answers 5

23

There's a few solutions you can try but take note truncating strings with html is generally a bad idea due to having potential unclosed or malformed tags.

1. Use |raw to output the html as html, may produce malformed tags:

{% set text = content.field_body|render %}
{{ text|length > 200 ? text|slice(0, 200)|raw ~ '...' : text|raw }}

2. Strip html first, cleaner:

{% set text = content.field_body|render|striptags %}
{{ text|length > 200 ? text|slice(0, 200) ~ '...' : text }}

3. Register a twig extension (untested):

https://gist.github.com/leon/2857883

Another helpful extension you can check out is the Text extension, which helps you prevent chopping up words:

http://twig.sensiolabs.org/doc/extensions/text.html

6
  • 3
    first solution malformed tags and second solution strip all html tags.
    – Yuseferi
    Commented Sep 25, 2016 at 12:31
  • 1
    @zhilevan yep, as described in the answer.
    – squall3d
    Commented Sep 25, 2016 at 12:54
  • 1
    @squall3d what is your solution for slice it without strip htmls?
    – Yuseferi
    Commented Sep 25, 2016 at 12:57
  • 1
    @zhilevan usually when I want to display truncated text it's for the purpose of a teaser, where I seldom want html. But if you do need to preserve html, you can try this extension: gist.github.com/leon/2857883
    – squall3d
    Commented Sep 25, 2016 at 13:04
  • 1
    If I use the image in the body field. No 2 , is not working for images. Is there any other code, will print the image as well Commented Aug 10, 2017 at 7:09
7

Improvements:

  1. if you strip tags you should |trim to get rid of whitespace
  2. trim on word boundary - see below slice() and split()
  3. Use ellipsis (…) rather than "..."
  4. |raw the output

{% set text = content.field_header_intro|render|striptags|trim %}

{{ (text|length > 200 ? text|slice(0, 201)|split(' ')|slice(0, -1)|join(' ') ~ '…' : text)|raw }}

1
  • content.field_header_intro|render|striptags|trim this gives perfect character count.
    – Akshay
    Commented Oct 27, 2022 at 7:10
6

You can now do this with the twig_extender module and use |truncate.

Here is an example of how to use it in the .twig template, note that I'm also using twig_field_value:

{{ content.field_name|field_value|first['#text']|truncate(15, true, '....') }}

note: I usually keep my devel settings (./admin/config/development/devel) set to use Symfony var-dumper and can figure out the chain with

ie: {{ devel_dump(content.field_name|field_value) }}

4

This is how I handled this.

Example:
field--node--body--article.html.twig

{% set mode = element['#view_mode'] %}
...
{% for item in items %}
  {% if mode == 'full' %}
    <div{{ attributes.addClass('texto') }}>{{ item.content }}</div>
  {% elseif mode == 'teaser' %}
    {# if there is something about trim_length in field formatter #}
    {% if item.content['#text_summary_trim_length'] %}
      {# first remove html tags then you slice with trim_length #}
      {% set texto = item.content['#text']|striptags|slice(0, item.content['#text_summary_trim_length']) %}
      <p {{ attributes }}>{{ texto }}...</p>
    {% else %}
      <p {{ attributes }}>{{ item.content }}</p>
    {% endif %}
  {% endif %}
{% endfor %}
...
1

There is a useful truncate function in the module Twig Tweak :

{{ node.field_summary.value|truncate(11, true, true) }}

Note that the third argument is not documented and add an ellipsis (...)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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