title: Node ID caching on hook_form_alter()

text:
# Question
Title: Node ID caching on hook_form_alter()
I have a webform with an email field. I am embedding the webform on each node, with a field on the node for the email address.

I implemented `hook_form_alter()` in my .theme file that loads the node using `$node = \Drupal::routeMatch()->getParameter('node');`.

I can then load the node and get the proper email address and set it in the webform. The problem is that the node is cached for anonymous users. It doesn't matter what node I'm on, `$node->id()` always returns the same, cached node ID.

I have tried either these lines, but the node ID is still the same.

```
\Drupal::service('page_cache_kill_switch')->trigger();

```

```
$vars['#cache']['max-age'] = 0;

```

I understand I have to clear cache tags and cache context, but none of the examples shows exactly how to do this in `hook_form_alter()`.

How can I properly clear the cache?

# Answer
> 5 votes
When you get route parameters you need this cache context:

```
$form['#cache']['contexts'][] = 'route';

```

You might also want to add the node cache data so that the form gets invalidated when the node is saved with a different field value:

```
$renderer = \Drupal::service('renderer');
$renderer->addCacheableDependency($form, $node);

```

The cache context is applied to the form and all page elements where the form is placed in. So this works no matter where you embed the form.

If the form is embedded within a node, getting the node from the route match is probably not the best idea. You should use the node or node ID as parameter when calling the form. Then you can try the answer from @sonfd because you don't need separate cache keys for the node and webform.

# Answer
> 3 votes
The problem is that the webform gets cached with the $node data from the first node visited, but you need the webform to be unique per node.

You can unset the cache keys for your webform - this will prevent the webform from being cached on its own, but will still allow the webform to be cached with its parent (the node), with all of the webform's cache metadata bubbling up.

