API page: https://api.drupal.org/comment/reply/11564263

I have a custom Twig Paragraphs template which I use as base template. There I define the markup and add some classes to attributes and add the array later to the attributes object.

{#
/**
 * @file
 * Theme override for a field.
 *
 * To override output, copy the "field.html.twig" from the templates directory
 * to your theme's directory and customize it, just like customizing other
 * Drupal templates such as page.html.twig or node.html.twig.
 *
 * Instead of overriding the theming for all fields, you can also just override
 * theming for a subset of fields using
 * @link themeable Theme hook suggestions. @endlink For example,
 * here are some theme hook suggestions that can be used for a field_foo field
 * on an article node type:
 * - field--node--field-foo--article.html.twig
 * - field--node--field-foo.html.twig
 * - field--node--article.html.twig
 * - field--field-foo.html.twig
 * - field--text-with-summary.html.twig
 * - field.html.twig
 *
 * Available variables:
 * - attributes: HTML attributes for the containing element.
 * - label_hidden: Whether to show the field label or not.
 * - title_attributes: HTML attributes for the title.
 * - label: The label for the field.
 * - multiple: TRUE if a field can contain multiple items.
 * - items: List of all the field items. Each item contains:
 *   - attributes: List of HTML attributes for each item.
 *   - content: The field item's content.
 * - entity_type: The entity type to which the field belongs.
 * - field_name: The name of the field.
 * - field_type: The type of the field.
 * - label_display: The display settings for the label.
 *
 *
 * @see template_preprocess_field()
 */
#}


{%
  set classes = [
    entity_type|clean_class ~ '__ref',     // results in paragraph__ref
    'field',
    'field--name-' ~ field_name|clean_class,
    'field--type-' ~ field_type|clean_class
  ]
%}
{%
  set classes_item = []
%}


<ul{{ attributes.addClass(classes, 'field__items') }}>
  {% for item in items %}
    <li{{ item.attributes.addClass(classes_item, 'field__item') }}>
      {{ item.content }}
    </li>
  {% endfor %}
</ul>

Then I have some layout variants where I extend this base template and add a layout class.

{% extends "field--paragraph--para-ref.html.twig" %}

{% set attributes = attributes.addClass(entity_type|clean_class ~ '__ref--2col') %}

This works fine so far!

But there is one case where I need to remove a class in the extended template which is set in the base template.

{% extends "field--paragraph--para-ref.html.twig" %}

{% set attributes = attributes.removeClass('paragraph__ref').addClass(entity_type|clean_class ~ '__ref--width--full') %}

What I have experienced so far is that this does not work.

Am I doing something wrong or is this 'by design' not possible?

Comments

4aficiona2 created an issue. See original summary.

4aficiona2’s picture

Issue summary: View changes
4aficiona2’s picture

Issue summary: View changes
star-szr’s picture

Component: Classy theme » theme system
Category: Bug report » Support request
Status: Active » Fixed

This is because of how Twig extending works, and also a result of the classes being added via template - the classes aren't there yet for you to remove.

In more detail: When you're in the child template all the child template things happen, THEN the parent template is called. You can see this by looking at the compiled Twig template if you're curious (in sites/default/files/php/twig by default). In this case the classes you want to remove are not there yet on the Attribute object in the child template, so therefore they can't be removed (order of operations essentially). If the classes were added in preprocess you would be able to remove them regardless of the template because preprocess comes before any template things.

Here's one option available to you that doesn't rely on manipulating the attribute object directly, and also relies on core not using strict mode in Twig:

Relevant part of parent template:

<ul{{ attributes.addClass(classes, 'field__items', add_classes).removeClass(remove_classes) }}>

Child template that wants to remove (and add) classes:

{% extends "field--paragraph--para-ref.html.twig" %}
{% set remove_classes = ['paragraph__ref'] %}
{% set add_classes = [entity_type|clean_class ~ '__ref--width--full'] %}

A few things to note:

  • add_classes is just shown as an example, arguably more consistent than manipulating the attribute object in this case
  • remove_classes or add_classes could also be a string rather than an array
  • In your child template you can reformat the variable set calls to be multiline like in the parent template's classes variable, assuming you keep them as arrays

Hope that helps.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.