# Question
Title: Sorting on a custom date field is slower than sorting on relevance: Is there a solution?
I'm using search api with database backend on a Drupal 9.3.3 site. I've indexed 26,000 nodes of a custom content type and these include a custom date field: field\_display\_date

The index is set up to do rendered html. Since I need users to be able to sort on field\_display\_date (descending) as well as relevance, I've exposed two sorts: relevance and date (using this custom date field) and have added field\_display\_date to the index in "date" format.

The ultimate goal is to be able get highly relevant search results but be able to sort them to see the most recent highly relevant results. Maybe there's a completely different way to do this.

**Problem:** with the view all set up, key in a search term an execute. With the sort set to the default 'relevance,' returns are pretty quick. If I change the sort to 'date' (field\_display\_date: descending) and submit again, there is a very long wait time, often a gateway timeout.

On one that didn't time out, the view sql and performance redout said this...

```
Query
Index: main2
Keys: 'test'
Parsed keys: array (
    '#conjunction' => 'AND',
    0 => 'test',
  )
Searched fields: rendered_item, title
Sorting: field_display_date DESC
Options: array (
    'search_api_view' => 'object (Drupal\\views\\ViewExecutable)',
    'search_api_base_path' => 'search2',
  )
Title   Search2
Path    /search2
Query build time    1.43 ms
Query execute time  2.81 ms
View render time    43237.89 ms

```