In your hook\_form\_FORM\_ID\_alter() (the one you're using to set the email address), you can unset the cache keys like:

```
if (isset($form['#cache']['keys']) {
  unset($form['#cache']['keys']);
}

```

---
Tags: nodes, webforms, caching
---


# Question
Title: Any idea why exposed sort filters won't show up when configured correctly in D9.3 (works on simpletest.me instance)?
D9.3.12

I have a block view with sort criteria configured, but no exposed sort criteria show up in the preview or on the site when placed - "Exposed form in block: No" and "Use Ajax: Yes". If I duplicate it to be a page or embed (exact same settings) the sort criteria show up this persisted across multiple views.

I uninstalled BEF in case that was interfering with things, but there was no change.

Views related contrib installed:

```
Better Exposed Filters 8.x-5.0
Chaos Tool Suite (ctools) 8.x-3.7
Views Aggregator Plus 2.0.1
Views Bulk Operations (VBO) 4.1.2
Views Field View 8.x-1.0-beta3
Views fieldsets 8.x-3.4
Views Simple Math Field 3.0.0

```

Here's some config that should be pretty universal:

```
uuid: 1ab41219-fdc3-4f44-89f6-e5c057633456
langcode: en
status: true
dependencies:
  config:
    - node.type.article
    - node.type.batch
    - node.type.page
    - node.type.pcas
  module:
    - node
    - user
id: exposed_sort_test
label: 'Exposed Sort Test'
module: views
description: ''
tag: ''
base_table: node_field_data
base_field: nid
display:
  default:
    id: default
    display_title: Default
    display_plugin: default
    position: 0
    display_options:
      title: 'Exposed Sort Test'
      fields:
        title:
          id: title
          table: node_field_data
          field: title
          relationship: none
          group_type: group
          admin_label: ''
          entity_type: node
          entity_field: title
          plugin_id: field
          label: ''
          exclude: false
          alter:
            alter_text: false
            make_link: false
            absolute: false
            word_boundary: false
            ellipsis: false
            strip_tags: false
            trim: false
            html: false
          element_type: ''
          element_class: ''
          element_label_type: ''
          element_label_class: ''
          element_label_colon: true
          element_wrapper_type: ''
          element_wrapper_class: ''
          element_default_classes: true
          empty: ''
          hide_empty: false
          empty_zero: false
          hide_alter_empty: true
          click_sort_column: value
          type: string
          settings:
            link_to_entity: true
          group_column: value
          group_columns: {  }
          group_rows: true
          delta_limit: 0
          delta_offset: 0
          delta_reversed: false
          delta_first_last: false
          multi_type: separator
          separator: ', '
          field_api_classes: false
      pager:
        type: some
        options:
          offset: 0
          items_per_page: 10
      exposed_form:
        type: basic
        options:
          submit_button: Apply
          reset_button: false
          reset_button_label: Reset
          exposed_sorts_label: 'Sort by'
          expose_sort_order: true
          sort_asc_label: Asc
          sort_desc_label: Desc
      access:
        type: perm
        options:
          perm: 'access content'
      cache:
        type: tag
        options: {  }
      empty: {  }
      sorts:
        created:
          id: created
          table: node_field_data
          field: created
          relationship: none
          group_type: group
          admin_label: ''
          entity_type: node
          entity_field: created
          plugin_id: date
          order: DESC
          expose:
            label: 'Authored on'
            field_identifier: created
          exposed: true
          granularity: second
      arguments: {  }
      filters:
        status:
          id: status
          table: node_field_data
          field: status
          entity_type: node
          entity_field: status
          plugin_id: boolean
          value: '1'
          group: 1
          expose:
            operator: ''
            operator_limit_selection: false
            operator_list: {  }
        type:
          id: type
          table: node_field_data
          field: type
          relationship: none
          group_type: group
          admin_label: ''
          entity_type: node
          entity_field: type
          plugin_id: bundle
          operator: in
          value:
            all: all
            article: article
            page: page
            batch: batch
            pcas: pcas
          group: 1
          exposed: false
          expose:
            operator_id: ''
            label: ''
            description: ''
            use_operator: false
            operator: ''
            operator_limit_selection: false
            operator_list: {  }
            identifier: ''
            required: false
            remember: false
            multiple: false
            remember_roles:
              authenticated: authenticated
            reduce: false
          is_grouped: false
          group_info:
            label: ''
            description: ''
            identifier: ''
            optional: true
            widget: select
            multiple: false
            remember: false
            default_group: All
            default_group_multiple: {  }
            group_items: {  }
      style:
        type: default
      row:
        type: fields
      query:
        type: views_query
        options:
          query_comment: ''
          disable_sql_rewrite: false
          distinct: false
          replica: false
          query_tags: {  }
      relationships: {  }
      use_ajax: true
      header: {  }
      footer: {  }
      display_extenders: {  }
    cache_metadata:
      max-age: -1
      contexts:
        - 'languages:language_content'
        - 'languages:language_interface'
        - 'url.query_args:sort_by'
        - 'url.query_args:sort_order'
        - 'user.node_grants:view'
        - user.permissions
      tags: {  }
  block_1:
    id: block_1
    display_title: Block
    display_plugin: block
    position: 1
    display_options:
      display_extenders: {  }
    cache_metadata:
      max-age: -1
      contexts:
        - 'languages:language_content'
        - 'languages:language_interface'
        - 'url.query_args:sort_by'
        - 'url.query_args:sort_order'
        - 'user.node_grants:view'
        - user.permissions
      tags: {  }
  page_1:
    id: page_1
    display_title: Page
    display_plugin: page
    position: 2
    display_options:
      display_extenders: {  }
      path: sortme
    cache_metadata:
      max-age: -1
      contexts:
        - 'languages:language_content'
        - 'languages:language_interface'
        - 'url.query_args:sort_by'
        - 'url.query_args:sort_order'
        - 'user.node_grants:view'
        - user.permissions
      tags: {  }

```

And views previews, showing the lack of exposed filters on the block:

with them appearing on the page view:

and rendered on site (in case it was a preview issue):

# Answer
> 0 votes
It was Chaos Views Tools - I backed up my db, then killed all my views contrib - sorts were exposed! Went back one by one and ctools is when it stopped working. Restored again and tried to reasonably uninstall as much as I can without disabling ctools to see if it was a conflict between two modules and that seems pretty unlikely.

update: this is repeatable on simplytest.me

---
Tags: views, blocks
---


# Question
Title: fetchAll Database query returns an error
I'm building a REST Resource in drupal 8 php that returns the result of a query to the database. However using the `fetchAssoc()` only returns one result. So I figured that `fetchAll()` returns all results, but it throws an error when I do so. This is the code

```
$result = $database
      ->select('node__field_recipe_category', 'recipe_cat')
      ->fields('recipe_cat', ['entity_id','bundle'])
      ->condition('entity_id', [3,8], 'BETWEEN')
      ->execute()
      ->fetchAll();
     // Configure caching settings.
    $build = [
      '#cache' => [
        'max-age' => 0,
      ],
    ];

    // Return results.
    return (new ResourceResponse($result, 200))->addCacheableDependency($build);

```

This is the error

```
The website encountered an unexpected error. Please try again later.</br></br><em class="placeholder">Symfony\Component\Serializer\Exception\NotNormalizableValueException</em>: Could not normalize object of type "stdClass", no supporting normalizer found. in <em class="placeholder">Symfony\Component\Serializer\Serializer->normalize()</em> (line <em class="placeholder">164</em> of <em class="placeholder">vendor/symfony/serializer/Serializer.php</em>). <pre class="backtrace">Symfony\Component\Serializer\Serializer->normalize(Array, 'json', Array) (Line: 116)
Symfony\Component\Serializer\Serializer->serialize(Array, 'json', Array) (Line: 176)
Drupal\rest\EventSubscriber\ResourceResponseSubscriber->Drupal\rest\EventSubscriber\{closure}() (Line: 573)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 177)
Drupal\rest\EventSubscriber\ResourceResponseSubscriber->renderResponseBody(Object, Object, Object, 'json') (Line: 76)
Drupal\rest\EventSubscriber\ResourceResponseSubscriber->onResponse(Object, 'kernel.response', Object)
call_user_func(Array, Object, 'kernel.response', Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.response', Object) (Line: 191)
Symfony\Component\HttpKernel\HttpKernel->filterResponse(Object, Object, 1) (Line: 173)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 708)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
</pre>

```

Any ideas?

# Answer
fetchAssoc worked for you because of the result is an associative array.

fetchAll did not work because the result is an array of stdClass objects and JSON normalizer did not know how to return the data.

I think you will need fetchAllKeyed(0,0), but better play around a bit.

reference: https://www.drupal.org/docs/8/api/database-api/result-sets
> 0 votes

# Answer
`$result->fetchAll()` Retrieves all records into an indexed array of stdClass objects. To have it return all results as an associative array pass in a fetch mode constant:

`$result->fetchAll(\PDO::FETCH_ASSOC);`

`PDO::FETCH_ASSOC`: Returns an array indexed by column name as returned in your result set.

References: https://www.drupal.org/docs/8/api/database-api/result-sets https://www.php.net/manual/en/pdostatement.fetch.php
> 0 votes

---
Tags: database, 8
---


# Question
Title: 502 Bad Gateway on editing or creating only for one content type
Drupal 9 project. I can create and edit all content types but one. I get a 502 Bad Gateway from Nginx. Theese are the logs:

```
2022-05-05 10:39:11 Error   ***.**.***.***  503 GET /node/6095/edit?destination=/admin/content HTTP/1.0 https://dev.mywebsite.com/admin/content Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36 20.8 K  Acceso SSL/TLS a Apache
2022-05-05 10:39:14 Error   ***.**.***.***      AH01068: Got bogus version 100, referer: https://dev.mywebsite.com/admin/content                Error de Apache
2022-05-05 10:39:14 Error   ***.**.***.***      (22)Invalid argument: AH01075: Error dispatching request to :, referer: https://dev.mywebsite.com/admin/content             Error de Apache
2022-05-05 10:39:14 Error   ***.**.***.***      11051#0: *1230277 upstream sent too big header while reading response header from upstream

```

# Answer
> 0 votes
This appears to be a well-understood, standard NGinx as proxy occurrence.

---
Tags: nodes
---


# Question
Title: Which cache should I invalidate in a block plugin that builds render arrays for one or more views?
The real issue is that the plugin will sometimes be returning render arrays that are discrete block displays from the same view, possibly also with different arguments. What I'm discovering is that in these cases, the first render array is cached so that the subsequent displays are the same as the initial one. I'm building the render arrays with `buildRenderable($display_id, $args, FALSE)`, which will apparently disable tag and keys caching. But, I'm unclear how to manually provide a custom cache context without a varying request.

# Answer
In the end, I could not for all these suggestions, get the first array not the cache. This could still be due to a deficiency in my process, but I finally just used two discrete views, rather than trying to get the arrays to vary on the display id for a single view.
> 0 votes

# Answer
> But, I'm unclear how to manually provide a custom cache context without a varying request.

There are three strategies:

1. Add the custom cache context to the render array, then the cache context bubbles up to the block and page adding variations on each level upstream.
2. Add a lazy-builder and set the property `#create_placeholder`. Then the custom cache context doesn't bubble up anymore. Instead the cached block and page includes the placeholder which gets replaced by the lazily built content later when the cached page is delivered.
3. Add a cache max-age of 0. Blocks are already built in a lazy builder and are placeholdered if the content meets the auto-placeholder condition. This results in a block never cached and always placeholdered.

Use the first option for a cache context not having too many variations. The second option is a bit more effort to implement, since Drupal 8.8 you need an extra class implementing TrustedCallbackInterface or RenderCallbackInterface, but is more flexible to define static and dynamic content, even within the same block. Easier is the third option, use this if the block content is so volatile that caching is not worth the effort.
> 1 votes

---
Tags: views, blocks, caching
---


# Question
Title: Can Drush display translated messages to users?
I'm working on a module which extended DrushCommands to create custom Drush commands. The maintainer wants those custom commands to display translatable custom messages (warnings, erros) upon usage.

(How) Can It be achieved?

# Answer
> 0 votes
After some research i was able to achieve this using Drush's logger method together with t() method.

```
$this->logger()->error($this->t('message with @arg', ['@arg' => $arg]));

```

Also defined a const ERRORCODE = 0 and returned self::ERRORCODE; to stop logger from sending the complete stack trace on the screen and guarantee that the correct error code is being returned when an error is thrown.

I thank you all for your help and i hope this can be useful for someone in the future :D

# Answer
> -1 votes
In the past there was the system that `dt()` would simply print translated strings that happened to have a translation in Drupal, if you've set a `default_language` in a drushrc.php file.

Modern Drush now does the same simply following your site's default language. But there's no way of overriding this from drush.yml anymore. Although this shouldn't be too difficult to implement.

Quoting Drush's core maintainer Moshe Weitzman I asked about that on drupal.slack.com in the #drush channel:

> There are no plans to add translation to drush output. Symfony Console apps have a standard but you have to separate your strings from your code and thats poor DX IMO.

I guess the only possible road to take now would be to create an issue to re-implement the possibility to override the `language_default` from drush.yml and provide that in a nice merge request.

---

Still you'd need to find a way to get the Drush core strings into the database somehow. Maybe from a nice new contrib module that parses all `dt()` strings and adds them to the database, so that you'd find them later on the interface translation page.

---
Tags: drush
---


# Question
Title: How can I access row field values in the parent views template?
In *views-view-fields--myview.html.twig* I can print a views fully formatted/rewritten field with a variable like: `{{ fields.field_my_view_field.content }}`.

I am wondering if there is some way to print fields in the same fashion in the parent view template: *views-view--myview.html.twig*. This would require having access to these variables with the sub items (row) of the `{{ rows }}` variable.

Is this possible? And if so, what is the correct syntax to access?

# Answer
You say that outputting the variables the template is supposed to be outputting is very powerful. Interesting, I would say this is the (only) correct way to use this template. In special cases it might be necessary to access field raw values, for example to add CSS classes to divs you put into the template, wrapping HTML markup around the content variables. The real purpose of this template.

======================================

If you want to control the rendering from the main View level then use a custom style plugin. Then you don't need to use the mentioned Views field templates. You can build a structure entirely from scratch rendering the fields as you want.

See Views style plugins.
> 0 votes

---
Tags: views, theming
---


# Question
Title: Azure web services does not remove index.php from URL
I have a PHP-based (drupal) website running with Azure web services. It uses NGINX, and the urls are broken. The homepage is absolutely fine, but once i go to the login link (/user/login), it gives a 404. I did figure out that if you put index.php before url (/index.php/user/login), it does work. This is however not ideal. Does anybody know how to fix this?

# Answer
Start with the Drupal configuration for NGINX. NGINX’s default configuration requires modifications to run Drupal.
> 3 votes

---
Tags: deployment
---


# Question
Title: How exactly does drush determine PROJECTROOT and WEBROOT for a project?
In the Drush Configuration section of the official documentation it is said:

> drush.yml files are discovered as below, in order of precedence:
>
> 1. Drupal site folder (e.g. sites/{example.com}/drush.yml).
> 2. sites/all/drush, WEBROOT/drush, or PROJECTROOT/drush.
> 3. ...

There you can see "WEBROOT" and "PROJECTROOT", but there's no explanation on what they are. In the Drush code there's no mention either apart from the configuration itself:

```
$ grep PROJECTROOT * -r
drush/docs/using-drush-configuration.md:2.  `sites/all/drush`, `WEBROOT/drush`, or `PROJECTROOT/drush`.

$ grep WEBROOT * -r
drush/docs/using-drush-configuration.md:2.  `sites/all/drush`, `WEBROOT/drush`, or `PROJECTROOT/drush`.

```

How Drush determines the values of PROJECTROOT and WEBROOT?

The questions is what those names means, but how Drush decide what they are. If they are used to search for different configuration files it means that Drush resolved those names to actual folders or paths in the current system. How Drush resolves them?

My guess is that Drush takes the root folder of the site (defined ion the Drush alias. If that folder is a Drupal root then WEBROOT and PROJECTROOT are the same, the defined root folder. If the configured root folder has a `composer.json` and a `web` folder then PROJECTROOT is the confiugred root path, and the `web` folder is the WEBROOT... but it is just a guess.

# Answer
Drush uses webflow/drupal-finder to determine these directories. The logic is in the DrupalFinder::findAndValidateRoots()

WEBROOT is the Drupal root folder and PROJECTROOT is the folder where the composer.json file is placed.

DrupalFinder is used in several places, but the interesting part is the Preflight::setSelectedSite function.

There Drush locates the "Drupal Root" and the "Composer Root". The "Drupal Root" is... well, the Drupal Root folder and what the Drush documentation calls WEBROOT. And the "Composer Root" is the folder where composer.json file is located and it is what the documentation calls PROJECTROOT.
> 3 votes

# Answer
When you download Drupal using Composer, you get directory (folder) with some files. This is the project root, as it is the top-level of the entire project.

However, when viewing a Drupal site through a browser, you are not viewing the project root, rather, you are viewing one directory below it; by default, this folder is called `/web` (though it can be changed in composer.json). The web folder is the webroot, as it is the top-level folder that is viewed when accessing the project through the web.
> 0 votes

---
Tags: drush
---


# Question
Title: How to invoke a custom operation in Views
I have a View that lists some nodes. Each node instance has a boolean - "Spam" - that defaults to FALSE.

In the view there is an "Operations" column where there shall be a link with the anchor text "Flag as spam". When the user clicks on that link, the value of the boolean Spam field for that node becomes "TRUE".

I found this tutorial: https://www.drupal.org/docs/7/creating-custom-modules/howtos/how-to-add-a-column-with-dynamically-generated-action-buttons \- but it is for Drupal 7.

However, what do I need to do to list a custom operation (with clickable link or button) in an "Operations" column produced by Views?

# Answer
> 4 votes
Those are "operations". That view field is controlled by the EntityOperations field.

It's pretty easy to add a new operation for an entity by implementing hook\_entity\_operation.

```
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Url;

/**
 * Implements hook_entity_operation().
 */
function mymodule_entity_operation(\Drupal\Core\Entity\EntityInterface $entity) {
  $operations = [];
  if ($entity->getEntityTypeId() == 'node' && someOtherCondition($entity)) {
    $operations['flag_as_spam'] = [
      'title' => t('Flag as Spam'),
      // Replace with the route you've created to set the node value.
      'url' => Url::fromRoute('entity.node.canonical', ['node' => $entity->id()]),
      'weight' => 50,
    ];
  }
  return $operations;
}

```

---
Tags: views, 9
---


# Question
Title: How do I get theme suggestions for a custom block attached via an entity reference field?
I have created a custom block type with the machine name "score\_card". I am displaying it on a node page via a paragraph with an entity reference field that references blocks. I would like to get a template suggestion for it along the lines of "block--block\_content--score-card.html.twig".

I have template suggestions turned on and I do see suggestions in the HTML output for the paragraph, the reference field and the individual custom block type fields. There are no suggestions shown for blocks at all, not even block.html.twig. Attempting to just place 'block--block\_content--score-card.html.twig' or 'block--score-card.html.twig' in my theme has no effect.

I also attempted to generate the theme suggestion using the suggested fix in this thread of adding hook\_theme\_suggestions\_block\_alter to no effect. Running this code through the debugger shows that the hook is not called for the block referenced via a field.

Using Drupal 8.9 latest how can I implement a custom theme for a custom block type referenced via a an entity reference field?

# Answer
I finally got some nice simple template suggestions by using the Block Content Template module. Found it from recent discussion in a core issue. Thanks to all involved.

For example this gives me : block-content--55.html.twig, block-content--hero.html.twig and block-content.html.twig when rendering a block content attached to an entity reference field.
> 1 votes

---
Tags: 8, theming, blocks
---


# Question
Title: How to display a content-management-system-agnostic contact form I have developed, just without iframe?
I have developed a simple, *content-management-system-agnostic*\[1\] PHP-HTML-JavaScript-CSS contact form which I normally embed by iframe but I no longer want to use iframe due to the form appearing partially in mobile display with scrolling needed to view all of it.

I can use this CSS as a partial solution:

```
@media screen and (max-width:733px) {
    #prcf_iframe {
        height:547px;
    }
}

```

This is neither a "pixel perfect" solution nor anything near pixel perfect because in some mobile displays the form either still has some scrolling area or, in other mobile displays, suddenly has some extra "dead height area".

---

How could I show this CMS-agnostic form in Drupal without using iframe?
1. Due to the form being CMS-agnostic by design, it should also not be part of a Drupal module.

# Answer
A "CMS-agnostic form that is not part of a Drupal module" could also be considered a "third-party PHP script", which is a security risk.

Now, you wrote this code yourself, so you can vouch for it. But, you are basically asking, "how can I inject a PHP script into Drupal?", which is something that Drupal doesn't want you to do as it can circumvent Drupal's various security features.

This means that the answer to your question is "It's hard and there will be compromises."

Here are three approaches you can take.

## Approach: Host the script on the same server, but separate it from Drupal

One approach is to host the script in its own directory on your server, and then exclude that directory from Drupal. This exclusion can be done at the server level so Drupal never sees the script and the script doesn't see Drupal.

In this case, the script will not be part of the Drupal site, so you won't have the theme.

The server configuration depends on your server; you can Google it.

## Approach: Embed it in an iframe

You said you didn't like scrolling in your iframes, but there are many JS libraries to work around this, such as iframe-resizer. This is a Stack Overflow question though.

## Approach: Use Webform

Re-write your form to use the Webform module. Yeah, it won't be CMS-agnostic anymore. But Webform is one of the premier Drupal contrib modules and can do basically anything-- many organizations choose Drupal because of this module. So it can obviously handle a contact form of any complexity, and it will give you full integration with Drupal.
> 1 votes

# Answer
Use the PHP module, at your own risk.
> 0 votes

---
Tags: entities, blocks
---


# Question
Title: How to list Links/Attachments in sidebar second
When managing fields for a given content type in Drupal 9, I would like to be given the option to list all items of a given field (e.g. Links, Attachments, ... ) in a specific region (say, sidebar second), rather than at the bottom of the page (as is default).

Can this be accomplished by CSS?

Can this maybe be accomplished with the Display Suite module?

# Answer
> 0 votes
The go-to module for arranging fields on forms is Field Group.

After installing the module, you can go to **Manage Form Display** for your content type and create field groups.

Advantages of using field groups:

* Stored as configuration so they can be kept in version control
* Can be configured in the UI
* Has options for vertical tabs, horizontal tabs, accordions and so on by default
* Can easily add classes for further customization

Note that this won't allow you to easily move things to sidebar second-- your form will be printed in the main content region of the theme, and it's not straightforward to print parts of the form UI in different regions-- but it will allow you to customize the layout a lot, and hopefully you can achieve the look you want.

# Answer
> 0 votes
The Layout builder module in Drupal core does what you need.

Note that the 2 approaches you mention can work, as well. However, if you don't need other features from Display suite, I think most people would recommend not adding such a huge module when you can accomplish your needs with core. You can also accomplish them with theming, but with significantly more work than Layout builder or Display suite.

All else being equal, I'd go with Layout builder. It lets you define and position content 'sections' and 'blocks' on a page via a User interface. Among the things you can do via this interface, you can set the number of columns, sections and blocks, and choose what content goes in each block.

Here are some instructional resources. I also include a few quick steps below.

## basic steps

Give these steps a whirl. The tool is often not immediately intuitive; it's a powerful set of features with a lot of options. The docs/videos will take you much further.

**Setup**

1. Enable modules. You can find do so on the Extend page ({yourdomain.com}/admin/modules). Put checks in the boxes next to the following:
    * Layout Builder
    > Allows users to add and arrange blocks and content fields directly on the content.
    * Layout Discovery
    > Provides a way for modules or themes to register layouts.
    * Field Layout
    > Allows users to configure the display and form display by arranging fields in several columns.
2. Enable Layout builder on the Manage display page of your content type:
    1. for this example, visit the Article Display mode at ({yourdomain.com}/admin/structure/types/manage/article/display/default)
    2. at the bottom of this configuration page, expand Layout options
    3. check the box next to Use layout builder
    4. for this example, select 2 columns
    5. click Manage layout
    6. in the 2nd column, click 'add block'
    7. select the field(s) you want to show in the 2nd column

**Verify it works as you expect**

1. Visit an existing Article or create a new one.
2. Ensure there is content in each field your layout uses. Empty fields can be set not to appear.

---
Tags: theming, display-suite, layout-builder
---


# Question
Title: Where can I find the Annotation(s) for test classes?
I've seen lots of examples of tests like:

```
/**
 * My test description.
 *
 * @group mymodule
 */
class MyModuleTest extends KernelTestBase { }

```

I know what `@group mymodule` is and how that annotation works, but what other information can I put there? or, more importantly, where is that information defined? I can’t find it anywhere.

# Answer
Yes, these are annotations. See https://phpunit.readthedocs.io/en/9.5/annotations.html

Specifically in Drupal the @group annotation is mandatory. The @requires annotation is optional. The description is discovered from the lines above the first annotation or, if specified, from @coversDefaultClass.

See TestDiscovery::getTestInfo.
> 5 votes

# Answer
@group is one of the many available PHPUnit annotations.
> 3 votes

---
Tags: testing
---


title: How do I get the UUID of a bundle?

text:
# Question
Title: How do I get the UUID of a bundle?
The getBundleInfo method returns only the machine name and label for bundles. How do I get the UUID of each bundle, or of all bundles?

# Answer
```
<?php

namespace Drupal\uuid\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\ContentEntityType;
use Symfony\Component\HttpFoundation\JsonResponse;

/**
 * Class UUIDController.
 *
 * @package Drupal\uuid\Controller
 */
class UUIDController extends ControllerBase {

  public function uuidGet() {
    $uuid = [];
    $entity_type_definations = \Drupal::entityTypeManager()->getDefinitions();
    /* @var $definition \Drupal\Core\Entity\EntityTypeInterface */
    foreach ($entity_type_definations as $definition) {
      if ($definition instanceof ContentEntityType) {
        $content_types = \Drupal::entityManager()->getBundleInfo($definition->id());
        $entity_type = $definition->getBundleEntityType();
        if ($entity_type && $content_types) {
          foreach ($content_types as $type_id => $type) {
            $uuid[$entity_type][$type_id] = \Drupal::entityTypeManager()->getStorage($entity_type)->load($type_id)->uuid();
          }
        }
      }
    }
    return new JsonResponse($uuid);
  }

}

```

Above code will give UUID of all bundles and you can call this controller anywhere in your code like below, this will give all UUID's for bundles presented.

> Drupal\entity\_type\_clone\Controller\UUIDController::uuidGet()

To get a single UUID for specific bundle try below code:

> Drupal::entityTypeManager()-\>getStorage("ENTITY\_TYPE")-\>load("BUNDLE\_MACHINE\_NAME")-\>uuid();
> 4 votes

# Answer
Replace `BUNDLE_MACHINE_NAME` with your bundle machine name.

```
Drupal::entityTypeManager()->getStorage("node_type")->load("BUNDLE_MACHINE_NAME")->uuid();

```

Or you can also load it like this:

```
Drupal\node\Entity\NodeType::load("BUNDLE_MACHINE_NAME")->uuid();

```

Entities based on `EntityInterface` will have the `uuid()` method.

See `EntityInterface::uuid`
> 3 votes

# Answer
The easiest method will be by adding UUID by editing views of entity listing.

Eg: if you want to find the UUID of content,

1. Edit the view admin/content
2. Add Field UUID
3. Save View

Navigate to admin/content to see uuid for corresponding content entity
> 0 votes

# Answer
If you have devel module installed, you can see the UUID by inspecting the development output of such content from the admin UI or debugging a variable.
> 0 votes

---
Tags: entities
---


# Question
Title: Views: Apply a wrapper to every 3 and 6 group of rows
My Views Output is as follows

```
<div class="views-row-1">Content</div>
<div class="views-row-2">Content</div>
<div class="views-row-3">Content</div>
<div class="views-row-4">Content</div>
<div class="views-row-5">Content</div>
<div class="views-row-6">Content</div>
<div class="views-row-7">Content</div>
<div class="views-row-8">Content</div>
<div class="views-row-9">Content</div>
<div class="views-row-10">Content</div>
<div class="views-row-11">Content</div>
<div class="views-row-12">Content</div>
<div class="views-row-13">Content</div>
<div class="views-row-14">Content</div>
<div class="views-row-15">Content</div>
<div class="views-row-16">Content</div>
<div class="views-row-17">Content</div>
<div class="views-row-18">Content</div>

```

I would like to put a wrapper around every 3 and 6 group of Views rows.

So my mark up would look like this:

```
<div class="group group-1">
<div class="views-row-1">Content</div>
<div class="views-row-2">Content</div>
<div class="views-row-3">Content</div>
</div>

<div class="group group-2">
<div class="views-row-4">Content</div>
<div class="views-row-5">Content</div>
<div class="views-row-6">Content</div>
<div class="views-row-7">Content</div>
<div class="views-row-8">Content</div>
<div class="views-row-9">Content</div>
</div>

<div class="group group-3">
<div class="views-row-10">Content</div>
<div class="views-row-11">Content</div>
<div class="views-row-12">Content</div>
</div>

<div class="group group-4">
<div class="views-row-13">Content</div>
<div class="views-row-14">Content</div>
<div class="views-row-15">Content</div>
<div class="views-row-16">Content</div>
<div class="views-row-17">Content</div>
<div class="views-row-18">Content</div>
</div>

```

How can I do this? I know that I have to use `views-view-unformatted.tpl.php` but I am not sure how to alter the `$row` variable to target every 3rd and 6th group.

Thanks in advance for any help that can be offered.

# Answer
A few tips about the code:

* You also can make the logic in the preproccess or proccess hooks if you prefer
* To complete the information given by Jack: Modular arithmetic . This theory help us to build our strategy.

Aplication in a preprocces hook to separate the logic from the template:

```
function YOURTHEME_preprocess_views_view_unformatted(&$vars){

   $vars['prefix'] = array();
   $vars['suffix'] = array();
   $group = 1;
   $last_row = count($vars['rows']) -1;

   foreach($vars['rows'] as $id => &$row){

     $vars['prefix'][$id] = '';
     $vars['suffix'][$id] = '';

     // Apply modular arithmetic
     $remainder = $id % 9;

     // First div => 3 items
     if($remainder == 0){
       $vars['prefix'][$id] = "\n <div class=\"group group-$group\">";
     }

     if($remainder == 2){
       $vars['suffix'][$id] = '\n </div>';
       $group++;
     }

     // Second item => 6 items
     if($remainder == 3){
       $vars['prefix'][$id] = "\n <div class=\"group group-$group\">";
     }

     if($remainder == 8){
       $vars['suffix'][$id] = '\n </div>';
       $group++;
     }

     // Close the div in case there are not enough items
     if($last_row == id && $remainder != 2 && $remainder != 8){
        $vars['suffix'][$id] = '\n </div>';
     }

   }

}

```

Your template in you theme that will overwrite the default template provided by views:

```
<?php if (!empty($title)): ?>
  <h3><?php print $title; ?></h3>
<?php endif; ?>
<?php foreach ($rows as $id => $row): ?>
  <?php if (!empty($prefix[$id])){ print $prefix[$id]; } ?>
    <div <?php if ($classes_array[$id]) { print 'class="' . $classes_array[$id] .'"';  } ?>>
    <?php print $row; ?>
  <?php if (!empty($suffix[$id])){ print $suffix[$id]; } ?>
</div>
<?php endforeach; ?>

```
> 6 votes

# Answer
If you are using `views-view-unformatted.tpl.php`

you can achieve a goal with the foreach loop:

```
<?php
$group_nr = 1;                  // first group number
$last_row = count($rows) -1;    // last row
$wrapper  = 3;                  // put a wrapper around every 3 rows
?>
<?php foreach ($rows as $id => $row): ?>
<?php if ($id % $wrapper == 0) {print '<div class="group group-'.$group_nr.'">'; $i = 0; $group_nr++; } ?>
    <div class="views-row-<?php print $id+1; ?>">
        <?php print $row; ?>
    </div>
<?php $i++; if ($i == $wrapper || $id == $last_row) print '</div>'; ?>
<?php endforeach; ?>

```

** In this example, every 3 rows will be wrapped in div with class "**group-\[group nr\]**"*

If these rows should be wrapped every sixth row as well, then you will need add some logic to tell whether do not wrapp in third row, but wait for the sixth.

Hope this will help.
> 2 votes

# Answer
Views Rows Wrapper module wraps every N rows with custom HTML element.
> 1 votes

# Answer
`views-view-list.tpl.php` might be a better option to wrap groups of results.

This template is used to output the results list, and might be a bit more concise scope wise.
> 0 votes

# Answer
Example in Twig for `views-view-unformatted.tpl.php` wrapping every 3 rows:

```
{#
/**
 * @file
 * Theme override to display a view of unformatted rows.
 *
 * Available variables:
 * - title: The title of this group of rows. May be empty.
 * - rows: A list of the view's row items.
 *   - attributes: The row's HTML attributes.
 *   - content: The row's content.
 * - view: The view object.
 * - default_row_class: A flag indicating whether default classes should be
 *   used on rows.
 *
 * @see template_preprocess_views_view_unformatted()
 */
#}
{% set wrapper_count = 3 %}
{% set wrapper_attributes = create_attribute({'class': ['group']}) %}
{% set row_classes = [default_row_class ? 'views-row'] %}

{% if title %}

  <h3>{{ title }}</h3>

{% endif %}

{% for row in rows %}
  {% if loop.index % wrapper_count == 1 %}
    <div {{ wrapper_attributes.addClass(['group-' ~ loop.index]) }}>
  {% endif %}
  <div{{ row.attributes.addClass(row_classes) }}>
    {{- row.content -}}
  </div>
  {% if loop.index % wrapper_count == 0 or loop.last %}
    </div>
  {% endif %}
{% endfor %}

```
> 0 votes

---
Tags: theming, views
---


# Question
Title: Access Denied for programmatically added file to a node
I have a custom script that imports contents from an external database. I'm attaching files using the below custom code.

```
$file = File::create([
  'filename' => $new_filename,
  'uri' => $folder_uri . '/' . $new_filename,// private://my_content_type/<subdir>/filename.pdf
]);
$file->setPermanent();
$file->save();

```

Once the above part is complete, then attach that file(s) to the new node using the below custom code.

```
$storage_handler = \Drupal::entityTypeManager()->getStorage("node");
$data = [
    'type' => 'my_content_type',
    'title' => 'A title',
    'status' => 1,
    ...
    'field_attach' => ['target_id' => $file->fid->value],
    ...
  ];
$node = $storage_handler->create($data);
$node->save();

```

When I edit the same node I see the correct file attached but while opening it in preview, I receive "Access Denied", even I'm logged as an admin.

Though, the field `field_attach` is a multiple one and if I manually attach another file from the edit page and save it, then I can correctly preview it.

### debug:

This is the devel part for the node:

```
[field_attach] => Array
(
    [x-default] => Array
    (
        [0] => Array
        (
            [target_id] => 1876 // Can't preview, access denied
            [display] => 1
            [description] =>
        )
        [1] => Array
        (
            [target_id] => 1878 // Can preview it
            [display] => 1
            [description] =>
        )
    )
)

```

In database each file has same values:

```
# select * from file_usage where fid in(1876, 1878)\G
*************************** 1. row ***************************
   fid: 1876
module: file
  type: node
    id: 92
 count: 1
*************************** 2. row ***************************
   fid: 1878
module: file
  type: node
    id: 92
 count: 1
2 rows in set (0.000 sec)

# select * from file_managed where fid in(1876, 1878)\G
*************************** 1. row ***************************
     fid: 1876
    uuid: 876c1bd1-566c-4d6b-a767-4925d75b593f
langcode: it
     uid: 1
filename: first_file.pdf
     uri: private://my_content_type/201211/first_file.pdf
filemime: application/pdf
filesize: 140982
  status: 1
 created: 1651744379
 changed: 1651744379
*************************** 2. row ***************************
     fid: 1878
    uuid: 4c26c169-3e92-4254-af49-e5b203caf4c6
langcode: it
     uid: 1
filename: second_file.pdf
     uri: private://my_content_type/202205/first_file.pdf
filemime: application/pdf
filesize: 140982
  status: 1
 created: 1651745721
 changed: 1651745725
2 rows in set (0.000 sec)

```

Permissions are the same for directories and for files. Something is different from manual and programmatically attach. Lost to set something?

Thanks in advance.

# Answer
At the page `/admin/reports/access-denied` it can be found where the access denied is fired. Comparing with a working situation I find that it is necessary to add also a line in the `file_usage` table. This is the line code necessary to place after node is saved:

```
\Drupal::service('file.usage')->add($file, 'file', 'node', $node->id());

```

where the service is an instance of `Drupal\file\FileUsage\DatabaseFileUsageBackend` class.
> 1 votes

# Answer
Your code looks OK to me. However, not sure what file permission you want. Have you tried passing user id to see whether you are able to see the uploaded file?

```
  $file = File::create([
      'filename' => $new_filename,
      'uri' => $folder_uri . '/' . $new_filename,
      'uid' => 1,
    ]);

```

Just a recommendation, it would be ideal to pass the file id using id() function.

```
 'target_id' => $file->id(),

```
> 0 votes

---
Tags: nodes, 9
---


# Question
Title: Upload directory with no prefix (://) was not found for file uploads
I am not able to get file uploads of any type to work on my Drupal instance when I attempt to add media using the built in form. When I upload an image file, I get:

And looking at the log messages in Drupal I see:

`The upload directory ://2022-05 for the file field field_media_image_private could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.`

I do not understand where the path :// comes from. I would have expected it to be something like public:// or private:// but not just ://.

A few things I tried with no success (for test purposes):

* Setting relative instead of absolute paths for files and private folders in settings.php.
* Setting 777 permissions on the files and private folders.
* Disabling every module except core and rebuilding all caches.

What else could be the source of this issue? What else can I check?

# Answer
> 0 votes
In your question you said you made sure the private directory is relative and not absolute. The private files directory must be specified as absolute. Below is the documentation for `file_private_path`, from `default.settings.php` (emphasis, mine).

> A local file system path where private files will be stored. This directory *must be absolute*, outside of the Drupal installation directory and not accessible over the web.

---
Tags: media, 9
---


# Question
Title: Programmatically add value to multi-valued/repeater field at weight/index
In Drupal 8, I have a content type and more than a few nodes that have a Paragraph field with unlimited number of values, and so I need to programmatically add a paragraph at an index to the existing values in the field. I know in the form editor widget I'm able to add a field value then drag the field to the order that I need, or change the weight then save the content.

I'm currently loading the node and appending the value like so

```
    $paragraph_node = Paragraph::create($fields);
    $paragraph_node->save();

    $node = Node::load($nid);

    $node->field_paragraph_repeater->appendItem(
      [
        'target_id' => $paragraph_node->id(),
        'target_revision_id' => $paragraph_node->getRevisionId(),
      ]
    );

    $node->save();

```

but this only adds the value at the end, how would I be able to add this with a weight?

# Answer
> 0 votes
You can get the field values as an array and then use array\_splice to insert your new value where you want it. See Insert new item in array on any position in PHP.

```
$values = $node->get('field_paragraph_repeater')->getValue();
$addition = [
  'target_id' => $paragraph_node->id(),
  'target_revision_id' => $paragraph_node->getRevisionId(),
];
$addition_index = 3;

// Insert the new value into your $values array.
array_splice($values, $addition_index, 0, [$addition]);

// Set the value on your node and save.
$node->set('field_paragraph_repeater', $values);
$node->save();

```

---
Tags: 8, entities, paragraphs
---


# Question
Title: drush not finding correct multisite settings.php
I have a Drupal 9 site using multisite to support both local and production hosts. I have defined them in sites/sites.php:

```
$sites['www.electronovelty.com'] = 'www.electronovelty.com';
$sites['www.en9-local.pglatz.com'] = 'www.en9-local.pglatz.com';

```

and created settings files in

```
sites/www.electronovelty.com/settings.php
sites/www.en9-local.pglatz.com/settings.php

```

Using xdebug, I've verified when opening the two web sites that the correct settings.php is used. But when I try to run drush 11, it is using settings from sites/default/settings.php for some reason:

```
% drush cr -v
 [info] Starting bootstrap to site
 [info] Drush bootstrap phase 2
 [info] Try to validate bootstrap phase 2
 [info] Try to validate bootstrap phase 2
 [info] Try to bootstrap at phase 2
 [info] Drush bootstrap phase: bootstrapDrupalRoot()
 [info] Change working directory to /Users/pglatz/dev/electronovelty/en9-www/web
 [info] Initialized Drupal 9.3.12 root directory at /Users/pglatz/dev/electronovelty/en9-www/web
 [info] Try to validate bootstrap phase 2
 [info] Try to bootstrap at phase 2
 [info] Drush bootstrap phase: bootstrapDrupalSite()
 [info] Initialized Drupal site default at sites/default
 [success] Cache rebuild complete.

```

I tried specifying the uri, and it finds the correct settings.php, but I'm also getting a "command nt found" error, which I do not understand:

```
% drush -l www.en9-local.pglatz.com -v cr
 [info] Starting bootstrap to site
 [info] Drush bootstrap phase 2
 [info] Try to validate bootstrap phase 2
 [info] Try to validate bootstrap phase 2
 [info] Try to bootstrap at phase 2
 [info] Drush bootstrap phase: bootstrapDrupalRoot()
 [info] Change working directory to /Users/pglatz/dev/electronovelty/en9-www/web
 [info] Initialized Drupal 9.3.12 root directory at /Users/pglatz/dev/electronovelty/en9-www/web
 [info] Try to validate bootstrap phase 2
 [info] Try to bootstrap at phase 2
 [info] Drush bootstrap phase: bootstrapDrupalSite()
 [info] Initialized Drupal site www.en9-local.pglatz.com at sites/www.en9-local.pglatz.com
sh: ^www.en9-local.pglatz.com$: command not found
 [success] Cache rebuild complete.

```

Where is that error coming from, and what does it mean?

# Answer
You have two options to handle this:

1. Use the `-l` flag with your drush command: `drush -l www.electronovelty.com cr`
2. Create a drush alias, and call the alias. To create aliases, you can create the file /drush/sites/self.site/yml, and put the following contents:

```
 site1:
   uri: www.en9-local.pglatz.com
 site2:
   uri: www.electronovelty.com

```

You can then use the aliases:

```
 drush @site1 cr
 drush @site2 cr

```

And the relevant multisite will be called.
> 0 votes

---
Tags: drush, multi-sites
---


# Question
Title: Is it possible to override configuration with yml files?
Override configuration guide shows how users can override configuration with global `$config` variable, for example by using `settings.php` file (the same method as for D7).

But is it possible to override the configuration in a similar way but with yml file? It's much more convenient to use yml instead of php to override settings.

A real life example: let's say my module offers some configuration but I don't want to expose it via UI. I only want users to be able to change the settings via yml files (there are reasons for that). Obviously they shouldn't change my modules yml config file. Can they create a new yml file, name it accordingly (how?) and put inside `sites` dir?

# Answer
No, you can't *override* with YAML files.

But, all configuration *is* YAML. You can edit them manually with single export and then import again, you can do a mass export and then change the exported files (then you even get a diff of the changes that you can confirm).

You can also use `drush cedit yourmodule.settings` or `drush cset yourmodule.settings some.key the_value` (or the export/import commands for editing configuration.

None of those touch the YAML files in your module.. those are only the starting point and are then imported into the active config store of a site, after which they can be edit with the mentioned tools.
> 1 votes

# Answer
No, it's not possible with YAML files but there is another way to override a configuration apart from the global overriding system.

**Global overrides**

```
global $config;
$config['system.maintenance']['message'] = 'Custom maintenance message.';

```

**Module overrides**

1\] Create a service with 'config.factory.override' tag.

```
services:
  foo.config_overrider:
    class: \Drupal\foo\FooConfigOverrides
    tags:
    - { name: config.factory.override, priority: 5 }

```

2\] Create a service class in your module root directory.

```
namespace Drupal\foo;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\Config\ConfigFactoryOverrideInterface;

class FooConfigOverrides implements ConfigFactoryOverrideInterface {

  /**
  * {@inheritdoc}
  */
  public function loadOverrides($names) {
    $overrides = [];

    if (in_array('system.maintenance', $names)) {
      $overrides['system.maintenance'] = ['message' => 'Custom maintennace message.'];
    }

    return $overrides;
  }

  /**
  * {@inheritdoc}
  */
  public function getCacheSuffix() {
    return 'FooConfigOverrider';
  }

  /**
  * {@inheritdoc}
  */
  public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION) {
    return NULL;
  }

  /**
  * {@inheritdoc}
  */
  public function getCacheableMetadata($name) {
    return new CacheableMetadata();
  }
}

```
* `loadOverrides()` Provide overridden configuration values
* `getCacheSuffix()` Return a string to be used in the static cache identifier
* `createConfigObject()` Create a configuration API object that would be used during installation or synchronization
* `getCacheableMetadata()` Return any cache metadata related to our override

**References**
> 1 votes

# Answer
It is possible to override config with YAML files in case you use your own installation profile. This option is provided by Drupal core, no additional modules are needed. It can override any configuration from core or contrib module. It fully replaces the original yml file, therefore "partial" override is not possible. The overrides can be added any time, not only when the site is installed.

For example `profiles/myprofile/config/install/system.site.yml` will override the site config from the system module. It is quite easy to write your own install profile, this feature should be better documented.

There are now multiple contrib modules which provide (even partial) config overrides with yaml files.

config\_override, config\_rewrite, config\_replace
> 0 votes

---
Tags: 8, hooks
---


# Question
Title: How to Install new module, add code to existing module that requires the new module, and import config for the new module in the same build
I seem to be running into a circular dependency issue in the scenario where my new build has a new module (B), new code in an existing module (A) that depends on the new module (B) and new config being imported for the new module (B).

In the past I have handled this with creating and deploying two independent builds, one where I deploy the new modules and enable them, and in the second build, deploy code that requires the new modules and the config for the new modules.

Is there a better way to handle this?

The change in Module A is that one of the services in Module A requires a service from Module B.

I have already added dependency to the new module B in module\_A.info.yml file but that does not help as the module is already installed.

`drush en module_b` does not work and it gives the error.

```
The service "module_A_service" has a dependency on a non-existent service "module_B_service".

```

The config import that is in the build has core.extensions updated to enable module\_B when it is imported but config import with `drush cim` is failing with the same error as above.

# Answer
> 1 votes
This is the solution that worked

a) Implement a hook\_update\_N in module A that is already installed. In the hook\_update\_N add code to install module\_b. Include this in the same build.

```
function module_a_update_NNNN(&$sandbox) {
  $module_installer = \Drupal::service('module_installer');
  $module_handler = \Drupal::service('module_handler');
  if (!$module_handler->moduleExists('module_b')) {
    $module_installer->install(['module_b']);
  }
}

```

b) Deploy the build

c) Do not clear cache. If you run cache clear before updb it will throw the same error as mentioned in the question.

d) Run `drush updb`

e) Run `drush cim`

f) Run `drush cr`

---
Tags: configuration, installation
---


# Question
Title: How do I select multiple values with one checkbox?
With Facets module/search API, I have a checkbox filter where I need to merge some value.

Example:

```
vocabulary  = color

term = light red

term = dark red

term = light blue

term = dark blue

```

In this case i have 4 checkbox.

My checkbox should look like this

```
vocabulary  = color

term = red

term = blue

```

And When i tick Red it list all content tagged with dark red and light red And When i tick blue it list all content tagged with dark blue and light blue

thus the parent term will not be a used value in the filtered content, but only the child value will filter the content.

**Question :** Is it possible to do that with taxonomy hierachy option in the facets?

# Answer
I've resolved this with by activating 'index Hierarchy" in the Search API processor configuration page with the proper taxonomy selected. in the taxonomy i've created new parent term and putted the childs in it, then in the facets those parent are displayed - in a checkbox in my case - and when selecting those parent it filter the content with the value of all the childs. Note that I've excludes the display of the childs in the checkbox, in the facets properties.
> 0 votes

---
Tags: search
---


# Question
Title: Token service not replacing text with term as a token
I'm trying to use the token service to replace a piece of text using a Taxonomy Term.