Why is the render time so high and any ideas on how to correct this? Also, is switching to apache solr likely to work better or have the same result? (Since setting up solr looks pretty involved and is going to take me quite a while, would like to know if it's likely to be worth doing.)

By contrast, here's the same view and index and search keyword sorted by relevance...

```
Query
Index: main2
Keys: 'test'
Parsed keys: array (
    '#conjunction' => 'AND',
    0 => 'test',
  )
Searched fields: rendered_item, title
Sorting: search_api_relevance DESC
Options: array (
    'search_api_view' => 'object (Drupal\\views\\ViewExecutable)',
    'search_api_base_path' => 'search2',
  )
Title   Search2
Path    /search2
Query build time    1.23 ms
Query execute time  2.68 ms
View render time    2990.91 ms

```

This seems to suggest that the search itself and getting the result are both pretty quick but for some reason loading the page is really slow?

Interestingly, bypassing search api entirely and just plopping the body field into a regular view and searching on the keyword gets a faster result, which makes me think I'm doing something incorrectly at a fundamental level.

Plain views filter with no index, sorted by field\_display\_date descending, searching the body field for the same keyword...

```
Title   Content
Path    /admin/content/node2
Query build time    3.23 ms
Query execute time  1.2 ms
View render time    6291.28 ms

```

# Answer
This is a vague solution, because I wasn't able to determine why sort would behave this way.

I can report, though, that installing Solr and switching the index to the Solr backend resulted in there no longer being any noticeable difference with one sort vs. the other.

To clarify: same views and fields, and same index configuration. (In search api, you can switch an index's backend, then re-index). This resulted in very quick sorts using the same search result view pages.
> 0 votes

---
Tags: search, 9, performance
---


# Question
Title: Why does js click function run multiple times?
I'm creating some accordion functionality for fields and paragraphs using a combination of twig templates and a custom JavaScript file.

Everything prints as expected and the basic accordion functionality works; however, the click function script is running multiple times, causing an "expand-collapse-expand-collapse..." behavior. See image:

Here is the script file:

```
(function($, Drupal) {

/* Add span to wysiwyg button classes for alignment
------------------------------------ */
Drupal.behaviors.accordionFaqFunction = {
  attach: function (context, settings) {
        $('.toggle').click(function(e) {

                e.preventDefault();
                var $this = $(this);

                if ($this.next().hasClass('show')) {
                        $this.next().removeClass('show');
                        $this.next().slideUp(350);
                        console.log("hiding");
                } else {
                        $this.parent().parent().find('li .inner').removeClass('show');
                        $this.parent().parent().find('li .inner').slideUp(350);
                        console.log("showing");
                        $this.next().toggleClass('show');
                        $this.next().slideToggle(350);
                }
        });

  }
};

})(jQuery, Drupal);

```

Why is the script running multiple times?

# Answer
Most importantly you have to use the JQuery selector `context`. Otherwise you run the entire DOM through your js code anytime when Drupal behaviors passes you only `context` to process.

If your function still runs multiple times, add once() with a unique identifier:

```
$('input.myCustom', context).once('mySecondBehavior').each(function () {

```

Don't forget to add the library `core/jquery.once` to mytheme.libraries.yml, see https://www.drupal.org/docs/8/api/javascript-api/javascript-api-overview
> 13 votes

# Answer
I just came across this post while working something out in our project. We have multiple events bound to $('body', context) since flexibility in the platform allows for widgets and such to be placed almost anywhere within the body.

Using `$('body', context).on('click', '.modal-trigger', function (e) {});` was causing the click event to be bound on body 2x.

Simply using `$('body', context).once().on('click', '.modal-trigger', function (e) {});` was binding only the last attached/loaded script to the body, resulting in no other script events being attached.

Adding .once() with a unique identifier for each script solved this issue beautifully.

Ex. 1st modal script

```
  Drupal.behaviors.SigmaModal = {

    attach: function (context, settings) {

      // Trigger sigma dialog on click.
      $('body', context).once('SigmaModal').on('click', '.sigma-modal-trigger', function (e) {

```

2nd modal script

```
  Drupal.behaviors.DisplayModal = {

    attach: function (context, settings) {

      // Trigger generic dialogs on click.
      $('body', context).once('DisplayModal').on('click', '.modal-trigger', function (e) {

```
> 8 votes

# Answer
You can try this one on Drupal 8:

```
Drupal.behaviors.custom = {
    attach: function(context, settings) {
        if(!Drupal.behaviors.custom.click_set){
            //Your code.
            Drupal.behaviors.custom.click_set = true;
        }
    }
};

```
> 1 votes

# Answer
You should add context to the dom object, which will limit execution to a particular context.

Refer to the example below which will fetch data from a remote url.

```
Drupal.behaviors.fetchTermsAndConditions = {
    attach: function (context, settings) {
        $('#clickableElementID', context).on('click', function(){
                var remoteURL = 'https://remotejson.url';
                $.ajax({
                    type: 'GET',
                    url: remoteURL,
                    success: function (data) {
                      {
                        $('#targetElementID').append(data.value);
                      }
                    }
                  });
                });

            }
      }
    };

```

In addition if the function to be executed on global context uses the html or body context it is Drupals equivalent to `$(document).ready( myInit() );`

Read more on the Drupal documentation here https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview
> 0 votes

---
Tags: 8, theming, javascript
---


# Question
Title: Referencing media from theme settings and display it on front page
In a custom subtheme of classy base theme, I made a theme setting for referencing an image media file. Contents of file theme-settings.php:

```
<?php
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Theme\ThemeSettings;
use Drupal\system\Form\ThemeSettingsForm;
use Drupal\Core\Form;
function mytheme_form_system_theme_settings_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {

$opts = [
'#type'          => 'entity_autocomplete',
'#title'         => t("Image on startpage"),
'#description'   => t("Referencing an image."),
'#target_type'   => 'media',
'#selection_settings' => ['target_bundles' => ['image']],
];
if ($default_id = theme_get_setting('startpage_image')) {
// element stores an int ID, but default value has to be the loaded entity
$image = \Drupal::entityTypeManager()->getStorage('media')->load($default_id);
$opts['#default_value'] = $image;
}
$form['startpage_image'] = $opts;
}
?>

```

Contents of file mytheme.theme:

```
<?php

function mytheme_preprocess_page(&$variables) {
$media_id = theme_get_setting('startpage_image');
$media = \Drupal::entityTypeManager()->getStorage('media')->load($media_id);
$variables['media_build'] = \Drupal::entityTypeManager()->getViewBuilder('media')->view($media, 'media.full');
}

?>

```

And finally in the template `page--front.html.twig` the image is called by `{{ startpage_image }}`. But unfortunately, the image isn't shown (all caches rebuilt and flushed multiple times). In the last line in file mytheme.theme I also tried `view($media, 'full')` because I wasn't sure if `media.full` is the correct display mode that is built in into media core module — but this as well wasn't successfull.

Why is my code not working?

# Answer
First you should add a test to see if it's the homepage or not, using

```
\Drupal::service('path.matcher')->isFrontPage()

```

Then if you add a variables in your `hook_page` for exemple `$variables['media_build']` you could get in the twig with `{{ media_build }}`.
> 1 votes

---
Tags: 8, theming, media
---


# Question
Title: How to render a view in a custom twig template?
I created a custom twig template to override views-view-fields in an unformatted view. What I would like to do is get rid of the rendering loop and explicitly display the variables in certain positions. I used dump() to list the variables, and am seeing a list like

```
  'field_pf_site_url' =>
    object(Drupal\views\Plugin\views\field\EntityField)[4373]
      ...
  'title' =>
    object(Drupal\views\Plugin\views\field\EntityField)[4375]
      ...

```

So I tried to display the title field with

```
title3: {{ title }}<br />

```

"title3" is displayed but not the variable. How can I correctly render it? I also have a field that is an array of images; are there special tricks to displaying them?

# Answer
> 2 votes
To sum up the comments. When customizing the output of a View based on fields (not on entities rendered in view modes as suggested by @Kevin), don't start with templating too early. First use the options available in Views. The core field plugins provide a lot of options, even to rewrite the entire field content using tokens of the same field or any other field defined before (which you can hide from display if you want to use it only as token).

You can also use style plugins to show fields in columns. If the core styles don't work for you add more contrib or custom styles. See https://www.drupal.org/docs/creating-custom-modules/building-a-views-display-style-plugin-for-drupal

---
Tags: theming
---


# Question
Title: How to list content that references another content type through paragraphs
I have two content types: "Author" and "Document." The Document content type uses a Paragraph "Author\_citation" to connect the two and display all the authors (plus other fields) that worked on that Document in a block. This works fine.

I also want to show a block - on the "Author" page - listing documents connected to that author, through the paragraph.

I know I've seen a way in the past to pull this with views. But I'm not finding the answer.

# Answer
Whoohoo! I figured it out! Here's a description, using my first Content type ('document') containing a paragraph ('citation') that has an entity reference to a second content type ('author'). While showing all authors on Document is easy, to show all documents connected to that author, do this:

1. In the view, under Advanced options, create a reference to the paragraph, ie, "field\_citation: Paragraph"
2. Create a second reference, "(field\_citation: Paragraph) field\_author: Content." Set its reference in the dropdown to the 1st relationship in step one.
3. Set a contextual filter of ID, and set its relationship to (field\_author: Content) Choose 'Provide Default Value: from URL'

That's pretty much it. place the views block on the "authors" page, and it works!
> 0 votes

---
Tags: views, 9, paragraphs
---


# Question
Title: How does `drush cim` find and handle the config-directory?
I would like to know where the `config directory` is, and how `drush cim` command exactly handles it, to be more specific:

* Where are the setting files imported from, can you provide me with a path relative to the root (I mean, relative to where the main `index.php` file of `drupal` is)?
* Can we change the import path?
* Does `cim` command remove the files after they are imported, or not?
* Can we tell `drush` to just delete any (previously exported) setting files?

> **Note** that I already did read https://www.drush.org/latest/commands/config\_import/
> and https://www.drush.org/latest/commands/config\_import/
>
> But at the time of writting (namely 2022),
> that of version `9x` just lists some command-line options, not even what they do.
> And docs of version `11` (current latest) do not clarify above points either.

# Answer
> 0 votes
> Where are the setting files imported from, can you provide me with a path relative to the root (I mean, relative to where the main `index.php` file of Drupal is)?

By default they are imported from a directory and/or path with following schema:

```
sites/default/files/config_RANDOM-HASH/sync

```

I mean, the `RANDOM-HASH` part of above is replaced, and can be anything.

The configuration folder's path can be set in "`sites/default/settings.php`" file (without quotes, and relative to your `index.php`), but in multi-site environments, you may need to change "`default`" to something else.

Said file may import other files, which set the path, instead of setting the path directly in `settings.php`.

However, setting the path should look like:

```
$config_directories = array();
$config_directories['sync'] = '../d8_config/sync';

```

Which is again relative to `index.php` file (from Drupal's root, goes one folder up, for security-reasons).

> Can we change the import path?

Yes, change the path in the above said `settings.php` file.

> Does `cim` command remove the files after they are imported?

No.

> Can we tell `drush` to just delete any (previously exported) setting files?

Each time we export configurations, the old configuration files will be all deleted, and new files get created based on database (where the old files were).

**Note** that `drush cdel` takes configuration object as input argument, and deletes it (from the active configuration) in the database, not the exported `.yml` files.

---
Tags: drush, configuration
---


# Question
Title: Is there any `drush` command to delete any (previously exported) setting files?
Can we use `drush` to simply delete any (previously exported) config-directory files?

# Answer
> -2 votes
**No.**

Simpy use your your operating system's file-browser to delete manually, there will be no issue (nothing depends on those files, except maybe importing).

Althoug, each time we export configurations, the old configuration files will be all deleted automatically, and new files get created based on database (where the old files were).

> **Note** that not even `drush cdel` is up to the task, because `cdel` takes configuration object as input argument, and deletes it (from the active configuration) in the database, not the exported `.yml` files.

# Answer
> 3 votes
Exported config files are regular files. So, if you want to delete them, you can delete them like you would any other file-- either use your operating system's file manager, or use the command line.

There is no need for drush to support this because every operating system offers robust support for deleting directories of files.

---
Tags: drush, configuration
---


# Question
Title: How to use datelist in a custom field widget?
Since an administrator of the website I am building is visually impaired, I need to create a custom date field widget rather than use the one provided by Drupal.

I am trying to implement a `datelist` element.

```
<?php

namespace Drupal\my_module\Plugin\Field\FieldWidget;

use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Accessible date field widget.
 *
 * @FieldWidget(
 *   id = "accessible_date",
 *   label = @Translation("Accessible date widget"),
 *   field_types = {
 *     "datetime"
 *   }
 * )
 */
class AccessibleDate extends WidgetBase {

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $max_year = date('Y') + 1;
    $default_date = new DrupalDateTime();
    if (isset($items[$delta]->value)) {
      $default_date = new DrupalDateTime($items[$delta]->value);
    }

    $element += [
      '#type' => 'datelist',
      '#default_value' => $default_date,
      '#date_part_order' => [
        'day',
        'month',
        'year',
        'hour',
        'minute',
      ],
      '#date_year_range' => '2000:' . $max_year,
    ];

    return ['value' => $element];
  }

}

```

The widget is displayed correctly but when I submit the form to add or edit a node, I have the following error on each of the datelist fields: "The datetime value must be a string."

Do you know how to fix this?

# Answer
> 0 votes
Ok I figured it out, the datetime format needs a `Y-m-dTH:i:s` format. I added a validate callback to my element to alter the data.

```
  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $max_year = date('Y') + 1;
    dpm($items[$delta]->value);
    $default_date = new DrupalDateTime();
    if (isset($items[$delta]->value)) {
      $default_date = new DrupalDateTime($items[$delta]->value);
    }

    $element += [
      '#type' => 'datelist',
      '#default_value' => $default_date,
      '#date_part_order' => [
        'day',
        'month',
        'year',
        'hour',
        'minute',
      ],
      '#date_year_range' => '2000:' . $max_year,
      '#element_validate' => [
        [static::class, 'validate'],
      ],
    ];

    return ['value' => $element];
  }

  /**
   * Prepare datelist value.
   */
  public static function validate($element, FormStateInterface $form_state) {
    $value = $element['#value'];
    $date = $value['year'] . '-' . $value['month'] . '-' . $value['day'] . 'T' . $value['hour'] . ':' . $value['minute'] . ':00';
    $form_state->setValueForElement($element, $date);
  }

```

---
Tags: entities, 9
---


# Question
Title: Check if a field is empty inside a twig paragraph template
I know how to check if a field is empty in a twig template (example node--lorem.html.twig):

```
{% if node.field_lorem.value is not empty %}

    <p>not empty</p>

{% else %}

    <p>empty</p>

{% endif %}

```

I would like to check if a field is not empty inside a paragraph twig template (example `paragraph--lorem.html.twig`). But this doesn't work :

```
{% if content.field_lorem.value is not empty %}

```

or

```
{% if node.field_lorem.value is not empty %}

```

I can display this field value like this :

```
{{ content.field_lorem }}

```

# Answer
> 4 votes
To check if a field is empty use ItemList::isEmpty

**Node**

```
{% if node.field_example.isempty %}
  <p>Field is empty</p>
{% endif %}

```

**Paragraph**

```
{% if paragraph.field_example.isempty %}
  <p>Field is empty</p>
{% endif %}

```

---
Tags: theming, paragraphs
---


# Question
Title: How do you receive JSON data in a controller?
I'm using AngularJS one of my module's settings page, so I have a javascript object in client side as a model.

This is the model I assembled with Angular.

```
var model = {
  title: 'This is a title',
  url: '/random-custom-url',
  description: 'little descrp',
  blocks: [
    {id: 1, name: 'block1', description: 'blockdecrtiption1', terms: [{"tid":"1","name":"term1","vid":"tags"}]},
    {id: null, name: 'block2', description: 'blockdecrtiption2', terms: []},
    {id: 3, name: 'block3', description: 'blockdecrtiption3', terms: []}
  ]
};

```

I'd like to "catch" it in a controller's function (as a PHP associative array), so then I can process it and save to database. (I have some tables in the database, created with `hook_schema()`).

In the controller's method, how can I get the data posted with AJAX and convert it to an associative array?

Thanks a lot!

# Answer
> 11 votes
Do not create your own table; that's not the Drupal 8 way. Instead, create your own entity type. Introduction to Entity API in Drupal 8 can be a starting point to understand better the entity API.

The storage controller will generate the SQL schema for you and do all the storage work. The REST module will handle what you need.

For a generic case to receive and reply with JSON, first make sure there isn't a Drupal API for it. Likely there is. REST gives you entities, the Views module gives you lists of entities.

If there isn't an API you can use, you need to write a custom controller with the request as an argument by just adding `Request $request` to the method parameters. (See Parameters in routes for more.)

To respond with JSON, use any `Response` object, for example `JsonResponse`. See `TimezoneController::getTimeZone()` and the relevant routing entry in core/modules/system/system.routing.yml.

```
class MyController {

  public function myJson(Request $request) {
    $params = array();
    $content = $request->getContent();
    if (!empty($content)) {
      $params = json_decode($content, TRUE);
    }
    return new JsonResponse($params);
  }
}

```

# Answer
> 14 votes
In case you want to do it more the D8 way here is a rough outline what you could do, which allows you to be flexible without the requirement to do everything in your own. A proper rest integration requires you to work with all the different HTTP status codes, header fields etc. Rest takes partly care of that

The rest module provides a generic abstraction for REST, not tight to entities in the first place. Entities are just one example.

First you should register your rest plugin, like every other plugin:

```
namespace Drupal\pinguin\Plugin\rest\resource;

use Drupal\rest\Plugin\ResourceBase;

/**
 * Provides a resource for database watchdog log entries.
 *
 * @RestResource(
 *   id = "pinguin",
 *   label = @Translation("Example rest plugin for pinguins"),
 *   uri_paths = {
 *     "canonical" = "/pinguin/{id}"
 *   },
 *   serialization_class = "Drupal\pinguin\PingInterface"
 * )
 */
class Pinguin extends ResourceBase {
}

```

If you do an updating request like PUSH or UPDATE, it uses the serializer component to convert your data into some php array/ object. It uses two steps in order to do that. First the data incoming is decoded, for example from JSON into a PHP array. The next step is the denormalization. This step converts the denormalized data (PHP array) into a domain object, for example the Ping (a single pinguin).

The first step is to specify the resulting class in the annotation (see above). To register a new denormalization you add the following entry into your .services.yml:

```
services:
  pinguin.denormalizer.pinguin:
    class: Drupal\pinguin\normalizer\PinguinDenormalizer
    tags:
      - { name: normalizer }

```

This normalizer specifies which interface it can convert to:

```
<?php

namespace Drupal\pinguin\normalizer;

use \Drupal\serialization\Normalizer\NormalizerBase;

class PinguinDenormalizer extends NormalizerBase {

   // IMPORTANT
   /**
    * The interface or class that this Normalizer supports.
    *
    * @var array
    */
    protected $supportedInterfaceOrClass = array('Drupal\pinguin\PingInterface');

    /**
    * {@inheritdoc}
    */
    public function denormalize($data, $class, $format = NULL, array $context  = array()) {
      // Validate the data.
      if (empty($data['location']) || $data['location'] == 'northpole') {
        throw new \UnexpectedValueException("this can't be real pinguins");
      }

      // create the domain object.
      return new Ping($data['name'], $data['location'], $data['family']);
    }
 }

```

Once this serialization is done, it calls a method named after the HTTP method on the plugin class, so for example "post". There you can do whatever you want.

```
<?php
class Pinguin extends ResourceBase {
  public function post(PingInterface $ping) {
    // deal with the data, save it for example.
    $ping_storage->save($ping):
  }
}

```

The advantages of these abstractions are that you don't have to deal with the incoming format but on the other hand it needs a bunch of code to get started.

# Answer
> 5 votes
> In the controller's method, how can I get the data posted with AJAX and convert it to an associative array?

```
use Drupal\Component\Serialization\Json;

class MyController {
  public function myPostAction(Request $request) {
    $params = Json::decode($request->getContent());
    //...
  }
}

```

# Answer
> 1 votes
Got this working for Drupal 9:

```
// Need to get POST params
// https://drupal.stackexchange.com/questions/207044/how-to-get-post-and-get-parameters
  $json_string = $request->request->get('json_string');
  $decoded = \Drupal\Component\Serialization\Json::decode($json_string);
  foreach ($decoded as $product) {
    print ($product['endTimeVal']);
    // etc.
  }

```

and the AJAX:

```
jQuery.post("/neway/addtocart", {json_string: JSON.stringify(cartItems)})
  .done(function () {
    console.log("success - reload (and reset) the page");
    // window.location.reload();
  })
  .fail(function () {
    console.log("error");
  })
  .always(function () {
    console.log("finished");
  });

```

---
Tags: 8
---


# Question
Title: How can one use one Webform element's selection as the argument in an Entity Select element using Views
I am hoping to use the selected option of one Webform element ("Organization") as the argument in an Entity Select element ("Site") using Views handler.

```
organization:
  '#type': entity_select
  '#title': 'What is the name of your organization?'
  '#empty_option': 'Please select'
  '#target_type': node
  '#selection_handler': 'default:node'
  '#selection_settings':
    target_bundles:
      organizations: organizations
site:
  '#type': entity_select
  '#title': Site
  '#target_type': node
  '#selection_handler': views
  '#selection_settings':
    view:
      view_name: sites
      display_name: entity_reference_1
      arguments:
        - 'WHAT DO I PUT HERE TO REPRESENT ORGANIZATION?'

```

I wouldn't expect this to happen with tokens, which become available after submission, but I was thinking this could potentially be done using "data", which is available to Webform Computed Twig elements. I tried adding `'#ajax': true` to the Entity Select element and then putting `{{ data.organization }}` as the argument, but that didn't work.

Thank in advance for any tips!

# Answer
So my colleague, @nikathone, provided the following code, to be put in a .module file. Replace the MYMODULE and MY\_WEBFORM\_ID according to your needs:

```
<?php

use Drupal\Core\Form\FormStateInterface;
use Drupal\webform\Element\WebformEntitySelect;

/**
 * Implements hook_webform_submission_form_alter().
 */
function MYMODULE_webform_submission_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  $webform_id = $form['#webform_id'] ?? '';
  if ($webform_id !== 'MY_WEBFORM_ID') {
    return;
  }

  $organization_element = $form['elements']['organization'] ?? [];
  $site_element = $form['elements']['site'] ?? [];
  if (!$organization_element || !$site_element || empty($site_element['#selection_settings']['view'])) {
    return;
  }

  // Settings ajax related properties.
  $site_element_wrapper_id = $site_element['#webform_id'] . '--wrapper';
  $organization_element['#ajax'] = [
    'callback' => 'MYMODULE_webform_submission_form_organization_element_ajax_callback',
    'wrapper' => $site_element_wrapper_id,
  ];
  $site_element['#prefix'] = '<div id="' . $site_element_wrapper_id . '">';
  $site_element['#suffix'] = '</div>';

  // Attempting to retrieve possible selected organization.
  if (!($selected_organization = $form_state->getValue('organization'))) {
    $selected_organization = $organization_element['#default_value'] ?? 0;
  }
  // Apply the selected organization if a selected one was found.
  if ($selected_organization) {
    $site_element['#selection_settings']['view']['arguments'] = [$selected_organization];
    // Reset the options so that we can repopulate it again. Without this the
    // ::setOptions method above won't process the new arguments.
    $site_element['#options'] = [];
    $form_object = $form_state->getFormObject();
    $settings = ['webform_submission' => $form_object->getEntity()];
    WebformEntitySelect::setOptions($site_element, $settings);
  }

  $form['elements']['organization'] = $organization_element;
  $form['elements']['site'] = $site_element;
}

/**
 * Ajax callback for the site element.
 *
 * @param array $form
 *   The full form element.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The form state.
 *
 * @return array
 *   The site element array.
 */
function MYMODULE_webform_submission_form_organization_element_ajax_callback(array $form, FormStateInterface $form_state) {
  return $form['elements']['site'];
}

```
> 0 votes

---
Tags: webforms, 9
---


# Question
Title: Adding Middleware::retry() to a custom httpClient effects the default http_client
We have two http\_clients in our custom service file on `__construct`, one default from Drupal's `http_client` service, another custom new Client created by the use of `http_client_factory` and `http_handler_stack` services following formOptions function.

The custom client was used to implement guzzle's retry mechanism by pushing `Middleware::retry` into the current handler\_stack in our custom services. But this middleware seems to be consistent in the default `httpClient` as well, causing all client calls going through the `retryDecider()`. gist of reference

I want to seperate Middleware effect of both clients, what should I do? Thanks for providing your share of knowledge!

```
  /**
   * Constructs a new service object.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, ClientInterface $http_client, ClientFactory $http_client_factory, HandlerStack $stack, TimeInterface $datetime_time, ConfigFactoryInterface $config_factory) {
    $this->entityTypeManager = $entity_type_manager;
    $this->datetimeTime = $datetime_time;
    $this->configFactory = $config_factory;
    $this->httpClient = $http_client;

    // Utilise retry middleware to retry 2 times, base on timeout of 20sec.
    $stack->push(Middleware::retry($this->retryDecider(), $this->retryDelay()));
    $this->customClient = $http_client_factory->fromOptions([
      'handler' => $stack,
      'timeout' => 20,
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function apiRequest($type, $method, array $data = [], $retry = FALSE) {
    $client = $retry ? $this->customClient : $this->httpClient;
    switch ($method) {
      case "POST":
        $result = $client->request('POST', $this->requestUrl . '/' . $type, [
          'form_params' => $data,
          'headers' => [
            'Accept'     => 'application/x-www-form-urlencoded',
          ],
        ]
        );
        break;

      case "GET":
        $result = $client->request('GET', $this->requestUrl . '/' . $type, [
          'query' => $data,
          'headers' => [
            'Accept'     => 'application/json',
          ],
        ]
        );
        break;

      case "PATCH":
        $result = $client->request('PATCH', $this->requestUrl . '/' . $type, [
          'form_params' => $data,
          'headers' => [
            'Accept'     => 'application/x-www-form-urlencoded',
          ],
        ]);
    }

    $apiRequest = $result->getBody()->getContents();

    return json_decode($apiRequest);
  }

  /**
   * Boolean decider of retry attempts for Guzzle.
   */
  protected function retryDecider() {
    return function (
      $retries,
      Request $request,
      Response $response = NULL,
      RequestException $exception = NULL
   ) {
      if ((0 < $retries) && ($retries <= 2)) {
        $this->getLogger('API')->info('%uniqid SystemAction retryDecider msg="Retrying %retries"', [
          '%uniqid' => $this->uniqid,
          '%retries' => $retries,
        ]);
      }
      // Limit the number of retries to 3.
      if ($retries >= 2) {
        $this->getLogger('API')->info('%uniqid SystemAction retryDecider msg="Attempt on Retrying for Guzzle Client"', [
          '%uniqid' => $this->uniqid,
        ]);
        return FALSE;
      }

      // Retry connection exceptions.
      if ($exception instanceof ConnectException) {
        return TRUE;
      }

      if ($response) {
        // Retry on server errors.
        if ($response->getStatusCode() >= 500) {
          return TRUE;
        }
      }

      return FALSE;
    };
  }

  /**
   * Delay of each retries between request attempts.
   */
  protected function retryDelay() {
    return function ($numberOfRetries) {
      return 1000 * $numberOfRetries;
    };
  }

```

# Answer
> 1 votes
It seems to me like by altering the injected **$stack**, you affect the default one.

Try to create a new one with `HandlerStack::create();` or clone the $stack you get injected, by `$mystack = clone $stack;`

There is also the onHandlerStack event you could apply, based on "what", I cannot tell you ;)

---
Tags: 9
---


# Question
Title: Why when I upload an image the image styles are not shown for the first time?
My settings are,

```
allow_insecure_derivatives: true
suppress_itok_output: false

```

Editing the itok token for the image src works at the browser level.

Does anyone know what causes the issue and a fix for it?

Notes :

1. When I hit CTRL+SHIFT+R in the browser the imagestyle images reappear. So the issues seems to be image is not present for the first time and browser is caching it.
2. The actual image can be accessed even for the first time without any issues. The issue is only with the image style images.
3. When I look at the actual image in the files folder, I see that there is an additional image with \_0 attached to it. So looks like when the image is uploaded for the first time, it is assuming there is a duplicate and creating a new image. But still not sure why it would cause this issue.

# Answer
> 0 votes
I had the exact same issue and as Russellt said, the issue was an extra space before a \<?php tag. There's a full thread about the issue here https://www.drupal.org/node/2195311

# Answer
> 2 votes
Without access to the environment, it's going to be near impossible to know what's going on.

Something between the upload AJAX request, the image form element render, and the image style request, is causing the upload/render process to break. With that known, you can try debugging through key parts of this process to determine where key assumptions break:

1. `file_managed_file_save_upload()`: Is the file being saved correctly at this point? Is there anything in the about the file system/configuration that creates a duplicate file?
2. `ImageStyle::buildUrl()`: After the file is saved and the form element is being rendered, is the style URL being generated correctly? Is the token correct? Is the file used the same as the one previously saved?
3. `ImageStyleDownloadController::deliver()`: Upon browser update, is the image payload delivery working correctly? Is this code being triggered (e.g. not proxied through some CDN)? Can it access the same file that was previously saved?

You can use Devel functions (e.g. `dpm(debug_backtrace())`), standard PHP debugging functions (e.g. `debug_print_backtrace()`), or whatever else your favorite IDE might provide you (e.g. XDebug/DBGp integration) to inspect state during these key functions to get to the bottom of the problem.

# Answer
> 1 votes
Are you using File (Field) Paths?

If yes, this is the module which is disturbing the thumbnail generation in the form.

# Answer
> 1 votes
Same happened to me while I was on maintenance mode, Images styles was not generated, images not being loaded (404), once I turned maintenance off, it worked fine.

# Answer
> 1 votes
I have had this several times, either because I have left a kint function uncommented(seems to cause Ajax to fail to display derivatives), or one of my custom modules(or settings.php) has a blank line before the opening php tag. Worth checking.

---
Tags: 8, media
---


# Question
Title: How do I handle smart quotes and curly apostrophes?
I'm building a new Drupal site, and the content authors and editors ared dyed-in-the-wool Microsoft Word users. I've got WYSIWYG set up to force all pasting to be treated as "Paste from Word", so much of Word's garbage seems to be handled well. The one remaining problem is characters like smart quotes, curly apostrophes, em-dashes, and the like. Although I'm shooting for end-to-end Unicode, and theoretically that should prevent those characters from showing up as weird garbage, I consider it safer to use HTML entities, in case at some future point someone else changes something that interferes with the end-to-end Unicode architecture.

Is there a way to convert non-ASCII characters into HTML entities, either when they are pasted or before they are displayed?

Converting to straight quotes (and using Typogrify to render them as smart quotes) would be fine too, if you can tell me how to convert to straight quotes. Preferably, other characters should be as well handled.

# Answer
> 2 votes
> Converting to straight quotes (and using Typogrify to render them as smart quotes) would be fine too, if you can tell me how to convert to straight quotes.

I had to do that for an online dictionary I built recently with Drupal 9.2. What I did is to create a `drush` command that updates all nodes (creating a new revision) converting all quote characters to straight quotes or ASCII quotes:

```
<?php

namespace Drupal\diccionari_custom\Commands;

use Drush\Commands\DrushCommands;

/**
 * A Drush commandfile.
 */
class DiccionariCustomCommands extends DrushCommands {

  /**
   * Standarize quotes.
   *
   * @usage diccionari_custom:standarizeQuotes
   *   Usage description
   *
   * @command diccionari_custom:standarizeQuotes
   */
  public function standarizeQuotes() {

    $query = \Drupal::entityQuery('node');
    $entity_ids = $query->execute();
    foreach ($entity_ids as $nid) {
      $node = \Drupal\node\Entity\Node::load($nid);

      $new_title = str_replace('‘', "'", $node->title->value);
      $new_title = str_replace('’', "'", $new_title);
      $new_title = str_replace('ʹ', "'", $new_title);
      $new_title = str_replace('ꞌ', "'", $new_title);
      $new_title = str_replace('“', '"', $new_title);
      $new_title = str_replace('”', '"', $new_title);
      $new_title = str_replace('‘', "'", $new_title);
      $new_title = str_replace('’', "'", $new_title);
      $new_title = str_replace('ʹ', "'", $new_title);
      $new_title = str_replace('ꞌ', "'", $new_title);
      $new_title = str_replace('“', '"', $new_title);
      $new_title = str_replace('”', '"', $new_title);
      $node->setTitle($new_title);

      $new_content = str_replace('‘', "'", $node->body->value);
      $new_content = str_replace('’', "'", $new_content);
      $new_content = str_replace('ʹ', "'", $new_content);
      $new_content = str_replace('ꞌ', "'", $new_content);
      $new_content = str_replace('“', '"', $new_content);
      $new_content = str_replace('”', '"', $new_content);
      $new_content = str_replace('‘', "'", $new_content);
      $new_content = str_replace('’', "'", $new_content);
      $new_content = str_replace('ʹ', "'", $new_content);
      $new_content = str_replace('ꞌ', "'", $new_content);
      $new_content = str_replace('“', '"', $new_content);
      $new_content = str_replace('”', '"', $new_content);
      $node->body->value  = $new_content;
      $node->body->format = 'basic_html';

      $node->setNewRevision(TRUE);
      $node->revision_log = 'Converting quotes to straight quotes';
      $node->setRevisionCreationTime(REQUEST_TIME);
      $node->setRevisionUserId(1);
      $node->save();

      $this->logger()->success(dt($nid . ':' . $node->title->value));
    }
  }
}

```

Now, when outputting the content, you can use a text format and Typogrify module to do the conversion to smart quotes.

And if you have to perform that conversion in the title too, see my last comment in this Drupal.org issue.

> Preferably your solution will handle other characters as well.

Both the drush command example and Typogrify settings can easily be extended to handle other characters.

# Answer
> 2 votes
You can create a custom text filter, which does a search and replace for the characters you want to replace, and apply that to any textfields where people may past word: https://www.drupal.org/forum/support/module-development-and-code-questions/2020-01-28/creating-a-custom-text-filter This will replace the quotes wherever the text field is outputted.

---
Tags: wysiwyg, input-formats
---


# Question
Title: How do I set the expiration value for tempstore.private service?
I am using the tempstore.private service, which uses an expiration time of one week. I need to change this; changing it globally is fine.

There is an `$expire` property, but I've no idea how I'm supposed to set it.

# Answer
> 2 votes
The expiration time is a parameter set in the service container. If you look at `core/core.services.yml` you will see the `tempstore.expire` parameter is set with a default value of 604800 seconds. This value is set when the container is compiled, and will be the same for all private tempstores.

There doesn't seem to be a way to set this in code or to override the parameter with a configuration setting, although I do see some issues in the core issue queue for adding that ability.

So apart from editing core.services.yml, you can override the `tempstore.private` service in your own module in order to customize the behavior.

---
Tags: 8
---


# Question
Title: Should I use an entity reference for nodes or taxonomy terms?
I'm dealing with a plant content type that currently contains a paragraph field. The paragraph contains an entity reference to *Common name* and an *Origin* text field (with the setting to create if it doesn't already exist). My reason is that common names can apply to numerous plants.

Before I add data, I'm wondering whether taxonomy terms are better for common names. Do nodes take up less memory than taxonomy term? I don't need more fields than the body field that exists on both.

I don't need any hierarchy. I need a simple way to create, reference, and view pages for that common name, and show any related scientific name.

# Answer
Which entity to use in the reference field depends on what features you are going to need or implement. The main purpose of taxonomy terms is filtering a list of entities basing on the taxonomy terms they use.

Taxonomy terms are still the lighter entity to use in entity reference fields. The differences between taxonomy terms and nodes are the following.

* #### Nodes store a reference to the user who created them

To that user (the *node owner*) are given permissions other users could not have, for example being able to update the node the owner created (as Drupal implements the *edit own content* and *edit any content* permissions). It can also be used to filter the entities shown to a user, or the entities a user can select.
* #### Nodes don't have a weight or a parent node

Taxonomy terms have a weight and a parent taxonomy term (used for hierarchies).
* #### Nodes allow to restore a previous revision

The user interface to restore a previous revision of a taxonomy term is still not implemented. \[PP-1\] Add revision UI for taxonomy terms would fix this, but it's now postponed since 4 years ago.
* #### There are modules that add features associated to nodes, but not to taxonomy terms

For example, the *Statistics* module logs content statistics, but not statistics about taxonomy terms; the *History* module records which user has read which content, but it doesn't do the same for the taxonomy pages (the pages showing a list of entities using a taxonomy term). There are other modules that could require you use nodes instead of taxonomy terms.
> 2 votes

# Answer
It's unclear whether you are talking about "memory" in the sense of RAM/performance or storage.

As for performance, taxonomy and content are both entities, so underneath the performance will be similar. Obviously if you really care about performance you need to do benchmarking, but since you said your needs are simple, I would just use taxonomy because it is designed for sharing common info among nodes.

For example, with the **Tags** taxonomy vocabulary that comes with Drupal core, you can have thousands of tags on cheap shared hosting and you are unlikely to have any performance issues due to the taxonomy.

As for storage, storing taxonomy takes up slightly more room than adding a **Common name** field to the content and putting all the data there. It takes up more room because you have to create entities, which have an entity ID and so on. However, this is generally negligible and not something to worry about-- creating a field instead of taxonomy will make it much harder to make your view of common names and to add additional info about them.
> 0 votes

---
Tags: nodes, taxonomy-terms, 9
---


# Question
Title: How to overwrite a file upload so that the filename is always the same?
I am trying to implement a file upload form in which files are saved. I had written the following code

```
<?php

/**
 * @file
 * Contains \Drupal\avenue_product_import\Form\avenue_product_importForm.
 */

namespace Drupal\avenue_product_import\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\file\Entity\File;

class AvenueForm extends FormBase {

  public function getFormId() {
    return 'AvenueForm';
  }

  public function buildForm(array $form, FormStateInterface $form_state) {

    $form['description'] = [
      '#markup' => '<p>Use this form to upload a CSV file of Data</p>',
    ];

    $form['import_csv'] = [
      '#type'              => 'managed_file',
      '#title'             => t('Upload file here'),
      '#upload_location'   => 'public://importcsv/',
      '#default_value'     => '',
      "#upload_validators" => ["file_validate_extensions" => ["csv"]],
      '#states'            => [
        'visible' => [
          ':input[name="File_type"]' => ['value' => t('Upload Your File')],
        ],
      ],
    ];

    $form['actions']['#type'] = 'actions';

    $form['actions']['submit'] = [
      '#type'        => 'submit',
      '#value'       => $this->t('Upload CSV'),
      '#button_type' => 'primary',
    ];

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {

    /* Fetch the array of the file stored temporarily in database */
    $csv_file = $form_state->getValue('import_csv');

    /* Load the object of the file by it's fid */
    $file = File::load($csv_file[0]);

    /* Set the status flag permanent of the file object */
    $file->setPermanent();

    /* Save the file in database */
    $file->save();

    drupal_set_message('File Uploaded Successfully');
  }

}

```

But here the problem is if the filename in which I am uploading is same. It is getting renamed. But I want to replace old with the new one. How can I achieve this? I had seen `file_move()` and `file_save_upload()` function. What changes should I make to replace existing filename with the newly uploaded CSV file?

# Answer
This would save always save the latest upload to `public://importcsv/avenue.csv`:

```
public function submitForm(array &$form, FormStateInterface $form_state) {

  /* Fetch the array of the file stored temporarily in database */
  $csv_file = $form_state->getValue('import_csv');

  /* Load the object of the file by it's fid */
  $file = File::load($csv_file[0]);

  $file_real_path = \Drupal::service('file_system')->realpath($csv_file->getFileUri());
  $file_contents = file_get_contents($file_real_path);
  file_unmanaged_save_data($file_contents, 'public://importcsv/avenue.csv', FILE_EXISTS_REPLACE);

  drupal_set_message('File Uploaded Successfully');
}

```
> 1 votes

# Answer
In Drupal 9 I was able to save the uploaded file so that the filename is always the same, as follows:

```
public function submitForm(array &$form, FormStateInterface $form_state) {

  // Loads file from upload form.
  $csv_file = $form_state->getValue('import_csv');
  $file = File::load($csv_file[0]);

  // Gets content from file.
  $file_real_path = \Drupal::service('file_system')->realpath($file->getFileUri());
  $file_contents = file_get_contents($file_real_path);

  // Saves new file with fixed name and replaces any existing file.
  \Drupal::service('file.repository')->writeData($file_contents, 'public://import.csv', FileSystemInterface::EXISTS_REPLACE);

  // Deletes the uploaded file.
  $file->delete();
  $this->messenger()->addStatus($this->t('The file has been uploaded.'));
}

```

I used Cesar's example as a starting point.
> 0 votes

# Answer
You could check if a file exists with that name beforehand? If so, remove it and continue saving.

https://api.drupal.org/api/drupal/core%21includes%21file.inc/function/file\_delete/8.5.x

or

https://api.drupal.org/api/drupal/core!lib!Drupal!Core!File!FileSystem.php/function/FileSystem%3A%3Aunlink/8.2.x
> -1 votes

---
Tags: 8, forms, files
---


title: Disabling Flag link access on view

text:
# Question
Title: Disabling Flag link access on view
I have a custom entity displayed in a view. If some field is of a certain value, the Flag link should not be available and replaced by some text.

```
function my_module_preprocess_flag(&$vars){
  $f = \Drupal::service('flag.link_builder');
  if ($vars["flaggable"]->field_my_field->getValue() != null) {
    if ($vars["flaggable"]->field_my_field->getValue()[0]["value"] == "0") {
      $link = $f->build('flag', $vars['flag']->id(), 'buy');
      $link["#access"] = FALSE;

    }
  }
}

```

Nothing seems to happen.

What could be the solution here?

# Answer
> 1 votes
I managed to disable the link by changing my function.

```
function my_module_preprocess_flag(&$vars){
  if ($vars["flaggable"]->field_my_field->getValue() != null) {
    if ($vars["flaggable"]->field_my_field->getValue()[0]["value"] == "0") {
      $vars["title"]["#markup"] = "New text";
      unset($vars["attributes"]["href"]);

    }
  }
}

```

---
Tags: views, flags
---


# Question
Title: Commerceguys/addressing missing locality in for some countries
I spent the weekend digging into this one. Pretty sure that the issue is a bug (or missing data) from https://github.com/commerceguys/addressing

I've installed a clean version of Drupal 9.3.6 Installed address module 8.x-1.10 Commerceguys/addressing v1.2.2

Added "address" as a field to a new (and only node).

Some countries display locality (e.g., state/province) others don't. I've filed a report in the issue queue (here), but wondering if anyone has encountered this and if so if there is a workaround.

# Answer
The Address module uses the Addressing library to display localities.

After installing the Address module, you can find the actual locality data here:

`/vendor/commerceguys/addressing/resources/subdivision/COUNTRY-CODE.json`

Where `COUNTRY-CODE` is the two-letter ISO code for that country.

As for 2-2022, Italy (`IT`) has data, but France (`FR`) does not.

You can easily create data for additional countries yourself. All you need to do is use one of the existing files as an example and get a list of ISO codes for the localities in question. Then you can add your JSON data as a PR to the addressing repo and hopefully it can get included for everyone.
> 3 votes

---
Tags: 9
---


# Question
Title: Is there a way to downgrade core from 9.3.6 to 9.2.7?
After updating the Drupal core version from 9.2.7 to 9.3.6 I got an error.

> TypeError: Argument 1 passed to Drupal\Core\File\FileUrlGenerator::generateAbsoluteString() must be of the type string, null given

I tried to apply the patch in TypeError: Argument 1 passed to Drupal\Core\File\FileUrlGenerator::generateString() must be of the type string, null given but it gives an error.

> Could not apply patch! Skipping. The error was: Cannot apply patch 3254245-78.patch.

Is it possible to downgrade the core version to get rid of this issue?

# Answer
If you already ran the database updates, no, you cannot downgrade; you need to fix the error.

If you did not run the database updates, you should be able to revert the code (for example, in git if you're using that) without any problem.

The real solution is to **always make a database backup (and code backup if you are not using version control) before updating anything.**

**If you already have a database backup**

You can re-install the old version of Drupal (9.2.7) and then restore the database backup and everything should be fine. You can do it locally with whatever environment you are using to develop your site.
> 2 votes

---
Tags: 9
---


# Question
Title: How do I check if an image field is empty in a template file?
I am trying to check if the user\_picture field is empty using the twig template, but I am not able to do this.

I tried lots of ways:-

```
{% if node.user_picture.value %}
{% if node.user_picture.entity %}
{% if content.user_picture.value %}
{% if content.user_picture|render.entity %}
{% if content.user_picture|render %}

```

---

Sample of code:

```
  {% if node.user_picture.value %}
    <p>User-picture 02</p>
    {{ user_picture }}
  {% else %}
    <p>Anymonus-picture 02</p>
    <div>
      <a href="#"><img src="{{base_path}}/WEBSITE/themes/THEME/images/anonymous.jpg" alt=""></a>
    </div>
  {% endif %}

```

# Answer
Use the method isEmpty() on the image field:

```
  {% if node.field_image.isempty %}
    <p>Field "field_image" is empty.</p>
  {% endif %}

```

Although in this case you might need to check the user entity of the node author:

```
  {% if node.uid.entity.user_picture.isempty %}
    <p>Picture of the node author is empty.</p>
  {% endif %}

```
> 10 votes

# Answer
I was able to use either one of the following in a template. The key to all of this is that you use `node.user_picture`.

```
{% if node.user_picture is empty %}
{% if node.user_picture.isEmpty() %}
{% if node.user_picture.isEmpty %}

```

That can be used to verify the field is empty. If you have set a default image on the content type field's setting, then you can use `content.user_picture` which should display either the image that was selected on the entity or the default image from the field's image setting.
> 3 votes

# Answer
I believe it best to use Drupal to set a default image for users. Edit the User Picture field and upload a default image.

If you're in comment.html.twig, "user\_picture" is available just as "node" or "content" is:

```
{{ user_picture }}

```

And the way to the image value is:

```
{{ user_picture['#user'].user_picture.entity.uri.0.value }}

```

That's if you did a full install of Drupal and not a minimal install. In a minimal install you will need to add your own field to the User Account fields. Then you just access your field name:

```
{{ user_picture['#user'].field_machine_name.entity.uri.0.value }}

```

What I've done before in the comment.html.twig file:

```
{% if user_picture['#user'].user_picture.entity.uri.0.value != "" %}
    <a href="/user/{{ user_picture['#user'].uid.0.value }}">
         <img src="{{ file_url(user_picture['#user'].user_picture.entity.uri.0.value) }}" />
    </a>
{% else %}
    <img src="/path/to/image" />
{% endif %}

```

Also you can check for a user id:

```
{% if user_picture['#user'].uid.0.value > 0 %}

```

A good way to set a picture for anonymous users.
> 1 votes

# Answer
It is possible to negate the twig condition for others purposes :

```
{% if not node.field_image.isempty %}
  <p>Field "field_image" is not empty.</p>
{% endif %}

```
> 0 votes

---
Tags: 8
---


# Question
Title: How to check and disable one of the checkboxes in a form?
I found this snippet in the code for a form (`$roles` is an array of roles).

```
$form['config_options']['roles'] = [
  '#type' => 'checkboxes',
  '#options' => $roles,
];
// Check and disable the 'authenticated' role.
$form['config_options']['roles'][RoleInterface::AUTHENTICATED_ID] = [
  '#default_value' => TRUE,
  '#disabled' => TRUE,
];

```

What this does is to check the checkbox for the 'authenticated' role, and then disables it (so it can't be unchecked). This works.

I have a very similar requirement. In a form I have checkboxes for a bunch of fields, where `$fields` is an array of them. The fields are from user profile. I want to check and disable the 'email' field.

Based upon the code snippet above, I think the solution should be something like this:

```
$form['config_fields']['fields'] = [
  '#type' => 'checkboxes',
  '#options' => $fields,
];
// Check and disable the 'email' field.
$form['config_fields']['fields'][ -- What to put here? -- ] = [
  '#default_value' => TRUE,
  '#disabled' => TRUE,
];

```

However, I have no idea what to put in the selector where I've written " `-- What to put here? --`".

Based upon a comment from Clive I've tried to examine `$fields`. This is what the *devel* Default variables-dumper gives me (using short array syntax):

```
$fields = [
  …
  mail => stdClass Object (
    [__CLASS__] => Drupal\Core\StringTranslation\TranslatableMarkup
    [translatedMarkup:protected] =>
    [options:protected] => []
    [stringTranslation:protected] =>
    [string:protected] => Email
    [arguments:protected] => []
  )
  …
]

```

So it is a bit more complex than the example given in Clive's comment (e.g. it is an object, not an array (as implied by Clive).

So far I've tried 'Email'.

```
$form['config_fields']['fields'] = [
  '#type' => 'checkboxes',
  '#options' => $fields,
];
// Check and disable the 'email' field.
$form['config_fields']['fields']['Email'] = [
  '#default_value' => TRUE,
  '#disabled' => TRUE,
];

```

This does not work.

Help will be appreciated.

Also, if I am barking up the wrong tree, and there exists another way to do this, I shall equally appreciate an alternative solution.

(I am using Drupal 9).

# Answer
> 0 votes
OK, it turns out that the key is simply the machine *name* of the field you want to check and disable. This works:

```
$form['config_fields']['fields'] = [
  '#type' => 'checkboxes',
  '#options' => $fields,
];
// Check and disable the 'mail' field.
$form['config_fields']['fields']['mail'] = [
  '#default_value' => TRUE,
  '#disabled' => TRUE,
];

```

---
Tags: forms
---


# Question
Title: hook_menu() items disappeared and no longer work
I'm feel like I'm losing my mind here. I have written a custom module and implemented `hook_menu` to add custom admin pages. Last week this worked perfectly - this week they stopped working then vanished altogether. I can't understand what the problem is and I can't even get simple pages to work now.

This is the code I am using.

### nhs\_session\_judge.module

```
/**
 * Implements hook_menu().
 */
function nhs_session_judge_menu() {
  $items['admin/session-judging'] = array(
    'title' => 'Your judging',
    'page callback' => 'your_judging_page',
    'access arguments' => array('access administration pages'),
    'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

/**
 * Custom page callback
 */
function your_judging_page() {
  $content['raw_markup'] = array(
    '#type' => 'markup',
    '#markup' => '<p>This table shows at-a-glance the session bids you have already scored and those yet to be judged.</p>',
  );

  // …

  return $content;
}

```

If I use a backup of the database and visit the page, it works.

If I make a change, I get this error.

> Warning: call\_user\_func\_array() expects parameter 1 to be a valid callback, function 'your\_judging\_page' not found or invalid function name in menu\_execute\_active\_handler()

If I clear the cache, the menu item disappears. Visiting the page by entering the URL directly in the browser address bar just redirects to /admin.

Does anyone know what's going on here? I can't make any changes/fixes to this because as soon as I do it breaks.

# Answer
Think I figured it out. I had a backup of the `nhs_session_judge.module` file in `sites/all/modules/custom/bak/nhs_session_judge.module` and I guess drupal was reading it instead of the `sites/all/modules/custom/nhs_session_judge/nhs_session_judge.module` I was working on, hence why my changes were ignored then lost.
> 0 votes

---
Tags: 7, navigation
---


# Question
Title: How to download bulma sass file and compile in order to change the primary font?
I'd like to change the primary font in Bulma as per https://stackoverflow.com/questions/64512940/setting-a-new-primary-font-family-with-bulma.

I've used composer to install libraries\_provider

```
 composer require drupal/libraries_provider

```

Libraries provider is enabled

```
dr en -y libraries_provider

```

Looking at the libraries provider documentation and the drulma documentation I should add something to my theme libraries yml file.

At a rough guess as I can't find documentation on how to do this

```
bulma:
  libraries_provider:
  enabled: true
  source: https://asset-packagist.org
  npm_name: 'bulma'

```

Then I run

```
composer require npm-asset/bulma

```

Which does not work

> Could not find a matching version of package npm-asset/bulma.

Then I set the variables in the sass file for the new font, which the stackoverflow question handles.

Finally, recompile the SASS file (what command is required?). Make sure the updated bulma CSS file is included in my theme and it is done.

# Answer
For

```
composer require npm-asset/bulma

```

to work https://asset-packagist.org/ is needed to be configured in your root composer.json Here is a more detailed guide on how to configure it for Drupal so the library end up in the `web/libraries` folder.

http://lightning.acquia.com/blog/round-your-front-end-javascript-libraries-composer

Once you succeed with that. Libraries provider will allow you to set the bulma library as "local" and given that you have the sassphp php extension installed then you can specify bulma variables on the libraries provider interface and that will recompile bulma to use them
> 1 votes

---
Tags: 8
---


# Question
Title: Custom access method for a Page Manager page
I've created a page using Page Manager, at the route `/project/(node}/attendance`.

I need to add a custom access check on it, comparing information about the current user with the node to see if they should have access.

I have added a route subscriber, but when I loop through the route collection, my route does not appear. I have read that this is because pages added through the page manager are they themselves nodes.

Is there a way to add a custom access method to a Page Manager route?

# Answer
The module already allows you to create Condition plugins by extending the **ConditionPluginBase** class.

There is an `evaluate()` method that you can put your logic in.

This plugin will be available then under the Page manager UI under "Page access" menu:
> 1 votes

# Answer
So, what I ended up doing is extending the Page Manager PageAccessCheck service:

```
services:
  custom_route_access.page_access_check:
    class: Drupal\custom_route_access\Entity\PageAccessCheck
    tags:
      - { name: access_check, applies_to: _page_access }

```

And then:

```
<?php

namespace Drupal\custom_route_access\Entity;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityAccessCheck;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\Routing\Route;

/**
 * We're overriding the page access checks so that we can add our own.
 * Mimics the generic entity access but with a custom key to prevent collisions.
 */
class PageAccessCheck extends EntityAccessCheck {

  /**
   * {@inheritdoc}
   */
  public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account) {

    // Backup the original requirements.
    $original_requirements = $route->getRequirements();

    // Replace it with our entity access value and run the parent access check.
    $route->setRequirement('_entity_access', $route->getRequirement('_page_access'));
    if($route->getPath() === '/project/{node}/take_attendance'){
      return self::takeAttendanceAccess($account);
    }
    $access = parent::access($route, $route_match, $account);

    // Restore the original requirements.
    $route->setRequirements($original_requirements);

    return $access;
  }

  /**
   * Check that user is admin or staff OR has an active team leader registration.
   */
  private static function takeAttendanceAccess($account){

    // ... my custom access check code
  }

}

```
> 0 votes

---
Tags: 8, page-controller
---


title: How do I combine terms in Drupal feeds?

text:
# Question
Title: How do I combine terms in Drupal feeds?
For example if I had 2 rows with people in them

```
uid | favourite colour
----------------------
 3  | Blue
 3  | Yellow

```

And I wanted the result to have both Blue and Yellow selected at the end. Is there a combine tamper plugin? I am already doing

```
class MyAlterSubscriber extends AfterParseBase

```

Do I need to lookup existing values here and combine them first?

# Answer
> 0 votes
AfterParseBase does not give access to the full set of data.

Therefore, use the FeedsEvents::AFTER event instead.

I found that if the last item had no taxonomy items selected then all items would be lost. To create a union of taxonomy items:

```
<?php

namespace Drupal\cbi_feed_alter\EventSubscriber;

use Drupal\feeds\Event\FeedsEvents;
use Drupal\feeds\Event\ParseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class IssuerFeedEventSubscriber implements EventSubscriberInterface {

  const JOIN_CHAR = ',';

  /**
  * {@inheritdoc}
  */
  public static function getSubscribedEvents() {
    $events[FeedsEvents::PARSE][] = ['afterParse', FeedsEvents::AFTER];
    return $events;
  }

  public function afterParse(ParseEvent $event) {
    /** @var \Drupal\feeds\FeedInterface */
    $feed = $event->getFeed();
    /** @var \Drupal\feeds\Result\ParserResultInterface */
    $parser_result = $event->getParserResult();

    $feed_type = $feed->getType();
    if ($feed_type->id() != 'issuer') {
      return;
    }

    for ($parser_result->rewind(); $parser_result->valid(); $parser_result->next()) {
      $this->findStates($parser_result->current(), $parser_result);
    }
  }

  protected function findStates($item, $parser_result) {
    $issuer_id = $item->get('issuerid');
    $states = [];
    $parser_current_key = $parser_result->key();
    for ($parser_result->rewind(); $parser_result->valid(); $parser_result->next()) {
      if ($parser_result->current()->get('issuerid') == $issuer_id) {
        $states = array_filter(array_merge($states, explode(self::JOIN_CHAR, $parser_result->current()->get('state'))));

     }
    }

    // Iterate back to the key
    $parser_result->rewind();
    while ($parser_result->valid() && $parser_result->key() != $parser_current_key) {
      $parser_result->next();
    }
    $parser_result->offsetSet($parser_current_key);
    $item->set('state', implode(self::JOIN_CHAR, array_unique($states, SORT_STRING)));
   }

}

```

---
Tags: feeds
---


title: Views Block Language Detection

text:
# Question
Title: Views Block Language Detection
I have a site with two languages (EN/FR). I have a Content Type (Article). I have a Block built with Views that is displayed on the Article Node page. This Views Block has a translation.

When the user switches to FR, all other Blocks and UI components detect and render in this language. Even if the user visits a node that does not have a FR translation, it will render the rest of the site in FR.

However, Views Blocks do not seem to adhere to the selected language. I must be missing something?

When a user changes the language of the site to FR, all translated interfaces should adhere to that, no?

# Answer
> 1 votes
In the view, add a new filter on 'translation language', and then for the filter, check the 'Interface text language selected for page' box, and save the view. This will filter the content of the view to the current language.

---
Tags: views, i18n-l10n
---


# Question
Title: How do I show a checkboxes form element that is selected by default?
How do I show a *checkboxes* form element that is selected by default?

I tried setting `#default_value` as in the following code, but it doesn't work.

```
$form['ios'] = array(
  '#type' => 'checkboxes',
  '#options' => $options,
  '#default_value' => 'checked',
);

```

Is `#default_value` the wrong attribute?

# Answer
`#default_value` for *checkboxes* form elements should be set as in the following code.

```
$options = array();
$options["1"] = "One";
$options["2"] = "Two";
$options["3"] = "Three";
$options["4"] = "Four";

$form['ios'] = array(
  '#type' => 'checkboxes',
  '#options' => $options,
  '#default_value' => array("1", "2", "3")
);

```
> 25 votes

# Answer
You have to give "#default\_value" all $options keys

In your case:

```
$form['ios']['#default_value'] =  array_keys($form['ios']['#options']);

```
> 0 votes

# Answer
If you want to checked all checkboxes values as default, you can use *checked* property in *#attribute*.

In your case:

```
$options = array();
$options["1"] = "One";
$options["2"] = "Two";
$options["3"] = "Three";
$options["4"] = "Four";

$form['ios'] = array(
  '#type' => 'checkboxes',
  '#options' => $options,
  '#attributes' => array('checked' => 'checked'),
);

```

This work for me.
> 0 votes

---
Tags: 7, forms
---


# Question
Title: "Limit allowed HTML tags" filter is deleting Ckeditor table styles
I'm using the "Limit allowed HTML tags" filter in my text format and put this to the allowed tags: `<th style>`

Anyway my table styling `<th style="width: 60%;">` added in Ckeditor is filtered out. What have I missed?

# Answer
> 1 votes
The "Limit allowed HTML tags" filter triggers Drupal's XSS filter, which strips all style attributes. So you cannot use `style` attributes and "Limit allowed HTML tags" at the same time.

There are stalled efforts to eventually address this by modifying how Drupal performs XSS filtering.

# Answer
> 1 votes
`style="width: 60%;"` is an html attribute, not a tag.

> I put this to the allowed tags: `<th style>`

Therefore, you need to remove the `style` part and just put table header tag `<th>` in the allowed tags.

---
Tags: 8, wysiwyg, input-formats
---


# Question
Title: CKeditor stripping allowed style attribute
I've installed Colorbutton to my Drupal 8 site.

I have enabled the button for Full HTML and For Basic HTML

I have allowed the attribute `<span style>` in the Basic HTML allowed attributes area.

I have defined a set of hex value colors.

When I edit a page the button appears and I can change font colors in the editor correctly, however, saving the page strips the attributes leaving only clean `<span>` tags...

what else am I suppose to do?

There is a simmilar question here, however in relation to colorbotton the documentation/README that comes with the module specifically states that we should be allowing `<span style>` in the allowed tags? Is their readme incorrect?

The extension appears to add the color by adding the attribute `style="color:#fff">` How can I allow it to do this successfully?

# Answer
> 1 votes
In case it is of use to someone, it seems colorbutton cannot work if the "limit html tags" filter is active.

You can find a slightly painful workaround here.

It would be nice to have an explicit warning in the documentation, but it seems only Full HTML or the above workaround will let you use it.

# Answer
> 10 votes
Your problem comes from the "Limit allowed HTML tags" option. According to this post (for Drupal 7, but the same logic applies on D8), setting this option triggers XSS filter in order to remove dangerous tags.

As for Drupal 8, it uses the core Filter module and calls `filterXss()` method in `\Drupal\editor\EditorXssFilter\Standard` class. First line of this method is:

```
$dangerous_tags = ['script', 'style', 'link', 'embed', 'object'];

```

Hence, your style tag will always be removed with the "Limit allowed HTML tags" option set.

If you really wish to use inline style, you have to either:

* unset the "Limit allowed HTML tags" option (which I do not recommend depending on the kind of users you give access to "Basic HTML" text format)
* or use "Full HTML" text format

Best solution would be to rely on classes and styling in CSS stylesheets and inline styling should be used sparingly.

Hope this helps.

# Answer
> 1 votes
CKEditor 5 (coming to Drupal 10) supports font color and background color natively. There is a CKEditor 5 issue about adding support for using classes instead of style, which, if implemented, will allow us to define the classes and allow use of font coloring with Basic HTML.

---
Tags: wysiwyg
---


title: How can I migrate a font library?

text:
# Question
Title: How can I migrate a font library?
I have a Drupal 7 multi-site platform which contains a `sites/all/libraries/fonts/<fontname>` directory, where there are several font files.

I am porting one of the Drupal 7 sites to a new Drupal 9 platform, where I have created a Drupal 9 version of the theme. I want to use these fonts on the Drupal 9 site.

Where should I copy these font files? How do I tell the Drupal 9 theme about them?

# Answer
It appears that you don't need to update the theme YAML files (`theme.info.yml`, `theme.libraries.yml`) to tell Drupal about the new font, just copying the font directory across to somewhere inside the D9 theme, and referencing it in the CSS was enough, as suggested in the comments.
> 1 votes

---
Tags: 9
---


# Question
Title: How to reference submitted Salesforce ID with webform mapping?
The Drupal Salesforce Suite and webform documentation state:

> The ID of created/updated records are stored with the submission, and can be used in subsequent record updates in the same submission

Source: https://www.drupal.org/project/salesforce\_webforms

Sadly I just don’t know how to reference it in the mapping. I first log a Case for the submission and in my second mapping I am trying things like:

```
[submissions:value:case]
[submissions:value:case:Id]

```

But it’s just trial and error, mostly error - got to be documented somewhere?

# Answer
> 1 votes
Turns out I was using the incorrect case, it is simply:

```
[submissions:salesforce:MAPPINGNAME]

```

where MAPPINGNAME is case sensitive. Everything you need is here:

https://www.drupal.org/node/2298943

---
Tags: webforms
---


# Question
Title: How to add a boolen attribute to a form?
I am trying to add the boolean attribute "novalidate" to all my forms.

I have tried numerous approaches in my theme\_preprocess\_form function but no luck. I see in some preprocess functions, $variables\['attribute'\] is an object and has methods like addClass() and setAttribute(). But in \_preprocess\_form it is an array. Plus setAttribute doesnt sound like it will do boolean attributes anyway.

I tried to simply override the twig template for a form and do this:

```
<form{{ attributes }} novalidate>
  {{ children }}
</form>

```

but even that outputs:

```
<form novalidate="">

```

# Answer
> 4 votes
You may be attempting to solve a non-issue here. `novalidate=""` is fine for the HTML spec - boolean attributes can have a value as long as it's an empty string or the same (case-insensitive) string as the attribute name. So `novalidate="novalidate"` would also be fine.

If you follow those rules, the attribute's existence is taken to mean `true`, regardless of the value.

See https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#boolean\_attributes for more info.

---
Tags: theming, forms, 9
---


title: robots.txt file per environment

text:
# Question
Title: robots.txt file per environment
We are using Drupal 8.9 and we have an EC2 stage site and our main site, which use the same code base.

Is it possible to have a different robots.txt file for each site (environment)?

We don't want the stage site to appears on search results.

# Answer
There's the RobotsTxt module that in the end after you removed the robots.txt file takes config to provide the contents of a /robots.txt page.

Together with the Configuration Split module you can then have it play different contents per environment.

---

To exclude Drupal's default robots.txt file from being recreated during scaffolding, adjust the `file-mapping` in composer.json like that:

```
"drupal-scaffold": {
    "locations": {
        "web-root": "web/"
    },
    "file-mapping": {
        "[web-root]/robots.txt": false
    }
},

```
> 4 votes

# Answer
I patch the root `.htaccess` file to redirect to a deny-robots.txt file (which will appear as robots.txt in the reponse) based on the domain, but you could easily use the same directives in your apache configuration:

```
RewriteEngine on

# Deny robots everywhere except the production site
RewriteCond %{HTTP_HOST} !^www\.mysite\.com\.au$
RewriteRule ^robots.txt(\??.*)$ deny-robots.txt$1

```

Contents of deny-robots.txt:

```
User-agent: *
Disallow: *

```
> 1 votes

---
Tags: 8
---


# Question
Title: How to get low resolution image urls from json:api?
The json:api put provides a link to file--file node types, but the url is to the original image file.

How can I get a lower resolution image file via json:api to avoid users from downloading a MB+ image file?

# Answer
Core does not support this (yet... hopefully).

Assuming you have already set up image styles, you can use the Consumer Image Styles module, which is the approach taken by Contenta CMS.

For reference, there's also a blog post on the background to the development of Consumer Image Styles.
> 1 votes

---
Tags: 8
---


title: Including modules in Git repository

text:
# Question
Title: Including modules in Git repository
Non core third party modules are maintained in *modules* directory in the Drupal root directory. Should this directory be added to the .gitignore file?

If a module is upgraded in a Staging system then why would the module be managed in a site specific Git repository when no changes are intended and the module is maintained by a third party? Surely if the module is required in production then it is a case of simply installing the module once pulling is finished?

If composer is used, would it be sufficient to run composer update once code is pulled (including composer.json) to have any missing modules installed? I am assuming that this would ensure staging and production modules are kept synchronized without maintaining code in Git.

# Answer
This is totally up to you and how you want to manage your web server.

For example, among dedicated Drupal hosts, Platform.sh and Pantheon have you commit `composer.json` and `composer.lock`, and then they automatically build your site based on that. This has the benefit of keeping your git repo small.

But, if you have a simple site on shared hosting, it is sometimes easier to commit all the modules so that you can do `git checkout` and be done without worrying about build failures. Of course, this makes the repository much bigger.

In the end, I don't think there is a **Drupal** best practice about this because it is a question of build tools. However, **composer** states that their best practice is to not commit dependencies.
> 0 votes

---
Tags: 9, composer, version-control
---


# Question
Title: Error when instantiating custom field in custom module
I apologize if the answer to this is obvious, but I am newly-embarked on porting a number of complex custom Drupal 7 modules to Drupal 9. I am using Drupal version 9.3.6, PHP version 7.4.28, mysql, apache2. I have created a custom field as follows, which on install goes without errors and appears in the field list report:

```
langcode: en
status: true
dependencies:
  module:
    - user
  enforced:
    module:
      - test_module
id: user.field_test
field_name: field_test
entity_type: user
type: string_long
settings:
  case_sensitive: false
module: core
locked: false
cardinality: 1
translatable: true
indexes: {  }
persist_with_no_fields: false
custom_storage: false

```

But when I try to instantiate it, either with field.field.user.user.field\_test.yml or manually through the UI, I get the following error stack:

```
 [warning] A non-numeric value encountered TypedConfigManager.php:189
 [error]  Error: Unsupported operand types in Drupal\Core\Config\TypedConfigManager->getDefinitionWithReplacements() (line 189 of /var/www/test_site/web/core/lib/Drupal/Core/Config/TypedConfigManager.php) #0 /var/www/test_site/web/core/lib/Drupal/Core/Config/TypedConfigManager.php(105): Drupal\Core\Config\TypedConfigManager->getDefinitionWithReplacements()

```

(Sorry, I had to delete the remainder of the stack dump to avoid getting flagged as spam!)

This is the part of TypedConfigManager as follows:

```
    // Add type and default definition class.
    $definition += [
      'definition_class' => '\Drupal\Core\TypedData\DataDefinition', // Here is line 189
      'type' => $type,
      'unwrap_for_canonical_representation' => TRUE,
    ];
    return $definition;

```

I am at a loss here. If I create the field storage through the admin interface and instantiate also through the admin interface, everything works fine. I export those definitions through the single export interface, and then I get the failure.

Thank you in advance for any insight!

Update: @Jaypan, here is the code for the field.field:

```
langcode: en
status: true
dependencies:
  config:
    - field.storage.user.field_test
  module:
    - user
  enforced:
    module:
      - test_module
id: user.user.field_test
field_name: field_test
entity_type: user
bundle: user
label: 'Test field'
description: ''
required: false
translatable: false
default_value: {  }
default_value_callback: ''
settings: {  }
field_type: string_long

```

# Answer
I have figured out where the problem is. The fact that instantiating the fields (both manually and programmatically) triggered the error has nothing to do with it, and I still do not understand exactly why, but here is what I learned by deleting files from the module one-by-one: a view that I had created manually and exported for my module apparently caused some issue in the configuration system. When I deleted the yml file for the view from config/schema, everything enabled fine. Go figure.
> 0 votes

---
Tags: 9
---


# Question
Title: Enable language selector for Paragraphs Library
I am using paragraphs on a multilingual Drupal 9 page. Everything is working fine, I can translate basic pages with paragraphs to get a multilingual node.

I have now enabled the Paragraphs Library sub module, but I can't enable the language support for that.

* When creating a new paragraph library item at */admin/content/paragraphs/add/default* there is no language selector. Library items are always in the page's default language: English.
* In the "Paragraphs library item settings - Manage form display" the default field "Language" with the widget "Language select" is present. (*/admin/config/content/paragraphs\_library\_item/form-display*)
* In "Configuration - Regional and language" at */admin/config/regional/content-language* there is a check box for "Paragraphs library item". If I tick this checkbox and save the page, it reloads and the tick is gone. I'm not able to enable "Paragraphs library item" in "Custom language settings" here. I do not get any error in the "Recent log messages" either.
* Below on this same page (*/admin/config/regional/content-language*) there is the default paragraph type entry "From library". I have enabled this like I did with my other paragraphs.

What am I missing to enable language support for paragraphs library items? Thank you for you help and suggestions in advance!

# Answer
I had the same issue but I solved it the following way:

* Make sure to tick "Paragraphs library item" in "Custom language settings" section
* After that, scroll down (without saving) to the section "Paragraphs library item" and tick "Paragraphs library item" + fields to be translated.
* Save your settings
> 1 votes

---
Tags: i18n-l10n, paragraphs, 9
---


# Question
Title: Disable content creation outside group context
I'm using the group module.

I have a content type for which nodes should only ever exist as members of groups.

Is there a sensible way to disable creation from `/node/add/{content_type}` so that nodes can only be created from `group/{group}/content/create/group_node:{content_type}`?

# Answer
> 1 votes
This is actually pretty simple: The regular permissions page, `/admin/people/permissions`, controls access to `/node/add/{content_type}`. The group-level permissions, `admin/group/types/{group_type}/permissions`, controls access to `group/{group}/content/create/group_node:{content_type}`. If you have the appropriate checkbox(es) unchecked on the former, and checked on the latter, you'll get what you're after.

---
Tags: 9, group
---


# Question
Title: SMTP module cannot connect to smtp.gmail.com
The SMTP module stopped working about a week ago. It is no longer able to connect to smtp.gmail.com. I have tried commonly recommended remedies:

I am still not able to send emails. This seems to have happened without any changes to the site. The debug output:

```
SMTP.module is active.
The configuration options have been saved.
SMTP -> get_lines(): $data was ""
SMTP -> get_lines(): $str is "220 smtp.gmail.com ESMTP f19-20020ac859d3000000b002de4d014733sm11933677qtf.13 - gsmtp "
SMTP -> get_lines(): $data was "220 smtp.gmail.com ESMTP f19-20020ac859d3000000b002de4d014733sm11933677qtf.13 - gsmtp "
SMTP -> FROM SERVER: 220 smtp.gmail.com ESMTP f19-20020ac859d3000000b002de4d014733sm11933677qtf.13 - gsmtp
SMTP -> get_lines(): $data was ""
SMTP -> get_lines(): $str is "250-smtp.gmail.com at your service, [66.228.44.53] "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] "
SMTP -> get_lines(): $str is "250-SIZE 35882577 "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 "
SMTP -> get_lines(): $str is "250-8BITMIME "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME "
SMTP -> get_lines(): $str is "250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH "
SMTP -> get_lines(): $str is "250-ENHANCEDSTATUSCODES "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH 250-ENHANCEDSTATUSCODES "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH 250-ENHANCEDSTATUSCODES "
SMTP -> get_lines(): $str is "250-PIPELINING "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH 250-ENHANCEDSTATUSCODES 250-PIPELINING "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH 250-ENHANCEDSTATUSCODES 250-PIPELINING "
SMTP -> get_lines(): $str is "250-CHUNKING "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH 250-ENHANCEDSTATUSCODES 250-PIPELINING 250-CHUNKING "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH 250-ENHANCEDSTATUSCODES 250-PIPELINING 250-CHUNKING "
SMTP -> get_lines(): $str is "250 SMTPUTF8 "
SMTP -> get_lines(): $data was "250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH 250-ENHANCEDSTATUSCODES 250-PIPELINING 250-CHUNKING 250 SMTPUTF8 "
SMTP -> FROM SERVER: 250-smtp.gmail.com at your service, [66.228.44.53] 250-SIZE 35882577 250-8BITMIME 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH 250-ENHANCEDSTATUSCODES 250-PIPELINING 250-CHUNKING 250 SMTPUTF8
SMTP -> get_lines(): $data was ""
SMTP -> get_lines(): $str is "334 VXNlcm5hbWU6 "
SMTP -> get_lines(): $data was "334 VXNlcm5hbWU6 "
SMTP -> get_lines(): $data was ""
SMTP -> get_lines(): $str is "334 UGFzc3dvcmQ6 "
SMTP -> get_lines(): $data was "334 UGFzc3dvcmQ6 "
SMTP -> get_lines(): $data was ""
SMTP -> get_lines(): $str is "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs "
SMTP -> get_lines(): $str is "534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs 534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs 534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX "
SMTP -> get_lines(): $str is "534-5.7.14 kFJOLwtOF7Agw6KdzAL_P3IQZlAY-bSuSgKpM_aD8Rzd7AAIdpfRWkwd9bXW-wWw> "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs 534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX 534-5.7.14 kFJOLwtOF7Agw6KdzAL_P3IQZlAY-bSuSgKpM_aD8Rzd7AAIdpfRWkwd9bXW-wWw> "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs 534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX 534-5.7.14 kFJOLwtOF7Agw6KdzAL_P3IQZlAY-bSuSgKpM_aD8Rzd7AAIdpfRWkwd9bXW-wWw> "
SMTP -> get_lines(): $str is "534-5.7.14 Please log in via your web browser and then try again. "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs 534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX 534-5.7.14 kFJOLwtOF7Agw6KdzAL_P3IQZlAY-bSuSgKpM_aD8Rzd7AAIdpfRWkwd9bXW-wWw> 534-5.7.14 Please log in via your web browser and then try again. "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs 534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX 534-5.7.14 kFJOLwtOF7Agw6KdzAL_P3IQZlAY-bSuSgKpM_aD8Rzd7AAIdpfRWkwd9bXW-wWw> 534-5.7.14 Please log in via your web browser and then try again. "
SMTP -> get_lines(): $str is "534-5.7.14 Learn more at "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs 534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX 534-5.7.14 kFJOLwtOF7Agw6KdzAL_P3IQZlAY-bSuSgKpM_aD8Rzd7AAIdpfRWkwd9bXW-wWw> 534-5.7.14 Please log in via your web browser and then try again. 534-5.7.14 Learn more at "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs 534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX 534-5.7.14 kFJOLwtOF7Agw6KdzAL_P3IQZlAY-bSuSgKpM_aD8Rzd7AAIdpfRWkwd9bXW-wWw> 534-5.7.14 Please log in via your web browser and then try again. 534-5.7.14 Learn more at "
SMTP -> get_lines(): $str is "534 5.7.14 https://support.google.com/mail/answer/78754 f19-20020ac859d3000000b002de4d014733sm11933677qtf.13 - gsmtp "
SMTP -> get_lines(): $data was "534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs 534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX 534-5.7.14 kFJOLwtOF7Agw6KdzAL_P3IQZlAY-bSuSgKpM_aD8Rzd7AAIdpfRWkwd9bXW-wWw> 534-5.7.14 Please log in via your web browser and then try again. 534-5.7.14 Learn more at 534 5.7.14 https://support.google.com/mail/answer/78754 f19-20020ac859d3000000b002de4d014733sm11933677qtf.13 - gsmtp "
SMTP -> ERROR: Password not accepted from server: 534-5.7.14 <https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=AKgnsbs 534-5.7.14 ayHmWfTW3uH_Y0l9QBdB8thX_D2gyq0cU5Ltn0zJWruuXlc4Bvxyeag-Md22UG22XWJJX 534-5.7.14 kFJOLwtOF7Agw6KdzAL_P3IQZlAY-bSuSgKpM_aD8Rzd7AAIdpfRWkwd9bXW-wWw> 534-5.7.14 Please log in via your web browser and then try again. 534-5.7.14 Learn more at 534 5.7.14 https://support.google.com/mail/answer/78754 f19-20020ac859d3000000b002de4d014733sm11933677qtf.13 - gsmtp
SMTP -> get_lines(): $data was ""
SMTP -> get_lines(): $str is "221 2.0.0 closing connection f19-20020ac859d3000000b002de4d014733sm11933677qtf.13 - gsmtp "
SMTP -> get_lines(): $data was "221 2.0.0 closing connection f19-20020ac859d3000000b002de4d014733sm11933677qtf.13 - gsmtp "
SMTP -> FROM SERVER: @byemsg
SMTP -> ERROR: Failed to connect to server: php_network_getaddresses: getaddrinfo failed: Name or service not known (0)

```

# Answer
> 1 votes
I needed to use an app password. This is done at https://myaccount.google.com/security

Before creating an app password, you have to turn on 2-factor authentication for the account.

---
Tags: 7
---


# Question
Title: What security configuration should I use in order to allow deployment?
During the deployment of a container in the AWS Fargate ECS cluster, although the Docker container remains in Running state, when I open the public IP of the service where the site should load, I get this message.

> The provided host name is not valid for this server.

This is an intranet site that runs on Drupal 8.

What security configuration Drupal should have in order to allow deployment, taking into account that the containers that are deployed are ephemeral, which means that their IP can change at any time?

# Answer
This exception is because the `trusted_host_patterns` as configured in settings.php does not match the host header in HTTP requests to the site. So you should assign a DNS hostname to the address of the load-balanced IP address provide by Fargate (if this is intranet, it will be the IP address of the elastic network interface, which you attach with a NAT gateway), browse the site with that hostname, and configure `trusted_host_patterns` with that hostname.

More information on Fargate networking is in the official documentation.
> 1 votes

---
Tags: 8
---


# Question
Title: How do I override a single JavaScript file used in a library?
I am trying to override the Search API autocomplete JavaScript file. In mytheme.libraries, I added the following lines.

```
mytheme_autocomplete:
  js:
    'assets/js/autocomplete.js': { }

```

In mytheme.info, I added the following lines.

```
libraries-override:
  search_api_autocomplete/search_api_autocomplete:
    js:
      component:
        js/search_api_autocomplete.js: mytheme_autocomplete

```

When I visit the site, js/search\_api\_autocomplete.js is still loaded, while assets/js/autocomplete.js isn't loaded.

How do I override a single JavaScript file used in a library?

# Answer
> 8 votes
If you're overriding a single js file, you need to specify a file, not a library:

```
libraries-override:
  search_api_autocomplete/search_api_autocomplete:
    js:
      js/search_api_autocomplete.js: assets/js/autocomplete.js

```

However, specify your theme's library if you intend to override an entire library:

```
libraries-override:
  search_api_autocomplete/search_api_autocomplete: mytheme/mytheme_autocomplete

```

See the Overriding and extending libraries documentation on d.o

---
Tags: javascript, 9
---