Example:
Hi \[term:field\_first\_name\], ...

The term is getting loaded correctly, but the text is not changing:

```
    $term = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($tid);

    $token_service = \Drupal::token();
    $text = $token_service->replace($text, [
        'term' => $term,
    ]);

    print_r($text);

```

The print returns:
Hi \[term:field\_first\_name\], ...
instead of:
Hi John, ...

I'm currently using drupal version 9.3.2.

# Answer
> 0 votes
Drupal out-of-the-box has only basic token support, which can replace core entity standard fields like `[term:name]` or `[term:description]`.

Configured fields, usually those with a prefix `field_`, need the module Token to be installed. Then `[term:field_first_name]` will be replaced, if the field exists.

---
Tags: taxonomy-terms, 9, tokens
---


# Question
Title: Programmatically change view mode of media field
I'm attempting to change the view mode of a media field programmatically. I've created a view mode called 'modal'. I created a mytheme\_preprocess\_media hook and attempted to change the view mode a variety ways like

```
mytheme_preprocess_media(&$variables) {
    $variables['view_mode'] = 'modal';
    $variables['elements']['#view_mode'] = 'modal';
    $variables['content']['field_media_oembed_video']['#view_mode'] = 'modal';
}

```

but none seem to work. Using xdebug I know for sure that this hook is being hit but for some reason it always uses the default view mode.

How can I programmatically change the view mode of a media field?

# Answer
*In my wysiwyg I'm embedding media entities. When I embed a media entity I want to be able to change the view mode that is used.*

When you embed a media entity in WYSIWYG you can select a view mode. If you want to change this later programmatically you have to change in the `<drupal-media>` tag the attribute `data-view-mode`. If you didn't specify a view mode this attribute is missing and you have to add it.

If you want to use a theme preprocess hook then use that of the template containing the WYSIWYG field, not that of the media template. Look for the WYSIWYG field in `$variables['content']` and change the HTML source you find in `'#text'`.
> 3 votes

---
Tags: media, hooks, 9
---


title: Inline Entity Form: alter autocomplete

text:
# Question
Title: Inline Entity Form: alter autocomplete
I need to alter the display of the "Add an existing node" autocomplete response:

* Add the content type and some more information form the content (location), display the result on two lines.
* Initiate the autocomplte only if al least 6 characters are entered
* alter the query sort (ORDER BY `changed`)

Which is the best way to to this ?

# Answer
Thanks @chalo

this helped to apply my custom autocomplete endpoint (instead of using views) Here my working example based on @chalos answer.

```
$reference_form['entity_id'] = array_merge(
  $reference_form['entity_id'], [
    '#type' => 'textfield',
    '#autocomplete_route_name' => 'cnfpt_internet.autocomplete',
    '#autocomplete_route_parameters' => [
      'field_name' => 'field_video',
      'target_type' => $reference_form['entity_id']['#target_type'],
      'bundle_name' => 'inline_entity_form',
      'selection_handler' => '',
      'selection_settings_key' => '',
      'entity_id' => 0,
    ],
  ]

```

My problem was that I didn't use the right hook to intercept the native entity autocomplete and replace it by the custom one.
> 0 votes

# Answer
The way I found to deal with this(part in your case) is with a view of type Entity Reference, where the fields you set in the view is what the autocomplete field will display and you can use available filters and sorts. Example:

```
function MYMODULE_inline_entity_form_reference_form_alter(&$reference_form, FormStateInterface $form_state) {
  $form_id = $form_state->getFormObject()->getFormId();
  if ($form_id === 'node_article_edit_form' || $form_id === 'node_article_form') {
    $reference_form["entity_id"]["#selection_handler"] = 'views';
    $reference_form["entity_id"]["#selection_settings"] = [
      "view" => [
        "view_name" => "my_view_name",
        "display_name" => "my_view_display_name",
      ],
    ];
  }
}

```

I hope it helps someone else
> 1 votes

---
Tags: entities, 9
---


# Question
Title: How can I programmatically add or remove a new request_path to block visibility?
It seems like I could utilize the `getVisibilityConditions` method on the block, which returns a `ConditionPluginCollection` object with a `setInstanceConfiguration` method, which is apparently easy enough to use, requiring `$request_path` and `$configuration` arguments. But, the current block visibility request path variable is a string, containing paths separated by commas. How can I update that to either add or remove paths on node save? I know that I'm essentially asking how to manipulate block visibility on the node form, which isn't completely wrong. It just seems like I could be missing something in the API that would allow this kind if thing.

# Answer
> 0 votes
*But, the current block visibility request path variable is a string, containing paths separated by commas.*

This is the summary display, not the data format saved in config. Here the raw input data is saved along with the new lines entered by the user.

If you want to follow @sonfd comment you can rewrite the code of the linked answer:

```
$block = \Drupal\block\Entity\Block::load('openidconnectlogin');
$visibility = $block->getVisibility();
if (isset($visibility['request_path']['pages'])) {
  $pages = $visibility['request_path']['pages'];
  $paths = array_map('trim', explode("\n", $pages));

```

and later

```
  $pages = implode("\n", $paths);
  $visibility['request_path']['pages'] = $pages;
  $block->setVisibilityConfig('request_path', $visibility['request_path']);
  $block->save();
}

```

---
Tags: blocks, configuration
---


# Question
Title: How do I apply different styles according to content type?
in a view I'm filtering content with search API /facets. In the view (field format) i've applied a specific style for the results, some sort of Bootstrap card. IT apply to all content index by search API.

I need to apply different styles according to content type in the results: For the content type "rose" i use a bootstrap card, for the content type "wood" i use full width div with an image a button and a text.

How can i achieve that?

I tried to duplicate the view with the same path parameter (/search), and tried relation/contextual filter but it s not working. And as the view overwrite the display style of the search API "rendered\_item", i cant use those, maybe i should?

# Answer
> 1 votes
Indeed, in the search API view, i had to change the "format display" from field to rendered entity, and in the parameter i choose a display format for the different content type. then i will customize if trough twig template, instead in the view with custom text as like that it apply to any content type.

---
Tags: search
---


# Question
Title: Migrate CSV to content type with paragraphs
I'm trying to import a CSV File into Content Types and Paragraphs, using Migrate module (and mainly this tutorial : https://mtech-llc.com/blog/charlotte-leon/migration-csv-data-paragraphs).

For this I have created a custom module in *modules/custom*, and I added the .yml files in *config/install*.

Here's my two .yml (produit\_epargne is for the Content Type, and epargne\_support is for the Paragraph) :

```
dependencies:
  enforced:
    module:
      - produit_migration
id: produit_epargne
migration_group: produit_group
source:
  plugin: csv
  path: public://csv/test_import_csv_migrate.csv
  ids:
    [id]
  header_row_count: 1
  delimiter: ';'
  fields:
    -
      name: id
      label: id
    -
      name: title
      label: title
    -
      name: field_referent
      label: field_referent
    -
      name: field_fiches_gamme
      label: field_fiches_gamme
    -
      name: field_date_mise_a_jour
      label: field_date_mise_a_jour
process:
  title: title
  field_referent: field_referent
  field_fiches_gamme: field_fiches_gamme
  field_date_mise_a_jour:
    plugin: format_date
    from_format: Y-m-d
    to_format: Y-m-d
    source: field_date_mise_a_jour
    field_supports/target_id:
      -
        plugin: migration_lookup
        migration: epargne_supports
        no_stub: true
        source: id
      -
        plugin: extract
        index:
          - '0'
    field_supports/target_revision_id:
      -
        plugin: migration_lookup
        migration: epargne_supports
        no_stub: true
        source: id
      -
        plugin: extract
        index:
          - 1
destination:
  plugin: 'entity:node'
  default_bundle: produit_epargne
migration_dependencies:
  required:
    - epargne_support
  optional: { }

```

```
dependencies:
  enforced:
    module:
      - produit_migration
id: epargne_support
migration_group: produit_group
source:
  plugin: csv
  path: public://csv/test_import_csv_migrate.csv
  header_row_count: 1
  delimiter: ';'
  ids:
    [id]
  fields:
    -
      name: id
      label: id
    -
      name: field_nb_fonds_euros
      label: field_nb_fonds_euros
    -
      name: field_nb_fonds_thematiques
      label: field_nb_fonds_thematiques
    -
      name: field_nb_support_fcpe
      label: field_nb_support_fcpe
    -
      name: field_nb_support_uc
      label: field_nb_support_uc
process:
  field_nb_fonds_euros: field_nb_fonds_euros
  field_nb_fonds_thematiques: field_nb_fonds_thematiques
  field_nb_support_fcpe: field_nb_support_fcpe
  field_nb_support_uc: field_nb_support_uc
destination:
  plugin: 'entity_reference_revisions:paragraph'
  default_bundle: epargne_supports
migration_dependencies:
  required:
    - files
  optional: { }

```

But I have two major issues :

1. First, the migration group *produit\_group* is not recognized when I run : `drush migrate:imports --group produit_group`  which is probably the source of the second issue
2. Second, when I run `drush migrate:imports produit_epargne`, it only creates the content types withtout the paragraphs linked to it.

Does anybody see the problem in my code / configuration ?

# Answer
Here are my thoughts for your code. Hope it helps!

#1 It should be `drush migrate:import --group=produit_group` instead of `drush migrate:imports --group produit_group`

#2 The paragraph migration name is wrong in the below mapping. It should be `epargne_support` instead of `epargne_support`

```
field_supports/target_id:
      -
        plugin: migration_lookup
        migration: epargne_supports
        no_stub: true
        source: id
      -
        plugin: extract
        index:
          - '0'
    field_supports/target_revision_id:
      -
        plugin: migration_lookup
        migration: epargne_supports
        no_stub: true
        source: id
      -
        plugin: extract
        index:
          - 1

```
> 0 votes

---
Tags: drush, migrations, 9, paragraphs
---


# Question
Title: How do I grab a field from a referenced item in views?
I currently have a view block called `Offerings` that shows up on all my `Course` content-type pages that display all the offerings for the said course. These offerings are their own content type called `Course Offerings`. The `Course Offerings` content type has a `field_course_reference` field so to know which `Course` the offering is for. In order for it to show the proper courses on my view, I have a Contextual Filter set up that references the `field_course_reference` and have it set to "Provide default value" of type "Content ID from URL". My `Course` content-type also has an Entity Reference taxonomy field called `field_course_category`.

What I'm trying to do from the `Offerings` view is grab the `field_course_category` that lives in the `Course` content-type in which the view is being displayed on. I've tried adding every type of relationship and played around with a bunch of settings but no matter what I choose, the field I create remains empty and doesn't seem to grab the taxonomy term that I'm looking for.

Does anyone have any idea on how to go about doing that?

---

I'll try to draw the structure out a bit below as well to hopefully clear up any misunderstandings.

**Content Types:**

* Course
    + `field_course_category`
* Course Offerings
    + `field_course_reference`

**View Block:**

* Offerings
    + This view lists all the "Course Offerings" content types on the "Course" pages using the `field_course_reference` contextual filter using "Content ID from URL".
    + Trying to also get the value of `field_course_category` on this view so that I can use some conditional logic.

Let me know if anything else is needed to clarify. Again, any help would be much appreciated.

# Answer
> 1 votes
Well, I ended up figuring this out myself after digging deeper into relationships so I'm just going to post what I did in case anyone else ever comes into a similar situation.

I had to create 3 new relationships in this order:

1. **`field_course_reference:content`** \- This appeared in my "Course Offerings" content type
2. **Taxonomy term referenced from `field_course_category`** \- This appeared in my "Course" content type. I had to use #1 above as a relationship.
3. **Content using `field_course_category`** \- Relate each content with a `field_course_category` set to the taxonomy term. This had to use #2 above as a relationship.

Then, I went over to my fields and selected the Category of "Taxonomy term" and chose **Name**. I selected the relationship of `field_course_category: Taxonomy term` and the data that I needed was now displayed properly.

---
Tags: views, 9
---


title: Get field widget settings

text:
# Question
Title: Get field widget settings
In Drupal 7 they can be found in object that is returned by field\_info\_instance(). Is there a way to get widget settings for certain field name and bundle in Drupal 8?

# Answer
> 2 votes
I found the way :-)

```
$settings = entity_get_form_display('node', 'article', 'default')
  ->getComponent('field_image')['settings'];

```

# Answer
> 4 votes
I believe the new way, as entity\_get\_form\_display is being deprecated, is this:

```
$entity_type = 'node';
$bundle = 'page';
$form_mode = 'default';

$form_display = \Drupal::entityTypeManager()
  ->getStorage('entity_form_display')
  ->load($entity_type . '.' . $bundle . '.' . $form_mode);

$specific_widget_type = $form_display->getComponent('some_specific_field_machine_name');
if($specific_widget_type['type'] == 'some_widget_machine_name';

// ^ OR v

$widget_types = $form_display->getComponents();
foreach ($widget_types as $widget_type) {
  if ($widget_type['type'] == "some_widget_machine_name") {
    // Do something
  }
}

```

# Answer
> 1 votes
Widget settings are part of entity form displays, not field settings

# Answer
> 0 votes
Just shorter version how to get $form\_display comparing to RaisinBranCrunch's

```
$form_display = \Drupal::service('entity_display.repository')->getViewDisplay($entity_type, $bundle, $form_mode);
$form_display->getComponent('field_name')['settings'];

```

---
Tags: 8, entities
---


title: Help with Views Field Plugin

text:
# Question
Title: Help with Views Field Plugin
I am trying to make a views field plugin that provides some additional functionality to a field for me. I am having issues with it.

I have an entity type called an lms\_request. It has numerous bundles inside of it.

When using the custom 'views field plugin' on a view that specifically filters a single bundle, it works fine.

When I attempt to use the same field on a view that has multiple bundles filtered, or no bundles at all filtered (to show all), it throws an error preventing me from rendering the view. The error it spits out is this:

`Notice: Undefined index: alter in Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender()`

as well as `Error: Unsupported operand types in Drupal\views\Plugin\views\field\FieldPluginBase->advancedRender()`

If I go into the fieldplugin definition and set override `defineOptions`

```
  public function defineOptions() {
    return parent::defineOptions();
  }

```

I receive the following in the dblog (3 times) `Notice: Trying to access array offset on value of type null in Drupal\views\Plugin\views\field\FieldPluginBase->defineOptions()`

I am confused why when filtering on a single bundle it works as expected, but as soon as I remove the filter or set the filter to multiple bundles, it breaks the field.

My hook\_views\_data() looks like this:

```
function lms_request_views_data() {
  $data['lms_request']['request_system_quick_edit'] = [
    'title' => t('Quick Edit Request'),
    'help' => t('Quick edit request form'),
    'field' => [
      'id' => 'request_system_quick_edit',
    ],
  ];

  return $data;
}

```

Where as 'request\_system\_quick\_edit' is the name of the custom field plugin I made.

The field plugin code looks like this:

```
<?php

namespace Drupal\request_system\Plugin\views\field;

use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ResultRow;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;

/**
 * Provides Quick Edit field handler.
 *
 * @ViewsField("request_system_quick_edit")
 *
 * @DCG
 * The plugin needs to be assigned to a specific table column through
 * hook_views_data() or hook_views_data_alter().
 * For non-existent columns (i.e. computed fields) you need to override
 * self::query() method.
 */
class QuickEdit extends FieldPluginBase {

  protected $storage;
  protected $taxonomy;
  protected $library_item;

  /**
   * {@inheritdoc}
   */
  public function __construct() {
    $this->storage = \Drupal::entityTypeManager()->getStorage('lms_request');
    $this->taxonomy = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
    $this->library_item = \Drupal::entityTypeManager()->getStorage('item_type');
  }

   /**
   * {@inheritdoc}
   */
  public function query() {

  }

  // /**
  //  * {@inheritdoc}
  //  */
  protected function defineOptions() {
    parent::defineOptions();
  }

  // /**
  //  * {@inheritdoc}
  //  */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function render(ResultRow $values) {
    $build['output']['#markup'] = 'Test';

    return $build;
  }
}

```

In addition, when adding the field the label and group shows up correctly, but once the field is in the view, it shows up a `:` instead of `Group:Field Name` Any help would be greatly appreciated.

# Answer
I think the issue might be that you need to add a type for your render array item:

```
public function render(ResultRow $values) {
    $build['output'] = [
      '#type' => 'container',
      '#markup' => 'Test',
    ];

    return $build;
}

```
> 0 votes

---
Tags: views, 9
---


# Question
Title: How to add a submission handler to a form class on Drupal 8?
I would like to add a submission handler to my form class so that the submitted values are saved. The parent class does not save them but only displays a message. I use Drupal 8! Here is my form class:

```
<?php

namespace Drupal\greeting\Form;

use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;

class GreetingForm extends ConfigFormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'greeting_form';
  }

/**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    $form = parent::buildForm($form, $form_state);

    $config = $this->config('greeting.settings');

    $form['page_text'] = array(
      '#type' => 'textarea',
      '#title' => $this->t('Content of the Greeting page'),
      '#default_value' => $config->get('page_text'),
      '#description' => $this->t('Allows you to define the text of the Greeting page'),
    );

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {

  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {

    $config = $this->config('greeting.settings');

    $config->set('page_text', $form_state->getValue('page_text'));

    $config->save();

    return parent::submitForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return [
      'greeting.settings',
    ];
  }

}

$config = \Drupal::config('greeting.settings');
$page_title = $config->get('page_text');

```

How do I do it?

# Answer
It looks like the problem reported in the question details have been resolved and the code in the question seems to be working.

However for anybody reaching this page trying to find an answer to the question in the title, here is the answer.

You can attach custom submit handlers to submit buttons in forms by setting the #submit property on the submit button.

```
$form['actions']['button_name'] = [
  '#type' => 'submit',
  '#value' => $this->t('Button Text'),
  '#submit' => ['::customSubmitHandler1', '::customSubmitHandler2'],
];

```

`customSubmitHandler1` and `customSubmitHandler2` would be functions defined inside your form class.

If instead you want to call a function defined in a module, you can add `'custom_module_submit_handler'` which can be a function defined in a module.
> 0 votes

---
Tags: 8, forms
---


# Question
Title: How to refresh and reload (with ajax?) order checkout panes and order calculation independent from commerce cart refresh (e.g. billing address change)
I have following problem:

During checkout, my customer has to fill in his billing address (at least at the first time) to calculate VAT rate and gross price. Further calculation is done via an order processor after that. So far it works fine.

My problem is, that the cart order refresh doesn't refresh the checkout panes (like the order summary) via AJAX, when the billing country (and so perhaps the valid VAT rate, too) has changed. The user has to reload the page in the browser actively or has to submit the form to see an effect, even if the order has been refreshed (and recalculated) behind the scenes already.

1. How can I force a cart refresh and a recalculation via my custom order processor, independent from the cart order refresh interval?
2. How can I trigger a reload for my checkout panes (in best case via AJAX, because of better UX), so that the user sees the changes just in time?

I found out that there have been hooks for that in D7 but in D8/D9 the hooks and services seem to exist no more (e.g. `commerce_cart_order_refresh()` \- see: How can I programmatically recalculate an order total after changing the billing country ).

# Answer
> 1 votes
So you want to refresh some content in the page that's not part of the checkout form? Basically, this can be done using an Ajax callback and one or more Ajax callback commands:

https://www.drupal.org/docs/drupal-apis/ajax-api/core-ajax-callback-commands

You'll need to add an Ajax callback to the country field using a `form_alter()`, and in this callback return the Ajax commands needed to replace the targeted content, selected by class or id.

---
Tags: forms, commerce, javascript, ajax, 9
---


# Question
Title: drush up fails with Unknown archive format
Today, I am getting an error message when I run the Drush download or update command.

```
drush up -y captcha

```

fails with

> Unable to extract /.tmp/drush\_tmp\_1582749966\_5e56d90e14736/captcha-7.x-1.7.tar.gz. Unknown archive format. \[error\]

When I changed the Drush temp directory I still get the same error message. Also, same error message using php7.2, php7.3, php7.4

Why does this happen?

# Answer
> 0 votes
It turned out that Drush was using PHP 7.4 instead of PHP 7.3 on command line. Adding export DRUSH\_PHP=/php\_path to bash\_profile resolved the issue. Updating and downloading Drupal modules is working again.

# Answer
> 9 votes
I had the same issue. I'm on PHP 7.4.5 The issue is fixed by upgrading drush from 8.1.15 to 8.3.3:

Change (update to 8.3.3) Drush-Version in

`~/.composer/composer.json`

and

`composer update`

# Answer
> 9 votes
I ran into this issue recently, which is caused by the fact that the PHP finfo function in PHP 7.4 returns mimetype application/gzip for gzip-compressed files instead of mimetype application/x-gzip as earlier PHP versions had done. A bug report was filed, but it was decided that the change was an improvement so was not fixed (see https://bugs.php.net/bug.php?id=79681).

Since my system does not have multiple PHP versions installed, I could not use either of the solutions involving the use of earlier PHP versions.

Since my system repositories do not yet include drush 8.3.3 which is reported to resolve this issue, I was not able to use that solution either.

Instead, I patched drush locally (located in /usr/share/drush on my system) with the following patch, which worked for me:

```
--- includes/drush.inc.20180206 2020-09-21 07:49:26.161595136 +0200
+++ includes/drush.inc  2020-09-21 07:49:37.012533799 +0200
@@ -891,8 +891,8 @@
   if (class_exists('finfo')) {
     $finfo = new finfo(FILEINFO_MIME_TYPE);
     $content_type = $finfo->file($filename);
+    drush_log(dt('Mime type (finfo) for !file is !ct.', array('!file' => $filename, '!ct' => $content_type)), LogLevel::DEBUG);
     if ($content_type == 'application/octet-stream') {
-      drush_log(dt('Mime type for !file is application/octet-stream.', array('!file' => $filename)), LogLevel::DEBUG);
       $content_type = FALSE;
     }
   }
@@ -972,6 +972,7 @@
 function drush_file_is_tarball($path) {
   $content_type = drush_attempt_mime_content_type($path);
   $supported = array(
+    'application/gzip',
     'application/x-bzip2',
     'application/x-gzip',
     'application/x-tar',

```

# Answer
> 5 votes
The accepted answer didn't work for me, but changing the default PHP version before doing the update did.

```
sudo update-alternatives --set php /usr/bin/php7.3

```

Perform the update, then set the PHP version back.

```
sudo update-alternatives --set php /usr/bin/php7.4

```

I ran into a permission error afterward which was fixed with the Drupal recommendations:

```
#!/bin/bash
cd /path/to/site
chown -R drupal-user:www-data .
find . -type d -exec chmod u=rwx,g=rx,o= '{}' \;
find . -type f -exec chmod u=rw,g=r,o= '{}' \;
cd /path/to/site/sites
find . -type d -name files -exec chmod ug=rwx,o= '{}' \;
for d in ./*/files
do
   find $d -type d -exec chmod ug=rwx,o= '{}' \;
   find $d -type f -exec chmod ug=rw,o= '{}' \;
done
find . -name .htaccess -type f -exec chmod u=rw,g=r,o= '{}' \;

```

Everything works now.

# Answer
> 2 votes
The first paragraph of the answer by @Eric Negaard well explains why it fails.

And the answer by @Hermann Schwarz should work well for a project-specific drush.

Here is how to deal with it if you are using *global* drush in you environment (and maybe Drupal 7).

If you follow the standard installation procedure of `drush`, you are probably using the tool cgr developed by Greg Anderson (see justification) to manage your global `drush`.

Then, `cgr update drush/drush` would do a job, which updates drush to say, 10.4.2 as of 2021-04-14, providing you are using Drupal 8 or above. However, this command would not work well with Drupal 7, because Drush Version 10 (or 9) does not support Drupal 7.

If you are using Drupal 7, do as follows - basically you must uninstall drush first and reinstall your desired version.

```
cgr remove drush/drush
cgr drush/drush:8.4.6

```

where `8.4.6` is the latest (or your chosen) version of drush Ver.8. See drush-ops/drush Releases on Github to check out the latest releases.

For your information,

```
cgr info drush/drush | grep -i versions

```

would return the version of your cgr-installed drush (In my environment, when its version was 10, it did not match with the result of `drush --version`, which confused me).

# Answer
> 0 votes
I solved it using an older version of php as stated here:

https://www.thinkbean.com/drupal-development-blog/running-drush-alternate-version-php

and then after loging in again:

`$ drush73 pm-update`

---
Tags: drush
---


# Question
Title: Comparing 'old' values in hook_user_update
I've got a function which is running on `hook_ENTITY_TYPE_update` for the user account, but I want to be able to compare against previous values that may have been on the user account, eg see if the user has changed their email address and be able to react to it.

I can see that if I run the debug on the `$entity` value that is part of the function that there is an 'original' item within the `values` array, is that the only way to retrieve the pre-edited data?

# Answer
Yes, the data prior to the edit is stored in `original`, which will let you access all the methods of the user object but return values of its prior state.

So, for example, to check whether the email address has been changed:

```
$previous_email = $account->original->getEmail();

if ($previous_email !== $account->getEmail()) {

```
> 1 votes

---
Tags: 8, users
---


title: Adding sequence item to configuration

text:
# Question
Title: Adding sequence item to configuration
I have a configuration item in my custom module, part of which is a sequence, basically I'm attempting to create something akin to an array of items

my\_module.schema.yml

```
my_module.settings:
  type: config_object
  label: 'Configuration'
  mapping:
    custom_fields:
      label: 'Custom Fields'
      type: sequence
      sequence:
        type: mapping
        label: 'Custom Field'
        mapping:
          field_label:
            type: string
            label: 'Field Label'
          field_key:
            type: string
            label: 'Field Key'

```

What I want to be able to do is add a new item to this 'list' as desired, but for the most part up to now (in other areas of my module) I've just been using `$config->set(key, value)` which will just overwrite the current setting, is there a method to add another value to the existing setting, or do I have to load the existing configuration, add it in manually, then save over the whole lot?

# Answer
> 0 votes
turns out, yes, you **can** retrieve the existing set of variables and add to it, but I'm not saying for certain that this is the correct, or best way to do it

```
// Load the current configuration and add this to it
$custom_fields = $config->get('custom_fields');
$custom_fields[] = array(
  'field_label' => 'some label',
  'field_key' => 'some_key',
);
$config->set('custom_fields', $custom_fields);

```

The above works fine, if anyone encounters this and wants to see how to do it, or anyone knows a better way, please feel free to comment

---
Tags: 8, configuration
---


# Question
Title: How to find module that is updating my node after insert
When trying to create a new book i get the following message:

```
Drupal\Core\Entity\EntityStorageException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '53' for key 'PRIMARY': INSERT INTO "book"

```

The problem here is the book is added twice. Therefor the book is created once and for the other one I get the message above.

For some reason the node creating is updated directly after creating it. This doesn't happen with a clean install with the book module. So it must be one of my custom or contrib modules doing this. Therefor the book module gives this error. To figure out where the problem comes from I wonder how I can see what module is updating the node after the insert.

Is it right that the only way the hook\_node\_update is called is by using the `save()` command in code? I trying to find this at this moment but none of the modules using this command seem to be the problem.

Can anyone help me with taking the next step in debugging this problem?

# Answer
> 5 votes
You could implement hook\_module\_implements\_alter to list all modules that implement a specific hook this way:

```
function myModule_module_implements_alter(&$implementations, $hook) {
  if ($hook === 'entity_insert') {
    // List of all modules names that implement hook_entity_insert.
    dump(array_keys($implementations));
  }
}

```

---
Tags: 9, debugging
---


title: Entity agnostic way of retrieving title

text:
# Question
Title: Entity agnostic way of retrieving title
Is there a way of the Title/Label/Name of an unknown entity type via 1 method?

At the moment if it's a node, I have to use `$entity->getTitle()`, for a user it's `$entity->getAccountName()`, for a taxonomy term it'd be `$entity->getName()`

In my head they all feel like the same piece of information, is there a way of retrieving it without having to write out possibilities for each type of entity?

# Answer
All entity types, content and config both, have a `label()` method (see `EntityInterface::label()`).

```
$label = $entity->label();

```

You can use this reliably on any entity. The entity classes themselves (Node, Term, etc) define the most appropriate value, so for nodes you get the title field, for terms you get the name field, and so on.
> 2 votes

---
Tags: 8, entities
---


title: Use HTTP_REFERER within a twig template

text:
# Question
Title: Use HTTP_REFERER within a twig template
I have a FAQ page with five nested bootstrap 5 accordions and I need to have one accordion item or another open depending on the page the user is coming from.

I tried using this:

```
{% set previousURL = app.request.headers.get('referer') %}

```

but I get nothing.

Using Drupal 9.

# Answer
To do this you must either:
> -1 votes

---
Tags: 9
---


title: Custom theme function for a Field

text:
# Question
Title: Custom theme function for a Field
I want to change a theme hook for one field from a custom FieldFormatter. It's #theme callback is 'field' but I want to give the user the option to toggle a setting that changes this to 'field\_raw', which then uses a Twig template with no markup. I can't figure out the theme hook.

Twig template:

```
{%- for item in items %}{{ item.content }}{% endfor -%}

```

Module hook:

```
function mymodule_theme($existing, $type, $theme, $path) {
  return [
    'field_raw' => [
      'items' => NULL,
    ],
  ];
}

```

I am unsure of what to pass here that makes it to the twig template. I can output text in the template so I know it is being hit. What is the right variables to set here so the template receives it?

I also tried:

```
'render element' => 'element'

```

```
'render element' => 'elements'

```

```
'render element' => 'children'

```

# Answer
> 1 votes
**Using the field base hook**

If this template with no markup should output field values `{{ item.content }}` you need the core code processing these values by defining a base hook.

See for example comment\_theme():

```
/**
 * Implements hook_theme().
 */
function comment_theme() {
  return [
    ...
    'field__comment' => [
      'base hook' => 'field',
    ],
  ];
}

```

In this case it's not enough to start the theme hook name with the base hook, it also needs double underscores: `field__raw`.

---

**Implementing a custom theme hook**

Not recommended, for demonstration purpose, you can copy the relevant core code to your own template:

*mymodule.module:*

```
function mymodule_theme($existing, $type, $theme, $path) {
  return [
    'field_raw' => [
      'render element' => 'element',
    ],
  ];
}

function template_preprocess_field_raw(&$variables, $hook) {
  $element = $variables['element'];
  $variables['items'] = [];
  $delta = 0;
  while (!empty($element[$delta])) {
    $variables['items'][$delta]['content'] = $element[$delta];
    $delta++;
  }
}

```

In this case you can choose a random name for the theme hook, but it must not start with `field__`.

Switch to this template in the custom field formatter:

```
  public function view(FieldItemListInterface $items, $langcode = NULL) {
    $elements = parent::view($items, $langcode);
    if (isset($elements['#theme'])) {
      $elements['#theme'] = 'field_raw';
    }
    return $elements;
  }

```

And finally place the minimal template in the module folder

*mymodule/templates/field-raw.html.twig*

```
{%- for item in items %}{{ item.content }}{% endfor -%}

```

---
Tags: entities, 9
---