# Question
Title: How to programmatically save a node's layout?
Not sure if this is the best approach but it does work well.. almost.

I am using the Layout Builder Modal module which, in layout builder, opens block configuration in a modal. This is great but I would like to extend this capability to the front end so that I can configure a layout block without having to go into the node's layout.

If I simply place the contextual link which this module creates on to my node page; sure enough it opens the required modal and allows me to change the configuration of the specific block. On submit, the block config is changed and the modal closes, but the layout isn't saved to use this new block config. This can be seen when I go to the node layout and it states there are changes pending. If I now save the layout I see my block config changes.

How can I programmatically force the node's layout to be saved?

# Answer
> 2 votes
While this is not an actual answer to your question "How can I programmatically force the node's layout to be saved?", I wanted to point you to the Layout Builder IPE module, that I have created to solve a similar use-case as yours: Provide editing possibilities directly from the view page of a node.

If this is not an option for you, then the programatic solution probably evolves around:

1. hooking into the form submit
2. adding your custom submit handler
3. grab the block config somehow
4. update the OverridesSectionStorage for the node
5. save the node
6. delete the temporary storage for the layout builder of that node

At least that's what I recall. While working on Layout Builder IPE, I found that whole structure a bit complicated to be honest, which was the main reason to try and get this done once in a more generic way.

**Update** Some more details I looked up that might help with this:

To get the sections for a layout builder enabled node you can use LayoutEntityHelperTrait::getSectionStorageForEntity, e.g.:

```
$section_storage = $this->getSectionStorageForEntity($node);
$sections = $section_storage->getSections();

```

This `$sections` variable is an array of sections, each section containing section components. You can iterate over them until you find the block you are looking for and do what you need to do to update the configuration (untested code):

```
foreach ($sections as $delta => $section) {
  foreach ($section->getComponents() as $component) {
    // Each component is an object of type \Drupal\layout_builder\SectionComponent.
    // To identify the block you can use the plugin id (or the UUID if
    // multiple blocks of the same type exist).
    $plugin_id = $component->getPluginId();
    if ($plugin_id == 'BLOCK_PLUGIN_ID') {
      $configuration = $component->get('configuration');
      // Update the configuration, and then update the component.
      $component->setConfiguration($configuration);
    }
  }
}

```

Once the necessary changes have been made, the sections can be saved back to the node by using this:

```
$node->get(OverridesSectionStorage::FIELD_NAME)->setValue($sections);

```

And to clear the tempstore something like this should work, though this should be using DI obviously:

```
\Drupal::service('layout_builder.tempstore_repository')->delete($section_storage);

```

---
Tags: 9, layout-builder
---


# Question
Title: show/hide a menu item based on specific user role
I have a certain number of main menus which need to showcased based on logged in user role. for example user with the role, A can sees few menus and user with the role B, sees another set of few menus.

# Answer
This can be achieved using the routes to manage the permissions. Take the following example:

**mymodule.routing.yml**

```
mymodule.home:
  path: '/mymodule'
  defaults:
    _controller: '\Drupal\mymodule\Controller\MyModuleController::overview'
    _title: 'My Module'
  requirements:
    _role: 'authenticated user'

mymodule.settings:
 path: '/admin/mymodule'
 defaults:
   _form: 'Drupal\mymodule\Form\MyModuleSettingsForm'
   _title: 'Settings'
 requirements:
   _permission: 'administer mymodule'

mymodule.view:
 path: '/mymodule/view'
 defaults:
   _controller: '\Drupal\mymodule\Controller\MyModuleController::view'
   _title: 'View'
 requirements:
   _role: 'authenticated user'

mymodule.edit:
 path: '/mymodule/edit'
 defaults:
   _form: 'Drupal\mymodule\Form\MyModuleEditForm'
   _title: 'Edit'
 requirements:
   _permission: 'edit mymodule'

```

**mymodule.links.menu.yml**

```
mymodule.home:
  title: 'My Module'
  parent: main
  route_name: mymodule.home
  weight: 10

mymodule.settings:
  title: 'Settings'
  parent: mymodule.home
  route_name: mymodule.settings
  weight: 10

mymodule.view:
  title: 'View'
  parent: mymodule.home
  route_name: mymodule.view
  weight: 10

mymodule.edit:
  title: 'Edit'
  parent: mymodule.home
  route_name: mymodule.edit
  weight: 10

```

With this approach you can display the same menu to all users, but because the links take the permissions from the routes, only users with the `administer mymodule` permission will be able to see the Settings link for example. You can use roles to manage it as well by using `_role: '$rid'`.
> 4 votes

# Answer
In Drupal 8, you can also use the following code in your `funky.module` file for a programmatic approach. The approach below allows to have access rules independent of menu visibility:

```
/**
 * Implements hook_preprocess_menu().
 *
 * @param array[] $variables
 */
function funky_preprocess_menu(&$variables) {
  if (in_array('role_b', Drupal::currentUser()->getRoles())) {
    // Hide the menu item
    unset($variables['items']['the_key_you_used_in_your_menu_links_yml_file']);
  }
}

```

This assumes your module is called `funky`. It also assumes you have a `funky.links.menu.yml` file containing something similar to this:

```
the_key_you_used_in_your_menu_links_yml_file:
  title: 'Your menu caption'
  route_name: your_route
  menu_name: account
  cache_contexts:
    - user.roles

```

If you only distinguish if a user has a role or not, then you can further tighten the cache\_context by that role. For the example above, `user.roles:role_b` would be appropriate. The documentation for cache contexts is here: https://www.drupal.org/docs/8/api/cache-api/cache-contexts
> 4 votes

# Answer
**Note:** A solution using route permissions is the best and appropriate solution to avoid repetition and prevent a user to access/view the page using a direct link.

---

All you gotta do is configure your menu block

Then under Visibility \> Roles, check mark ☑ the roles that you want to be able to view this block menu.
> 2 votes

# Answer
For a non-coding approach, the contrib module Menu Per Role may be of use.

> This module allows you to restrict access to menu items based on user roles. Just activate the module and edit a menu item as usual. There will be a new fieldset that allows you to restrict access by role.
> 0 votes

# Answer
Just use Menu Item Role Access. It makes it much easier than writing code.
> -1 votes

---
Tags: 8, navigation
---


# Question
Title: How can I add classes to an item in field.html.twig
I have a typical content type, with a field, let's say field\_name.

I can output each field using the field.html.twig file. In the file, to output each item, there is a line

`<div{{ item.attributes }}>{{ item.content }}</div>`

So how can I set item.attributes, to output, say, the machine name of the field, so that my output is:

`<div class="field_name">My Name</div>`

I suspect it has to do with using the:

**function theme\_preprocess\_field(&$variables) {**

`$item['content']['#item_attributes']['class'][] = $variables['field_name'];`

Is this correct? Where do I go from here? How can I make this work?

Thanks!!

# Answer
*How can I add classes to an item in field.html.twig?*

Use attributes.addClass():

```
<div{{ item.attributes.addClass(field_name|clean_class) }}>{{ item.content }}

```
> 1 votes

---
Tags: theming
---


# Question
Title: How to load a sandbox project via composer and enable other devs on project to commit to the sandbox project
I'm working on an install profile right now in Drupal (https://www.drupal.org/sandbox/jnicola/3277854). I want to while developing the next project we're on also build this out during the initial part of building our site out.

I can load the sandbox project via composer no problem, and it's checked out via git, but when I run git status I get "HEAD detached at 56eaaa5"

I'd like the sandbox repo to be checked out on the active development branch, and I want to be able to work inside of that project inside of Drupal in general.

It is fairly important that this is brought in via composer as well, since I will be adding modules requirements into the sandboxes composer.json file for the overall project, so I believe bringing in the repo as a "submodule" wouldn't work, even though that is the desired functionality.

# Answer
> 0 votes
Reference this project version in `composer.json` as `1.0.x-dev`. This is documented by Composer. Composer checks out a commit, so `cd` into the project working copy and type `git checkout 1.0.x`.

In detail, `composer.json` should contain this in the `repositories` section:

```
        {
            "type": "vcs",
            "url": "https://git.drupalcode.org/sandbox/jnicola-3277854.git"
        }

```

Then you type:

```
composer require 'drupal/simple_grouped_content:1.0.x-dev'
cd profiles/contrib/simple_group_content
git checkout 1.0.x

```

This is a Composer question rather than a Drupal question.

---
Tags: composer
---


# Question
Title: Programmatically adding block into layout builder layout?
I'm trying to add a block into a layout builder, but it seems the 'getSections' for a node which is currently at the default layout does not output anything, not sure if it's a bug or if that's intended behaviour... getSections will only output items if the layout for the node has deviated fromt he default...

ie:

```
 $entity = \Drupal::entityTypeManager()->getStorage('node')->load('127');
 $layout = $entity->get('layout_builder__layout');
 $sections = $layout->getSections();
 dpm($sections, 'sections');

```

$sections will be empty unless that node has had it's layout modified...is that normal behaviour?? seems like a bug, shouldn't the default sections still be outputted?

# Answer
Until a nodes layout has been overridden, no layout is stored in the node field `layout_builder__layout` (better use `OverridesSectionStorage::FIELD_NAME` actually). That is by design and makes a lot of sense if you think about it.

To get the configured sections that make up the layout of a node, be it the default layout or an overridden one, you have to use the section storage for a given entity.

```
$section_storage = $this->getSectionStorageForEntity($node);
$sections = $section_storage->getSections();

```

The method `getSectionStorageForEntity` comes from the LayoutEntityHelperTrait.
> 3 votes

---
Tags: layout-builder
---


# Question
Title: How to hide an exposed filter block if the view results are empty?
I have an exposed filter block on the sidebar on my page. I want to hide the exposed filter block if the result of the view is empty. What is the best was to do it ? Right now i am having some Jquery code in a no result behaviour textfield wich hides some block elements. But i dont like this solution. I prefer if the code is clean and the html code is completely removed.

# Answer
@pierre's answer is a good one, however $view-\>total\_rows is not always populated.

So you could do something like this instead, which will work no matter what:

```
function MODULE_views_pre_render(&$view) {
  if ($view->name == 'VIEW_NAME' && $view->current_display == 'DISPLAY_NAME') {
    if (empty($view->result) && empty($view->getExposedInput())) {
      $view->exposed_widgets = NULL;
    }
  }
}

```
> 8 votes

# Answer
In a custom module, implements `hook_form_FORM_ID_alter()` for the `views_exposed_form` form. Start by checking if the form is the one from your view and display, then set its `#access` property `FALSE` if the views has no results.

```
function MODULE_form_views_exposed_form_alter (&$form, &$form_state) {
  $view = &$form_state['view'];
  if ($view->name == VIEW_NAME && $view->current_display == DISPLAY_NAME) {
    if (empty($view->total_rows)) {
      $form['#access'] = FALSE;
    }
  }
}

```
> 1 votes

# Answer
The above suggestions for **\[function MODULE\_form\_views\_exposed\_form\_alter(&$form, &$form\_state)\]** are helpful if you want to hide the exposed filters whether or not the results will showing.

So according to yours requirement you can hide filters when no result will found using below code-:

```
function hook_views_pre_render(&$view){
  if($view->name == VIEW_NAME){
    if(empty($view->result) && isset($view->exposed_widgets)){
        $view->exposed_widgets = FALSE;
      }
   }
}

```
> 1 votes

# Answer
Just one quick correction for Drupal 9 to avoid having the warning:

```
Warning: Parameter 1 to hook_views_views_pre_render() expected to be a reference, value given.

```

```
use Drupal\views\ViewExecutable;

/**
 * Implements hook_views_views_pre_render().
 */
function agi_views_views_pre_render(ViewExecutable $view) {
  if ($view->id() === 'view_id'){
    if (empty($view->result) && isset($view->exposed_widgets)) {
      $view->exposed_widgets = FALSE;
    }
  }
}

```
> 1 votes

# Answer
Answer provided by @Juyal Jee is generally correct, but probably outdated. `$view->name` variable doesn't exist any more. Insted `$view->id()` method can be used:

```
function hook_views_pre_render(&$view){
  if($view->id() == VIEW_NAME){
    if(empty($view->result) && isset($view->exposed_widgets)){
      $view->exposed_widgets = FALSE;
    }
  }
}

```
> 0 votes

# Answer
To my surprise, adding a `Global: Result summary` field in the Header seems to have changed the block behavior.

Before, the block showed on the page with only the Title search box visible. Immediately after I saved the new field, the block stopped showing.

My answer is obviously very unscientific, and I've not tested thoroughly. Are others experiencing the same magic?
> 0 votes

# Answer
1. Go to the advanced tab of you view
2. Add contextual filters
3. Select Global: Null
4. When the filter value is NOT available: Select 'Hide view'
> -2 votes

---
Tags: views, blocks
---


# Question
Title: How to not show the "has been created" message?
I want to remove the message that is output in the message area when a new node is created. A typical message may look like this.

"Article My article has been created."

I examine the node in `hook_node_insert`, and when certain criteria is met, I want to delete the message or prevent the message from appearing.

I've tried to put the following in `hook_node_insert`:

```
 $messages = \Drupal::messenger()->all();
 dpm($messages, 'messages');

```

It outputs an empty array: `messages => []`.

This similar question for Drupal 7 How do I change/modify an update content message suggests `hook_message_alter()`. I haven't found that, or a replacement, for Drupal 9.

It has been suggested that this is a duplicate of How do I programmatically change a system message?

I don't think it is a duplicate, but that question contains a single answer that is helpful to my use case. *Most* of the answers are not a good fit for this question, so I believe that my question presents a more focused problem and deserves to stay open.

I went through all the answers. These are my findings as to how well they fit *this* question:

* The accepted one (use `\Drupal::messenger()->deleteAll();`) does not work when placed in `hook_node_insert`, and no alternative placement is suggested.
* The most upvoted one (implement `hook_preprocess_status_messages`) does not fire *after* node creation form has been submitted and has no effect.
* To use hack the `$SESSION` variable (`unset($SESSION['_symfony_flashes']['status'][0]);`) does not work in `hook_node_insert`and no other placement is suggested.

The answer from Achraf JEDAY, with 1 upvote prior to mine today (Adding a a custom submit handler to the node creation form) works. Cudos.

This is also the accepted answer (from Patrick Kenny) here.

# Answer
> 4 votes
If you want to add a custom message in a hook, you can clear the messages and then add your custom message. This is quick and easy, and it can be done in most hooks.

Unfortunately, this won't work with `hook_node_insert()`, so an alternative is to add a custom submit handler to the node creation form and call the Messenger service statically:

```
  \Drupal::messenger()->deleteByType('status');
  \Drupal::messenger()->addMessage(t('My new custom message.'));

```

This will get very messy if you override a lot of messages, but if you just need to change a few, this is the approach I use.

# Answer
> 2 votes
I've accepted and upvoted Patrick Kenny's answer, since it provides 99% of the solution.

However, I realized that I also needed this worked out:

> I examine the node in `hook_node_insert`, and when certain criteria is met, I want to delete the message or prevent the message from appearing.

This was added to the question *after* Patrick Kenny answered, but for those interested in how this final step was solved:

1. If certain criteria is met insert an error message `\Drupal::messenger()->addError(t('Error'));`
2. Sniff for the error message in the submit handler, and if it is present, delete the unwanted status message.

Voilà!

---
Tags: hooks, 9
---


# Question
Title: How do I get the value of Markup::$string?
I have the following code in a custom submit handler:

```
$status = \Drupal::messenger()->messagesByType('status');
foreach ($status as $delta) {
   // Here I want to extract the text string that is in $delta.
}

```

The variable `$delta` now contains this:

```
delta => stdClass Object
(
    [__CLASS__] => Drupal\Core\Render\Markup
    [string:protected] => Article request My article has been created.
)

```

How do I get the protected string from `$delta`?

I've already tried some methods, but so far I haven't found one that works.

Here are those tried so far:

> Error: Call to undefined method Drupal\Core\Render\Markup::getMessages()
> Error: Call to undefined method Drupal\Core\Render\Markup::toString()

# Answer
> 5 votes
A protected variable is only accessible from the class itself. Your only option to access it from outside the class is via a public method.

Looking at the Markup class, the only public methods are:

1. `count()`
2. `jsonSerialize()`
3. `__toString()`

Simply put, because Markup implements the magic method `__toString()` (which returns `$this->string`), you can get that string simply by using the object as a string, e.g. `echo $my_markup_object;`

---
Tags: 9
---


title: How do I import user roles with feeds?

text:
# Question
Title: How do I import user roles with feeds?
I created a CSV file with a column "Roles" and values like `role_a, role_b`, where `role_a` is the machine name of the role.

However, when I try to import the role in my feed, I get an error that `role_a` and `role_b` do not exist-- but they definitely do exist on my site. How can I import roles?

# Answer
> 1 votes
By default, the Feeds module can only handle a single input value. To input multiple values (such as multiple roles), you need to modify the data before Feeds processes it.

You can do this with the Feeds Tamper module.

1. Install the Feeds Tamper module.
2. Go to the **Tamper** tab of your feed type admin screen (`/admin/structure/feeds/manage/MY_FEED_MACHINE_NAME/tamper`.
3. For the Roles field, click **Add Plugin** and add the `Explode` plugin with the default settings.
4. Next, click **Add Plugin** again and add the `Characters to trim` plugin with the default settings.

If you don't complete step 4, then when Feeds Tamper explodes the string into multiple values, your second value will be  `role_b` (with a space in front), which will cause assignment of that role to fail.

---
Tags: 9, feeds
---


title: Access FieldItem object from Widget

text:
# Question
Title: Access FieldItem object from Widget
I have a custom FieldItem with a method doing a calculation on the field's values:

```
class MyFieldItem extends FieldItemBase {
  ...
  public function getAmountInEuros() {
    $amount = $this->get('amount')->getValue();
    $currency = $this->get('currency')->getValue();
    $exchange_rate = $this->getExchangeRate($currency);
    return $exchange_rate * $amount;
  }
  ...

```

I have a custom widget for that FieldItem where I need to do exactly the same calculation.

```
class MyWidget extends WidgetBase {
  ...
  public function getAmountInEuros() {
    ...
  }
  ...
}

```

Of course, I would prefer to write down this logic only in one place, preferably in the FieldItem definition.

**How can I access the corresponding FieldItem from within the widget?**

(The code is just a minimal example that should show the principal problem with a complex field and widget that work otherwise.)

# Answer
> 1 votes
If you are building a single form element you have $delta to get the field item.

```
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {

  $euros = $items[$delta]->getAmountInEuros();

```

In other widget methods you can loop over $items.

---
Tags: entities, database
---


title: Selective cancellation from Watchdog

text:
# Question
Title: Selective cancellation from Watchdog
Can I selectively DELETE rows from watchdog? I have annoying errors and warnings I'm slowly getting rid of, but I would like to keep the history of user actions (create, update and delete on content).

I made an experiment on my development environment and I had no problem, I also found somebody around who did something similar and survived – but still, I'd like to be sure that this is legit.

# Answer
You can do this with Drush and it's super easy:

*Delete a specific message containing a string:*

`drush watchdog:delete "a string I want to delete"`

*Delete all php category messages:*

`drush watchdog:delete --type=php`

Full documentation

It is totally safe to delete watchdog messages like this-- core automatically prunes messages when you get too many, anyway. The only "danger" is that you may delete information you need to debug issues with your site, but as long as you check the messages before deleting them, it shouldn't be a problem.
> 1 votes

---
Tags: 8, log-messages
---


# Question
Title: Custom textfield element, different $form_state value and element '#value' value
I have a textfield element (named 'bus\_station'), which holds a bus station name.

I am looking for a way to create a custom 'bus\_station' element (possibly extending Textfield class), which would:

* Still expect a text input in form of bus station name (and retain it during `$form_state->setRebuild()` and show it to user), but
* In `$form_value`, after form submit, either provide a `FALSE` (custom code in Element definition doesn't recognize input as a station) or `TRUE` (it does recognize a station)? Or Entity ID (ID of a matched bus station) and/or `NULL` (no match)?

# Answer
> 0 votes
This can be done via Form API callback implementation:

Inside `module/src/Element/ElementClass.php`, in `public function getInfo() {}` define a callback, e.g. `processMyElement` under `'#process'` key:

```
public function getInfo() {
  $class = static::class;
  return [
    // [...] Some other definitions.
    '#process' => [
      [$class, 'processMyElement'],
    ],
  ];
}

```

And then perform two complementary operations.

(1) Process the user input and return a value which will be provided in the `'#form_state'` values in `valueCallback()` method:

```
public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
  $output = parent::valueCallback($element, $input, $form_state);
  if ($input == 'SOMETHING') {
    $output = 'SOMETHING_ELSE';
  }
  return $output;
}

```

(2) And vice versa, in the `processMyElement()` method return the original value:

```
public static function processMyElement(&$element, FormStateInterface $form_state, &$complete_form) {
  if ($element['#value'] == 'SOMETHING_ELSE') {
    $element['#value'] = 'SOMETHING';
  }
  return $element;
}

```

**Usage example**

I have used this to extend `Drupal\Core\Render\Element\Textfield` class in combination with JS Storage Complete. That gives me Autocomplete (without need for a callback URL). This autocomplete returns Entity ID obtained via entity load based on unique label inside `valueCallback()` method, but user is still presented with its text input (obtained by returning `$entity->label()` inside `processMyElement()` method).

---
Tags: forms, 9
---


# Question
Title: Logs full of "page not found" entries for various *.js.map files
Our Drupal 9 site is full of "page not found" warnings in the Drupal logs. All entries end in \*.js.map (all map files). I cannot figure out where the warnings are coming from (what system is trying to find non-existent map files?) or how to resolve.

See screenshot for examples of not-found files.

# Answer
> 2 votes
It means that someone browsed the site with developer tools enabled, which tried to load debugging files that do not exist.

`.map` files, known as "sourcemap" files, are used by web browser developer tools for debugging CSS and JavaScript by allowing minified and aggregated CSS and JavaScript to appear in their original source code forms.

`.map` files are not necessary for the normal operation of a web site. If `.map` files are missing, it is because a preprocessor did not create them, or in some cases, a vendor did not provide them.

There is an open issue in Drupal core to create these.

---
Tags: log-messages
---


title: How upload a file\image via json api?

text:
# Question
Title: How upload a file\image via json api?
I'm trying to upload a file or image on a D9 site via json api. The test is namely to upload the user picture on the user entity.

I've been following the documentation or read questions about, but I can't get it working.

The front-end is done with Next.js.

One the test done is the following:

The front-end next calls the next.js api server:

```
const filename = selectedFile.name;
const fr = new FileReader();
fr.readAsArrayBuffer(selectedFile);
fr.onload = async function () {
    const arrayBuffer = fr.result;
    if (arrayBuffer && typeof arrayBuffer !== 'string') {
        const base64String = _arrayBufferToBase64(arrayBuffer);
        const cookieSession = await getUpdateCookie();
        const res = await fetch(`/api/users-test/user?cookie=${cookieSession}&name=${filename}`, {
            method: 'POST', body: base64String,
        });
    }
}

function _arrayBufferToBase64(buffer: ArrayBuffer) {
    let binary = '';
    const bytes = new Uint8Array(buffer);
    const len = bytes.byteLength;
    for (let i = 0; i < len; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return window.btoa(binary);
}

```

The api next.js server post then to Drupal:

```
const res = await fetch(
      `${process.env.NEXT_PUBLIC_DRUPAL_BASE_URL}/jsonapi/user/user/{userID}/user_picture`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/octet-stream',
          Accept: 'application/vnd.api+json',
          'Content-Disposition': `name="file"; filename="${filename}"`,
          Authorization: `Bearer ${token}`,
        },
        body: req.body,
      }
    );

```

I tried different ways to convert the file to "binary file data", but none work: the user picture is always a blank square with an X.

However, if I try the same call with postman, the file is correctly loaded:

So, for now, I hypothesize the problem is on the javascript code, while Drupal has been configured correctly.

# Answer
I am currently having the same issue. The post goes thru perfectly in postman. the code snippet below is used to perform the post action in nextjs

```

//this function is used to convert the file

const readFileDataAsBase64 = (fl) => {
    const file = fl;

    return new Promise((resolve, reject) => {
        const reader = new FileReader();

        reader.onload = (event) => {
          console.log('here')
            resolve(event.target.result);
        };

        reader.onerror = (err) => {
            reject(err);
        };

        reader.readAsDataURL(file);
    });
}

//get the value of the file converted to binary
const filedata= await readFileDataAsBase64(values.files[0]);

//call the post file function to perform the post
const resfile = await postFiles(
      'http://the-url',
      filedata,
      values.files[0].name
    );

const postFiles = (url, body, filename) => {

    const myPost = async() => {
        try {
         const res = await fetch(url, {
              method: 'POST',
              body: body,
              headers: {
                'Content-Type': 'application/octet-stream',
                'Content-Disposition': `file; filename=${filename}`,
                'api-key': 'myapi-key',
              },
            });
        } catch (err){
        }

    }
    postData();

  };

```

This file isn't being posted to drupal. Did anyone found a solution to properly post a file using the api
> 0 votes

---
Tags: javascript, files, 9
---


# Question
Title: There were errors validating the config synchronization
Locally I deleted custom block "CTA" from custom blocks and block types. Then I exported configs and created merge request. After merge is accepted, the pipeline runs commands on the dev server. And after `drush -y cim` command I receive the table which shows what configs were deleted and changed and also the next error:

> \[error\] Drupal\Core\Config\ConfigImporterException: There were errors validating the config synchronization. Entities exist of type Custom block and Custom block type CTA. These entities need to be deleted before importing. in Drupal\Core\Config\ConfigImporter-\>validate() (line 750 of /var/www/html/website/web/core/lib/Drupal/Core/Config/ConfigImporter.php).

In ConfigImportCommands.php line 360:

> The import failed due to the following reasons:
> Entities exist of type Custom block and Custom block type CTA. These entities need to be deleted before importing.

How can I fix this error?

# Answer
The error message tells you what to do:

> Entities exist of type Custom block and Custom block type CTA. These entities need to be deleted before importing.

You can solve this as follows:

1. Delete all blocks of type CTA at Admin -\> Structure -\> Block Layout -\> Custom Block Library
2. Delete the CTA block type at Admin -\> Structure -\> Block Layout -\> Custom Block Library -\> Block Types
3. Import the configuration
> 3 votes

---
Tags: blocks, configuration
---


# Question
Title: Method getTitle() returns an unexpected value. What causes this?
In an implementation of `hook_node_insert()`, I have the following three lines of code:

```
dpm($entity, 'entity');
$title = $entity->getTitle();
dpm($title, 'title');

```

From the first `dpm()` I get:

```
entity =>
Drupal\node\Entity\Node {#1632 ▼
  +in_preview: null
  #values: array:27 [▼
    ...
    "title" => array:1 [▼
       "x-default" => array:1 [▼
        0 => array:1 [▼
          "value" => "Expected title"
        ]
     ]
...

```

I.e. the title field output by the variable dumper is the title field I expected to see.

The second `dpm()` produces:

```
title =>
"The previous title"

```

I.e. when I extract the title from the entity, using the `getTitle()` method, I get a *different* value. The value is from an entity (node) the I load in a operations link controller (overriding `ControllerBase`), but it not saved inside the controller, and should not fire `hook_node_insert()`.

I construct and save a new node in the controller, using this code:

```
$node = \Drupal::entityTypeManager()->getStorage('node')->create([
  'type' => 'my_type',
  'body' => 'Body',
]);
$node->setTitle('Expected title');
$node->save();

```

I assume that this is the `$node->save();`that fires `hook_node_insert`.

What is going on here?

Why does the bogus title appear in the hook, and how do I get the expected result?

For the record: I am not changing the node in `hook_node_insert`. I am deleting it if the title meets certain criteria. I am unable to use a constraint for preventing it from being created for reasons unrelated to this question.

# Answer
In a content entity the protected `$values` array contains the original values of the entity. The actual field values are stored in the protected array `$fields`, which holds an array of FieldItemList objects. These are lazily built, so when the node is loaded this array is empty. When you get/set fields through the public entity methods and properties the field objects with the actual data will be created and stored in this internal array.

For debugging purpose you can force the `$fields` array to be fully populated by

```
$values = $node->toArray();

```

This returns the entity values by creating all field objects and building an array of actual field values.

To check the object properties don't use dpm() because you don't know whether the displayed result is from the same request.
> 1 votes

---
Tags: nodes, 9
---


# Question
Title: How to check if secondary database definition exists
Can anyone please help me on how to check if secondary database is set. If not throw an error.

I am currently defining database connection as below.

```
Database::getConnection('default', 'sqlite')

```

I am trying to defining a if , else condition based the database defining.

When I try

```
if(Database::getConnection('default', 'sqlite')){
  echo success;
}else {
  echo fail;
}

```

I am getting below error. If secondary database definition is not defined in settings.php

```
Drupal\Core\Entity\EntityStorageException:
The specified database connection is not defined: sqlite in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 811 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).

```

# Answer
To check if a connection has been defined, I would use code similar to the following one.

```
if ($connections = Database::getAllConnectionInfo() && isset($connections['default']['sqlite'])) {
  // The connection is defined.
}

```

`Database::getConnection()` returns a connection object, and it could return the one for default/primary server, when the requested information is for an ignored connection or the requested connection isn't defined.

```
  // If the requested target does not exist, or if it is ignored, we fall back
  // to the default target. The target is typically either "default" or
  // "replica", indicating to use a replica SQL server if one is available. If
  // it's not available, then the default/primary server is the correct server
  // to use.
  if (!empty(self::$ignoreTargets[$key][$target]) || !isset(self::$databaseInfo[$key][$target])) {
    $target = 'default';
  }
  if (!isset(self::$connections[$key][$target])) {

    // If necessary, a new connection is opened.
    self::$connections[$key][$target] = self::openConnection($key, $target);
  }

```

This means that expecting an exception from `Database::getConnection()` when the connection isn't defined is wrong.
> 2 votes

# Answer
```
try {
    $connection = Database::getConnection('default', 'sqlite');
}
catch (Drupal\Core\Entity\EntityStorageException $e) {
    // Do something here.
}
finally {
    // Optional: do something in any case.
}

```
> 1 votes

# Answer
Although cilefen pointed me in the right direction. It still throws fatal error when using cilefen's answer. I am able to resolve this issue by slightly modifying exception handling.

```
try {
  $connection = Database::getConnection('default', 'sqlite');
} catch (\Exception $e) {
  return new \Exception("SQLite Database configurtion is not setup.", 1);
}

```

Created a core issue #3282024 to add native method to check database connection.
> -1 votes

---
Tags: database, 9
---


# Question
Title: When editing a node, tab group titles are missing
When editing a node, tab group titles are missing:

The HTML looks like this:

```
<ul class="horizontal-tabs-list">
   <li class="horizontal-tab-button horizontal-tab-button-0 first selected" tabindex="-1"><a href="#edit-group-m"><strong></strong><span class="summary"></span><span id="active-horizontal-tab" class="visually-hidden">(active tab)</span></a></li>
   <li class="horizontal-tab-button horizontal-tab-button-1" tabindex="-1"><a href="#edit-group-content"><strong></strong><span class="summary"></span></a></li>
   <li class="horizontal-tab-button horizontal-tab-button-2" tabindex="-1"><a href="#edit-group-sidebar"><strong></strong><span class="summary"></span></a></li>
   <li class="horizontal-tab-button horizontal-tab-button-3 last" tabindex="-1"><a href="#edit-group-related-content"><strong></strong><span class="summary"></span></a></li>
</ul>

```

So the titles are already not printed, so it is not a CSS issue.

Is this a known issue? How can I start debugging this?

# Answer
> 1 votes
Updating `drupal/field_group` to 3.2.0 helped.

---
Tags: 8, panels
---


# Question
Title: Sort the entity obtained from the Query class with values from the Statistics module
I am using the following code to sort the published nodes basing on the value stored from the Statistics module.

```
$query = \Drupal::entityQuery('node')
      ->condition('status', 1)
      ->range(0, 5)
      ->sort('totalcount', 'DESC' );

$result = $query->execute();

```

The code is causing the following exception.

> Drupal\Core\Entity\Query\QueryException: 'totalcount' not found in Drupal\Core\Entity\Query\Sql\Tables-\>ensureEntityTable() (line 316 of core/lib/Drupal/Core/Entity/Query/Sql/Tables.php).

How do I sort nodes basing on the *totalcount* value stored from the Statistics module?

# Answer
> 3 votes
The code you are showing doesn't work because *totalcount* is not a Node property the node entity. That is a value saved in a different database table, not used from the Node entity. See `statistics_get()`, which retrieves the value you are looking for.

```
if ($nid > 0) {
  // Retrieve an array with both totalcount and daycount.
  return db_query('SELECT totalcount, daycount, timestamp FROM {node_counter} WHERE nid = :nid', array(':nid' => $nid), array('target' => 'replica'))->fetchAssoc();
}

```

Since the entity query doesn't allow to join tables, you need to:

* Add a tag to the entity query you are using
* Implement `hook_query_TAG_alter()` to alter the queries with the tag you added (Replace *TAG* with the tag you added to the entity query)

`node_query_node_access_alter()` is the implementation of that hook done from the Node module to allow an entity query to return just the nodes the currently logged-in user has access. You can use its code as guide to write your own implementation.

For example, I would start trying with the following code.

#### The code for the query

```
$query = \Drupal::entityQuery('node')
  ->addTag('statistics_totalcount')
  ->condition('status', 1)
  ->range(0, 5)
  ->sort('totalcount', 'DESC');

$result = $query->execute();

```

#### The hook implementation

```
function mymodule_query_stastics_totalcount_alter(Drupal\Core\Database\Query\AlterableInterface $query) {
  $query->join('node_counter', 'nc', '%alias.nid = n.nid');
}

```

# Answer
> 0 votes
In case this helps anyone else, for me, I had to move the sort clause into the hook\_query\_TAG\_alter() function because of a validation issue on the entity query object.

```
$query->leftJoin('node_counter', 'nc', '%alias.nid = node_field_data.nid');
$query->orderBy('totalcount', 'DESC');

```

---
Tags: database, nodes
---


title: Set nested value in storable config

text:
# Question
Title: Set nested value in storable config
I have a settings form that saves site wide configuration information My submit form function looks something like this

```
$data = [];
foreach ($groups as $key) {
  $data[$key] = $form_state->getValue($key);
  if (empty($data[$key])) {
    $data[$key] = [];
  }
}

$this->configFactory
  ->getEditable('my_config.settings')
  ->setData($data)
  ->save();

```

My issue is that in a callback I'd like to be able to directly set the value of a single configuration field that is nested in that data array without grabbing everything again and changing the data array and resetting it with -\>setData

The data in my config array looks like this

```
[
    'num_campaigns'=> 4
    'campaigns'=> [
        'campaign_ids' => ['abc','def','ghi','jkl']
    ]
]

```

And my callback looks like this

```
  public function removeField(array $form, FormStateInterface $form_state){
    $config = $this->getConfig();
    $num_campaigns = $config['num_campaigns']-1;
    $config_factory = $this->configFactory->getEditable('my_config.settings');
    $config_factory->set('num_campaigns', $num_campaigns);
    $config_factory->set(['campaigns','campaign_ids',$num_campaigns], '')
    $config_factory->save();
    $form_state->setRebuild();
  }

```

My issue is that the **set** method accepts a string and not an array. If I can only supply a string how do I set the value of something that is nested down in my config array? Is using set even an option? Or do I have to resort to using setData?

# Answer
The first parameter is a string with nested keys separated by dots. The second parameter is the value, which is not necessarily a string. It can also be an array:

```
$config->set('campaigns.campaign_ids', ['abc','def','ghi','jkl']);

```
> 3 votes

---
Tags: 9, configuration
---


# Question
Title: How can I get Average of a comment field by node_id?
I have Comments here wherein user can rate a content.

I want to get the average rating per content, how do I efficiently get the average?

I have the following code to get the Average:

```
$cids = \Drupal::entityQuery('comment')
    ->condition('entity_id', $variables['row']->nid)
    ->condition('entity_type', 'node')
    ->condition('comment_type', 'content_rating')
    ->execute();

$comments = [];

$totalRating = 0;

if ($cids) {
    foreach ($cids as $cid) {
        $comment = Comment::load($cid);
        $comments[] = $comment->get('field_rating')->value;
    }

    $totRating = array_sum($comments) / count( $comments );

    $totalRating = ceil($totRating);
}

```

I know this is not efficient because I'm getting ALL the comments and manually computing for the average rating.

How can I get the average rating on a query level?

# Answer
> 1 votes
You should have a table in your database named something like `comment__field_rating`. That table should have a column like `field_rating_value`. Once you've confirmed that, you can write a query something like this:

```
$q = $database->db_select('comment__field_rating)
$q->addExpression('avg(field_rating_value)', 'avg_rating')
$avg = $q->execute()->fetchCol();

```

That's all untested because I don't have your database.

# Answer
> 0 votes
In the docs about the Entity API, there is a method from EntityStorage that you can use to load an array of entity IDs, the `loadMultiple($id)`. Then you can loop through the array of Comments and get all field\_ratings like you are already doing.

```
// Load multiple entities, also exists as entity_load_multiple().
$entities = \Drupal::entityTypeManager()->getStorage($entity_type)
  ->loadMultiple([1, 2, 3]);

```

Also, instead of loading `\Drupal::entityTypeManager()`, you can inject the service `'entity_type.manager'` inside the constructor of your class. This is the best way to call it, but the first one will work ok.

---
Tags: 9, comments
---


title: Alter jsonlog data

text:
# Question
Title: Alter jsonlog data
I am looking to alter the generated output of the log files from the contrib module JsonLog - https://www.drupal.org/project/jsonlog/ The logger generates a .log file, which I need to customize with a few additional fields. Is there a way to alter the data generated by the Logger class? What is the best approach for this? Is extending the Logger within a custom module a good approach?

# Answer
> 3 votes
Loggers in Drupal are Symfony services, so the best way to modify this is to *decorate* the logger.jsonlog service (you need a custom module to this of course). I'd suggest starting with the Symfony docs or google'ing for `symfony decorate service` to get some code examples.

---
Tags: 9
---


# Question
Title: Can I know what I'm looking at from the URL?
I think on Drupal 7 I had previously used something like `menu_get_object()` to find out what content I was on. For example, with mysite.com/content/my-page, it would tell me that this was a node, its content type, its ID, etc.

Ideally I'm trying to do it even if the URL is the site's front page, I'd like to be able to reverse engineer what content it is showing me.

# Answer
> 2 votes
You are looking for a route parameter, which is automatically upcasted to an entity object if you are on an entity route.

For example on a node route:

```
use Drupal\node\NodeInterface;

  $node = \Drupal::routeMatch()->getParameter('node');
  if ($node instanceof NodeInterface) {
    $content_type = $node->getType();
    $id = $node->id();
  }

```

---
Tags: 8, uri
---


# Question
Title: Cannot get entity form to display date field value
I have an entity with two date fields. In the code that saves the entity, is:

```
$date_requested = date('Y-m-d', time());

```

and in the list of field values that get added to the entity:

```
->set('field_date_requested', $date_requested)

```

In inspecting the db, the table contains:

```
bundle | deleted | entity_id | revision_id | langcode | delta|field_date_requested_value
+-------+---------+-----------+-------------+----------+------+--------------+
| my_bundle |       0 |         4 |           4 | en   |    0 | 2022-05-26

```

But when I edit the entity, I see this:

If I insert the date using the same format as the placeholder, it is in the db with that format, but still does not display. If I enter the date in the entity form manually (which requires it to be m/d/Y), it displays when edited again, in that format, though I see no difference in the value subfield in the db.

# Answer
When storing datetimes in the database, you should use DateTimeItemInterface::DATETIME\_STORAGE\_FORMAT, which is `Y-m-d\\TH:i:s`. If you store it in a different format, Drupal will fail to process it correctly.
> 0 votes

---
Tags: datetime, 9
---


# Question
Title: using 2 language switchers in the same node
So i am not sure if this is doable or not, I am trying to add 2 language switchers block to the same node. I would like to have one language switcher for my content type that will be in charge of translating the content only. the other language switcher would be global in my navbar and will be in charge of translating the whole site.

would this idea be doable or not?

# Answer
Drupal supports having one language for the content (controlled by a language switcher block) and a separate language for the site UI.

You can set this up like this:

* Add a language switcher block for the content.
* Enable **Account administration pages** at `/admin/config/regional/language/detection`. (docs here)

Can you actually have two different language switcher blocks in the UI that do different things? No, not without a lot of custom coding.
> 0 votes

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


# Question
Title: Content for textgroup views is not allowed for translation because of its text format
I have this problem with a view's header. I am allowed to enter a translation but the translated text is not rendered when the view is displayed in that language.

I have the following warning in the Views interface.

> content for textgroup views is not allowed for translation because of its text format

I read other posts suggesting to visit *Configuration » Regional and language » Multilingual settings* and verify the text format is selected. These posts were addressing the problem for blocks and they didn't solve my problem.

Any similar experience or solution?

# Answer
I had the same problem, then found a solution. I'll show you the details with screenshots.

1. First enable Internationalization Views (i18nviews).
2. Create your custom view. For example, I'll simply list the nodes related to Article content type.
3. Add a header:
    1. Click on "add" next to Header section
    2. Add *"Global: Text area"*
    3. Type your header text, and select your input format. Please note that I selected *"Filtered HTML"* here!
    4. Click Apply
4. After saving the view, you'll see notice, telling that this header text can not be translated, so in my case:
*"The string `views:list_articles:default:header:views:area:content` for textgroup `views` is not allowed for translation because of its text format."*
5. Go to `admin/config/regional/i18n/strings` (Home » Administration » Configuration » Regional and language » Multilingual settings » Strings)
6. Check the appropriate text format you used above, when adding a header text, it must be the same - so in my case, it's *"Filtered HTML"* -, and then click *Save configuration*.
7. Now go back to your custom view, and on the right dropdown menu, click **"translate view"**:
8. Now you'll see this:
9. Click on one of the *"**translate**"* links. After that, you'll see the following screen, and a message that the appropriate string for the header text translation has been created - which means from now on, you can translate it!
10. Scroll down to the appropriate header text, and translate it:
11. After translating, click on "Save translation".
12. On the following screen, you can see that some translations have been saved.
13. Now when switching to the other language, you'll see that the header text is translated! You are READY!
> 21 votes

# Answer
**This helps for webforms:**

Content --\> Webforms --\> Formname --\> Edit --\> Tab "Webform" --\> Form settings --\> (scroll down) Section "Preview Page"

* Activate in section "Preview Page" the checkbox "enable preview page"
* Set Textformat to "Plain text"
* Save configuration
* Open again section "Preview Page" and **deactivate** the checkbox "enable preview page"
* Save configuration
> 0 votes

---
Tags: 7, views
---


# Question
Title: Store cache's datas in files instead of database
In a huge website, database's tables storing cache may become very large : is there a way to store cache in file system instead of DB ?

I'm talking about a solution that doesn't use external systems like varnish, simply an option provided by Drupal (a config for example). This doesn't seem documented and I'm not sure it exists !

Thanks !

# Answer
> 3 votes
Drupal comes with a php-file based cache backend by default: `\Drupal\Core\Cache\PhpBackend`, the factory is available as the `cache.backend.php` service.

You would configure that to use that by default with `$settings['cache']['default'] = 'cache.backend.php';`.

That said, I wouldn't really recommend using that. PHP files are going to fill your disk as well (without a cleanup-mechanism that the database now has) and if you have a very large site then you probably also have multiple servers and then cache invalidation becomes a problem again, clearing the cache on one server won't clear it on others unless you use a shared file system and that is again slow.

The recommended approach IMHO for a big site is to use an in-memory cache backend like Redis or Memcache (varnish is not a cache backend that is used by Drupal, it's something that sits in front of it). The big advantage of those two is that they store their data only stored in memory (configurable in case of redis) and very fast to access due to that but still easy to for multiple servers. They also have built-in purging of data and a fixed size, so they will automatically delete less-frequently used cache entries. And while not perfect, they are far better at that than the default database backend now which just deletes old cache entries and keeps a fixed amount of caches.

# Answer
> 2 votes
To reduce the overall size of your caches you might want to try to compress them. There's a module for that which works with default database if you have zlib available with your php. Module: compressed\_cache

# Answer
> 0 votes
If you don't use multiple webservers (then there might be better options) or you are on a shared hosting webservers and can't use tools like Varnish, you can use the module File Cache to store cache in file system.

"This module allows Drupal cache bins to be **stored in files instead of storing in database**."

---
Tags: 8, caching
---


title: Problem with feeds taxonomy import

text:
# Question
Title: Problem with feeds taxonomy import
Why is that I cant import taxonomy terms with feeds, it says it imported 23 terms, but they are nowhere to be found....

I used term name, url alias, term id in mapping then imported it via feeds, nothing happens, it says that the terms were imported but tehy are not

vocabolary is called category...

# Answer
> 0 votes
You have to auto-create the term in the feeds field mapping, and/or in the vocabulary option "auto-create" term.

---
Tags: taxonomy-terms, feeds
---


title: How do I bulk delete taxonomy terms?

text:
# Question
Title: How do I bulk delete taxonomy terms?
I'm looking for a way to delete about 1300 taxonomy terms (of 5250 in total) and their association with nodes. I firstly thought to delete the content of these tables:

* taxonomy\_index
* taxonomy\_term\_data
* taxonomy\_ter\_field\_data
* taxonomy\_term\_hierarchy
* node\__field\_tags
* node\_revision\__field\_tag

Is this sufficient?
Is there a better way to do it, without Drush, which I cannot install?

**EDIT :**

I'm trying to do it programmaticaly, but I have an error

```
Error: Call to undefined function field_attach_delete() in delete_taxonomy_terms() (line 42 of /var/www/html/d8/delete_tags.php).

```

Trying to add call to module\_load\_include() but still get the same error. I put the file at the root of my Drupal installation (../mydrupal/delete\_tags.php).

```
<?php
error_reporting(E_ALL);
date_default_timezone_set('Europe/Paris');

define('DRUPAL_DIR', $_SERVER["DOCUMENT_ROOT"]); //__DIR__ ); //.'/../drupal');

use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;

$autoloader = require_once 'autoload.php';
$kernel = new DrupalKernel('prod', $autoloader);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

/**
 * Deletes taxonomy terms.
 *
 * @param array $tids
 *   Array of taxonomy term IDs.
 */

$tids = [830];

delete_taxonomy_terms($tids);

function delete_taxonomy_terms($tids) {

module_load_include("inc", "field", "field.attach");

  db_delete('taxonomy_term_data')
    ->condition('tid', $tids, 'IN')
    ->execute();
  db_delete('taxonomy_term_hierarchy')
    ->condition('tid', $tids, 'IN')
    ->execute();

  $terms = taxonomy_term_load_multiple($tids);

  foreach ($terms as $term) {
    field_attach_delete('taxonomy_term', $term);
    module_invoke_all('taxonomy_term_delete', $term);
    module_invoke_all('entity_delete', $term, 'taxonomy_term');
  }

  // Reset static cache after all terms deleted.
  taxonomy_terms_static_reset();
}

```

# Answer
Before you clean the vocabulary you need to change the taxonomy reference field, to do this you can use this code:

```
$nids = \Drupal::entityQuery('node')->condition('type','YOUR_CONTENT_TYPE')->execute();
$nodes =  \Drupal\node\Entity\Node::loadMultiple($nids);

foreach($nodes as $node) {
  // Change your term here
  $node->field_YOUR_TAXONOMY_REFERENCE_FIELD->value = '';
 $node->save();
}

```

To clean the vocabulary use this modification of a drush command that you can see in https://github.com/adrian-cid/drush\_commands/blob/master/drush\_taxonomy.drush.inc

You need to pass an array of vocabularies names to clean.

I use the `dpm()` function (you need to install Devel) to show the messages, but you can change it if you want.

```
function taxonomy_vocabulary_clean(array $names) {
  if (!empty($names)) {
    // Check for duplicate ids.
    $test_names = array_unique($names);
    if (count($test_names) != count($names)) {
      dpm('You have duplicate vocabulary names.');
      return;
    }
    //Searching the vocabularies in the site
    $vocabulary_in_db = array_keys(Drupal\taxonomy\Entity\Vocabulary::loadMultiple());
    $vocabulary_non_existent = array_diff($names, $vocabulary_in_db);
    $vocabulary_existent = array_diff($names, $vocabulary_non_existent);

    if (count($vocabulary_existent) == 0) {
      dpm("The desired vocabulary to clean doesn't exists.");
      return;
    }
    if (count($vocabulary_non_existent)) {
      dpm('Non-existent vocabulary:');
      dpm(implode(' ', $vocabulary_non_existent));
    }

    foreach ($vocabulary_existent as $name) {
      $tids = \Drupal::entityQuery('taxonomy_term')
        ->condition('vid', $name)
        ->execute();

      $controller = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
      $entities = $controller->loadMultiple($tids);
      $controller->delete($entities);
    }
    dpm('Vocabulary cleaned:');
    dpm(implode(' ', $vocabulary_existent));
  }
  else {
    dpm('You must enter at least one vocabulary name.');
  }
}

```

Using the function:

```
taxonomy_vocabulary_clean(['tags', 'my_vocabulary_machine_name']);

```

The Drupal 7 code:

```
function taxonomy_vocabulary_clean(array $names) {
  if (!empty($names)) {
    // Check for duplicate ids.
    $test_names = array_unique($names);
    if (count($test_names) != count($names)) {
      dpm('You have duplicate vocabulary names.'));
      return;
    }
    //Searching the vocabularies in the site
    $vocabulary_in_db = array_column(taxonomy_get_vocabularies(), 'machine_name');
    $vocabulary_non_existent = array_diff($names, $vocabulary_in_db);
    $vocabulary_existent = array_diff($names, $vocabulary_non_existent);

    if(count($vocabulary_existent) == 0) {
      dpm("The desired vocabulary to clean doesn't exists.");
      return;
    }
    if(count($vocabulary_non_existent)) {
      dpm('Non-existent vocabulary:');
      dpm(implode(' ', $vocabulary_non_existent));
    }

    foreach ($vocabulary_existent as $name) {
      $vid = taxonomy_vocabulary_machine_name_load($name)->vid;
      foreach(taxonomy_get_tree($vid) as $term) {
        taxonomy_term_delete($term->tid);
      }
    }
    dpm('Vocabulary cleaned:');
    dpm(implode(' ', $vocabulary_existent));
  }
  else {
    dpm('You must enter at least one vocabulary name.');
  }
}

```
> 3 votes

# Answer
You can write a custom function let's say on some form submit and do something like this:

```
/**
 * Deletes taxonomy terms.
 *
 * @param array $tids
 *   Array of taxonomy term IDs.
 */
function delete_taxonomy_terms($tids) {
 // Required to use field_attach_delete. - @tenken
 module_load_include("inc", "field", "field.attach");

  db_delete('taxonomy_term_data')
    ->condition('tid', $tids, 'IN')
    ->execute();
  db_delete('taxonomy_term_hierarchy')
    ->condition('tid', $tids, 'IN')
    ->execute();

  $terms = taxonomy_term_load_multiple($tids);

  foreach ($terms as $term) {
    field_attach_delete('taxonomy_term', $term);
    module_invoke_all('taxonomy_term_delete', $term);
    module_invoke_all('entity_delete', $term, 'taxonomy_term');
  }

  // Reset static cache after all terms deleted.
  taxonomy_terms_static_reset();
}

```

of course it's better to write batch function but if it's one time operation you can try to do it simple (be aware that operation may be interrupted depends on your max\_execution\_time value).
> 1 votes

# Answer
If you have taxonomy manager module installed, you can mass delete by running this javascript line in the console, which triggers a click on all the items

`jQuery(".fancytree-checkbox").each(function() { jQuery(this).trigger("click")} )`
> 0 votes

---
Tags: 8, taxonomy-terms, database
---


# Question
Title: Is it possible to have a nested SELECT in a WHERE clause using dynamic queries?
I need to execute this SQL query using dynamic queries.

```
WHERE (node_field_data.status = 1)
AND (node__field_document_places.entity_id IN (SELECT entity_id FROM node__field_document_places where field_document_places_target_id = 51673))

```

This is the code I am using.

```
$connection = Database::getConnection();
$query = $connection->select('node_field_data', 'node_field_data');

$query->condition('node_field_data.status',1);
$query->condition('node__field_document_places.entity_id',[ -- Can I do this here somehow? -- ], "IN");

```

I could technically run a separate query and put the IDs in an array. But I was hoping to avoid executing two different queries.

Is there a way to do this using dynamic queries?

# Answer
> 4 votes
Yes, this is very possible, see the Subqueries can now be added to query conditions change record for full details.

The canonical example is very similar to yours and should demonstrate how to refactor your code:

```
// Create a subquery, which is just a normal query object.
$subquery = db_select('test', 't2');
$subquery->addExpression('AVG(t2.age)');

// Create another query that adds a clause using the subquery.
$select = db_select('test', 't');
$select->addField('t', 'name');
$select->condition('t.age', $subquery, '<');

```

Don't forget to replace the deprecated `db_select()` with `$connection->select()`.

---
Tags: database
---


# Question
Title: Restrict access to webform submission nodes for anonymous
I have a webform in my drupal website. I am uploading a text and pdf file through it. Now I am displaying all the content in a list using a block which is accessible for everyone. It's working fine.

So for every submission there is of-course a node created dynamically. Like - **http://localhost/mysite/webform/upload/submissions/3** So it can be 3, 4, 5 whatever as uploading goes on. Now i have to restrict the access of these nodes / url pattern only to admin. I have tried every thing i found in webform settings configuration. No Luck !!!

One thing i can do is add css to hide that, but i dont think its the way to do it. So, Any help would be appreciated. Thank You.

# Answer
> 0 votes
In Webform (i checked version 5.8) you can do the following.

* Go to the form in question, to the settings tab, and then the access tab
* You can click and tune "view any submissions" and set it to the "admininstrator" role
* You can also tune the area "view own submissions"
* You can do the same thing via main permissions page (/admin/people/permissions)

---
Tags: webforms
---


title: refresh form_token with refresh page

text:
# Question
Title: refresh form_token with refresh page
Unfortunately, the form\_token does not change when I refresh the form pages. Doesn't this cause abuse and security risks? Can anyone explain what Drupal does for CSRF in all its forms? Thanks

# Answer
> 3 votes
As the definition of CSRF says

> A CSRF token is a secure random token (e.g., synchronizer token or challenge token) that is used to prevent CSRF attacks. The token needs to be unique per user session and should be of large random value to make it difficult to guess. A CSRF secure application assigns a unique CSRF token for every user session.

it protects BE to be sure the posted that to the BE comes from a form generated by BE unless anybody can post data to BE from any source.

for example in a login form, a hacker could write a code to try several combinations ( of course drupal has a max retry policy which prevents users to try the wrong password more than 5 times and there is flood detection in drupal that prevent brute force attacking). But still, forms without CSRF protection are good places for bots and spammers to post data to the side several times.

So it's better if your forms are open to anonymous protect them honeypot and a human detection solution ( captcha, Recaptcha, Recaptcha 3 math captcha, etc).

additionally, having Security Kit module make it more secure.

**Update part after I noticed it's happening for logged in users** for the reasons I mentioned above, particularly to have better caching functionalities, for an anonymous user, it does not get refreshed. **But for logged-in user** after some checking in the code level I figure out it's not a bug.

it's generated based on the form\_id and until you have not submitted the form it will be the same and refreshing does not generate a new one. So, `form_token` and `form_build_id` are things that protects form from.

for reference and get more take a look on :

```
    // Add a token, based on either #token or form_id, to any form displayed to
  // authenticated users. This ensures that any submitted form was actually
  // requested previously by the user and protects against cross site request
  // forgeries.
  // This does not apply to programmatically submitted forms. Furthermore,
  // since tokens are session-bound and forms displayed to anonymous users are
  // very likely cached, we cannot assign a token for them.
  // During installation, there is no $user yet.
  // Form constructors may explicitly set #token to FALSE when cross site
  // request forgery is irrelevant to the form, such as search forms.
  if ($form_state
    ->isProgrammed() || isset($form['#token']) && $form['#token'] === FALSE) {
    unset($form['#token']);
  }
  else {
    $form['#cache']['contexts'][] = 'user.roles:authenticated';
    if ($user && $user
      ->isAuthenticated()) {

      // Generate a public token and placeholder based on the form ID.
      $placeholder = 'form_token_placeholder_' . Crypt::hashBase64($form_id);
      $form['#token'] = $placeholder;
      $form['form_token'] = [
        '#id' => Html::getUniqueId('edit-' . $form_id . '-form-token'),
        '#type' => 'token',
        '#default_value' => $placeholder,
        // Form processing and validation require this value. Ensure the
        // submitted form value appears literally, regardless of custom #tree
        // and #parents being set elsewhere.
        '#parents' => [
          'form_token',
        ],

```

**Reference :** https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Form%21FormBuilder.php/function/FormBuilder%3A%3AprepareForm/9.3.x

# Answer
> 2 votes
> Drupal's anti-CSRF token works by combining information that is secret to the site, the action, and the individual user into a hashed value sent in the HTML of the page.

From https://www.drupal.org/node/2319205

---
Tags: 9, security, csrf
---


# Question
Title: How do I access the parameters fields of hook_mail_alter(&$message)?
I am using hook\_mail\_alter in drupal 8 to alter the email messages sent through contact form . How can I access `$message['params']` fields in `hook_mail_alter()`?

I am getting the following values with `print_r(array_keys($message['params']));`.

```
Array (
  [0] => contact_message
  [1] => sender
  [2] => contact_form
)

```

Can anyone suggest how I access the contact form fields?

When I access the values with `print_r($message['params']['contact_form']);die;` I don't get anything displayed.

# Answer
> 4 votes
The message entity is stored in `$message['params']['contact_message']` and it contains all the values from the contact form. Given that it's an entity of type `contact_message`, you can operate with `get()` method to get the values of any field that your contact message might have. Example:

```
/**
 * Implements hook_mail_alter().
 */
function mymodule_mail_alter(&$message) {
  if (isset($message['id']) && $message['id'] == 'contact_page_mail') {
    /** @var \Drupal\contact\Entity\Message $contact_message */
    $contact_message = $message['params']['contact_message'];
    // Get sender's name.
    $sender_name = $contact_message->getSenderName();
    // Get sender's mail.
    $sender_mail = $contact_message->getSenderMail();
    // Get subject.
    $subject = $contact_message->getSubject();
    // Get message.
    $message_body = $contact_message->getMessage();
    // Get the value of "field_request" field.
    $request_value = $contact_message->get('field_request')->getValue();
  }
}

```

# Answer
> 0 votes
The original post assumes the use of the "Contact" module, but for a more generic solution (for example, for user account registration/activation emails), you can access user account information via the 'account' element:

```
/**
 * Implements hook_mail_alter().
 *
 * Modify outgoing emails.
 */
function mymodule_mail_alter(&$message) {
  switch ($message['id']) {
    case 'user_register_pending_approval':
      $field_data = $message['params']['account']->get('field_example')->getValue();
      // do something with $field_data in $message['body']
      break;

    case 'user_status_activated':
      if ($message['params']['account']->hasRole('content_editor')) {
        // do something with $field_data in $message['body']
      }
      break;
  }
}

```

---
Tags: 8, emails
---


# Question
Title: pattern name for override view templates
Twig template - `views-view-unformatted.html.twig` contains :

```
#}
{% if title %}
<h3>{{ title }}</h3>
{% endif %}
{% for row in rows %}
{%
set row_classes = [
default_row_class ? 'views-row',
]
%}
<div{{ row.attributes.addClass(row_classes) }}>
{{ row.content }}
</div>
{% endfor %}

```

I want to insert a `<hr>` tag after each `</div>`:

```
<div{{ row.attributes.addClass(row_classes) }}>
{{ row.content }}
</div>
<hr>
{% endfor %}

```

It works, but for all and every `{{ row.content }}`. I want to do it **only for certain views-blocks**. Twig debugging offers me to theme a whole block (for example: `block--views-block--news-left-block-1.html.twig`) and I need something like views-view-unformatted--news-left-block-1.html.twig or some other way to insert the tag.

what is the correct filename to override view template?

Thank you.

# Answer
Just use `views-view-unformatted--(your view block name).html.twig`. Eg. If your view name is Slideshow, use views-view-unformatted--slideshow.html.twig

This is a good reference point - http://redcrackle.com/blog/drupal-8/theme-views-templates
> 8 votes

# Answer
The pattern for override view template is

views-view-DISPLAYNAME--VIEWS\_MACHINENAME--DISPLAY\_MACHINENAME.html.twig

if you don't consider *--DISPLAY\_MACHINENAME* the template will be used for all displays on *VIEWS\_MACHINENAME* view.

in your case

**DISPLAYNAME =** unformatted
**DISPLAY\_MACHINENAME =** news-left
**DISPLAY\_MACHINENAME =** block-1

So your file pattern is

```
 views-view-unformatted--news-left.html.twig

```

or

```
views-view-unformatted--news-left--block-1.html.twig

```

**Note :** if your machine name contain "\_"(underscore) convert all of them to "-".
> 6 votes

# Answer
**Update if you're on Drupal 9**

Twig **doesn't** seem to use the templates named with with a hyphen in place of underscores.

If:

* View Format = unformatted
* View Machine Name = my\_view
* View Page/Block Machine Name= myviewpage

This appears to be the file that twig uses:

```
views-view-unformatted--my_view.html.twig

```

It ignores the following even if they exist:

```
views-view-unformatted--my_view--myviewpage.html.twig
views-view-unformatted--my-view--myviewpage.html.twig
views-view-unformatted--my-view.html.twig

```
> 0 votes

---
Tags: views, theming, 8
---


# Question
Title: What is good way to hide update.php file?
I will like to know what is the correct/better way to hide update.php file on the production server.

Currently when you try to access update.php file, Drupal shows default access denied page with info about how to edit settings.php file which I think is bit more revealing than is required.

Any suggestions or best practices ?

# Answer
You can add the following line:

```
RewriteRule ^update.php$ - [R=404,NC,L]

```

to your `.htaccess` file so the web server returns a 404 rather than bootstrapping Drupal to show access denied.
> 4 votes

# Answer
Also you can make the variable `$update_free_access = FALSE;` so with out admin login you are not able to access it. It is `FALSE` by default. or you can manage it from setting.php. I do not recommend that you should hide it because drupal release security update as required, so when you update your module or core drupal, you need the `update.php`. Hope this will help you out.
> 1 votes

# Answer
Block update.php except from \[YOUR\_IP\]: Put into .htaccess:

```
RewriteCond %{REQUEST_URI} ^/update.php
RewriteCond %{REMOTE_ADDR} !=[YOUR_IP]
RewriteRule .* - [F]

```
> 0 votes

# Answer
Add below code in .htacces file in website root directory to restrict access to below files in production.

```
<FilesMatch "(^API|CHANGELOG|COPYRIGHT|INSTALL|LICENSE|PATCHES|MAINTAINERS|README|TODO|UPGRADE|UPDATE|CHANGES|install|update|authorize).*\.(md|txt|php)$">
  Order deny,allow
  Deny from all
</FilesMatch>

```
> 0 votes

# Answer
In **Drupal 7** set `$update_free_access = FALSE` in your settings.php file. This is the default. Performing database updates via `drush updb` is not affected by that.

> ```
> /**
>  * Access control for update.php script.
>  *
>  * If you are updating your Drupal installation using the update.php script but
>  * are not logged in using either an account with the "Administer software
>  * updates" permission or the site maintenance account (the account that was
>  * created during installation), you will need to modify the access check
>  * statement below. Change the FALSE to a TRUE to disable the access check.
>  * After finishing the upgrade, be sure to open this file again and change the
>  * TRUE back to a FALSE!
>  */
> $update_free_access = FALSE;
>
> ```

Since **Drupal 8** set `$settings['update_free_access'] = FALSE` in your settings.php file. This is the default. Performing database updates via `drush updb` is not affected by that.

> ```
> /**
>  * Access control for update.php script.
>  *
>  * If you are updating your Drupal installation using the update.php script but
>  * are not logged in using either an account with the "Administer software
>  * updates" permission or the site maintenance account (the account that was
>  * created during installation), you will need to modify the access check
>  * statement below. Change the FALSE to a TRUE to disable the access check.
>  * After finishing the upgrade, be sure to open this file again and change the
>  * TRUE back to a FALSE!
>  */
> $settings['update_free_access'] = FALSE;
>
> ```
> 0 votes

---
Tags: security, .htaccess, configuration
---


title: In which table is a path alias stored?

text:
# Question
Title: In which table is a path alias stored?
I need to make a query to get the path alias used for a node. In which table is it stored?

# Answer
> 5 votes
They're in the aptly named `url_alias` table, but you shouldn't query it directly. The path alias manager service is preferable:

```
$alias = \Drupal::service('path.alias_manager')
    ->getAliasByPath("/node/$nid");

```

As always, inject the service if you can.

# Answer
> 1 votes
There is a `url_alias` table in the database that holds source and alias records.

# Answer
> 1 votes
For drupal 8 there is a table `path_alias` that holds source and alias records.

# Answer
> 1 votes
The url alias field is stored in the “path\_alias” table, and when querying, you can retrieve the data you are looking for based on the table field path.

---
Tags: database
---


# Question
Title: How to get the valid URL of a Link field from within a Twig template?
I have a Link field named `field_my_link` (machine name).

Within a Twig template I can get the link's URL value with this:

```
{{ node.field_my_link.uri }}

```

If inside the Link's URL there is an *external* URL, e.g. `http://example.com` it works good.

But, if inside the Link's URL there is stored an *internal* URL, e.g. `"/node/11"`, I get a value like this:

```
"internal:/node/11"

```

with the "`internal:`" prefix.

How can I get the *valid* URL?

For example, if the link's URL is "`http://example.com`" I want "`http://example.com`" (this already works), if the link's URL is "`/node/11`" I want the relative URL "`/node/11`", if the link's URL is "`<front>`" I want the URL "`/`", etc.

---

**EDIT**

I can get the value I want within a PHP preprocess function, using this:

```
$url = $variables['node']->get('field_my_link')->first()->getUrl();

```

How can I access the same value within the Twig template?

I know I can do this within the preprocess function:

```
$variables['my_url'] = $url;

```

Then access the url within Twig using `{{ my_url }}`, but I would avoid to write a preprocess function each time I have a link field.

# Answer
> 68 votes
Your PHP from your latest edit would translate into twig like this:

```
{{ node.field_my_link.0.url }}

```

This works like this, `0` returns the first item of the field item list, `url` gets the url object and because twig will cast this object as a string this will call the magic method toString() and will output the url as a string value.

You only need to use `url`, because twig looks automatically for the method `getxyz()` if there is no property with that name `xyz`.

# Answer
> 30 votes
You can access the render array element directly, in your case:

```
{{ node.field_my_link[0]['#url'] }}

```

# Answer
> 24 votes
You have to cover both cases: external and internal URLs.

First let's check if the URL is **external** and simply print its `*.uri`.

Else if it's **internal** we have to wire its route name and parameters through Drupal's `path($name, $parameters, $options)` function.

```
{% if node.field_link.0.url.external %}
  <a href="{{ node.field_link.uri }}">
    {{ node.field_link.title }}
  </a>
{% else %}
  <a href="{{ path(node.field_link.0.url.routeName, node.field_link.0.url.routeParameters) }}">
    {{ node.field_link.title }}
  </a>
{% endif %}

```

# Answer
> 19 votes
I had to do this on a Link Field in a Block. This worked well:

```
{{ content.field_my_link[0]['#url']|render }}

```

# Answer
> 16 votes
you can also use something like the following, it all depends of the type of object you are extracting and the field name, In my case it was a paragraph with a field named field\_link and the following worked:

```
{{ paragraph.field_link.get(0).getUrl().toString() }}

```

# Answer
> 11 votes
I know it's an old post but with the last version of Drupal 8 (8.6) you can directly display the url for both version (external and internal):

```
node.field_link.0.url

```

And if you need to know if the link is external or not (for my case it was for the target), you can use that:

```
node.field_link.0.url.external

```

Example:

```
<a href="{{ node.field_link.0.url }}" title="Title" target="{{ node.field_link.0.url.external ? '_blank' : '_self' }}"

```

# Answer
> 4 votes
In paragraph, to get the link url and link name -

```
<a href="{{ content.FIELD_LINK_NAME[0]['#url']|render }}">
   {{ content.FIELD_LINK_NAME[0]['#title']|render }}
</a>

```

# Answer
> 2 votes
Following on from a previous answer - Twig tweak is my goto for future proofing some of the cryptic syntax used in the past.

{{ node.field\_link\_to\_purchase | file\_url }} - this work for me on the latest version at the time of writing.

# Answer
> 1 votes
I *know* it's horrible, but if nothing else works:

`{{ link|replace({'internal:':''}) }}`

**My situation**: accessing a Link field via an overridden views template: `views-view-fields.html.twig`

I had to get the variable from:

`row._entity.field_machine_name.value.0.uri`

(I gave up trying to use the `fields` variable, you can seemingly get a *.content* property out of that, but not much else)

*….field\_machine\_name.value* is just a flat array, which only has a `uri` key, NOT `url`, and the filters mentioned in other answers (toString(), render etc.) simply don't seem to work here.

# Answer
> 1 votes
Here's another way to do this. This example exclude the use of the Title field.

```
{% set link_url = content.field_link.0['#url'] %}
{% set link = link_url ? link_url : content.field_link.0['#title'] %}

{% if link %}
  {{ link.toString() }}
{% endif %}

```

Possible results

```
# Input ---------------- Output -----------
# This is a node (23)    /relative/url
# <front>                /
# https://drupal.org     https://drupal.org

```

# Answer
> 1 votes
Actually there is much simpler solution using https://www.drupal.org/project/twig\_field\_value module

```
<a href="{{ content.FIELD_LINK_NAME|field_value|first['#url']|render }}">
  {{ content.FIELD_LINK_NAME|field_value|first['#title'] }}
</a>

```

This will work for both internal and external links.

# Answer
> 1 votes
I needed to add some classes to my link. field\_url is a link field. I didn't have *content* in the Twig context.

`{{ node.field_url[0] }}` gives me a \Drupal\Core\Url object.

`{% set link = node.field_url[0] | view %}` This is a filter from the Twig Tweak module. It returns a render array.

I can now output my link like this:

```
<a href="{{ link['#url'] | render }}" class="featured-link featured-link--small">{{ link['#title'] | render }}</a>

```

Twig tweak is amazing. Here is a link to the cheat sheet where you can see all the functionality.

# Answer
> 1 votes
I'm using mix of the next solutions for wrap content in a link within paragraph entity and to add target attribute:

```
{% set link = paragraph.field_link.get(0) %}
{% set url = link.getUrl().toString() %}

{# prevent having urls built from special types "<button>", "<nolink>", but allow "<front>" #}
{% if url %}
  <a href="{{ url }}" target="{{ link.url.external ? '_blank' : '_self' }}">
{% endif %}
    content here...
{% if url %}
  </a>
{% endif %}

```

# Answer
> 0 votes
**Supplementary answer**

The answer above can be applied to a Drupal Paragraph:

```
{{ node.field_link.0.url }}

```

...if you replace the entity type `name` node with `paragraph` as so:

```
{{ paragraph.field_link.0.url }}

```

Where in your site, you would have created a Paragraph with a field called link - which would have machine name field\_link.

I found that the above `{{ paragraph.field_link.0.url }}` renders to the URL when used link this:

```
<a href="{{ paragraph.field_link.0.url }}">{{ paragraph.field_link.0.title }}</a>

```

This works for both internal and external URLs. I tested:

* `#our-team` \- a URL fragment for use with an `<a` anchor
* `https://bbc.co.uk`

I have defined in the paragraph instance I added in a entity reference node - the usual process for adding paragraphs, of course.

For my purpose, I wanted to create a Call-to-action (CTA) button, using a paragraph, here is all my code below to do that, which illustrates how I've used the twig link and title.

I enclose the whole paragraph markup with the with `<a href="{{ paragraph.field_link.0.url }`... ...`/>`

And put the link text, the `title` inside: `{{ paragraph.field_link.0.title }}`

file:

```
web/themes/custom/my_theme/templates/paragraphs/paragraph--call-to-action.html.twig

```

code:

```
{%
  set classes = [
    'paragraph',
    'paragraph--type--' ~ paragraph.bundle|clean_class,
    view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
    not paragraph.isPublished() ? 'paragraph--unpublished'
  ]
%}
{% block paragraph %}

  <div class="mysite-cta-outer">
  <a href="{{ paragraph.field_link.0.url }}">
    <span{{ attributes.addClass(classes).addClass('mysite-cta-fixed') }}>
      {% block content %}
        {{ paragraph.field_link.0.title }}
      {% endblock %}
    </span>
  </a>
  </div>

{% endblock paragraph %}

```

file:

```
web/themes/custom/my_theme/css/styles/_cta.css

```

code:

```
.mysite-cta-outer {
  padding-top: 1.0em;
  padding-left: 1.5em;
}

.field--name-field-main-call-to-action-area {
  margin-bottom: 5em;
}

.mysite-cta-fixed {
  border-radius: 0.5em;
  border: 0.2em solid;
  padding-top: 0.8em;
  padding-bottom: 0.8em;
  width: 15em;
  color: white;
  display: inline-block;
  text-align: center;
}

span.mysite-cta-fixed a
{
  text-decoration: none;
  color: white;
}

span.mysite-cta a
{
    text-decoration: none;
    color: white;
}

.mysite-cta {
  border-radius: 0.5em;
  border: 0.2em solid;
  padding-top: 0.8em;
  padding-bottom: 0.8em;
  padding-left: 2em;
  padding-right: 2em;
  color: white;
  display: inline-block;
}

```

Also, a comment about, `url` vs `uri` as this has been talked about in other answers. For me, as you can see from my code, url is what I use, in the `<a href="{{ paragraph.field_link.0.url }}">`...

`vardumper` util (from Drupal module `twig_vardumper` ) shows the following for `url` and `url`:

`{{ vardumper( paragraph.field_link.0.url ) }}`

* output :-

^ that initially put me off using `url` because it was a `Url` class and not text which I assumed had to be output but it is the right one for outputting the URL. So what seems to happen is that twig renders this Url object as text automatically.

And here's `uri` output

`{{ vardumper( paragraph.field_link.0.uri ) }}`

output:-

```
^ "internal:#our-story"

```

Which I didn't use for aforementioned explanation.

This took me a few hours for troubleshooting so I'm grateful for the other answers here, though a bit despairing that there are multiple ways to do it, which potentially causes confusion, also somewhat demoralising to spend a lot of time on something so small. The 'dot' notation here is still something mysterious to me as to how to use it fully, and it shouldn't be. I hope to encounter a definitive guide to get results quickly with this. These answers here do help in the meantime!

---
Tags: theming, 8, uri, navigation
---


# Question
Title: Add tab for custom entity type on content page
I made a custom entity type and I'd like it added to the tabs on the content page seen below.

My custom\_entity.links.menu.yml Looks like this

```
entity.custom_entity.collection:
  title: 'Custom Entities'
  route_name: 'entity.custom_entity.collection'
  description: 'List Custom Entities'
  parent: system.admin_content
entity.custom_entity.add_form:
  title: 'Add Custom Entity'
  route_name: 'entity.custom_entity.collection'
  description: 'Add custom entity'
  parent: entity.custom_entity.collection
custom_entity.admin.structure.settings:
  title: 'Custom Entity Settings'
  description: 'Configure Custom Entity'
  route_name: 'custom_entity.settings'
  parent: system.admin_structure

```

And it does display the custom entity pages in the admin menu but it does not appear amongst the tabs on the content page. Is there a separate yml file that governs that?

# Answer
Those tabs called "local tasks." See Providing module-defined local tasks on d.o.

In the simplest case you can define your local tasks in a yaml file:

```
# example.links.task.yml

example.admin: # The first plugin ID
  route_name: example.admin
  title: 'Settings'
  base_route: example.admin

example.admin_3rd_party: # The second plugin ID
  route_name: example.admin_3rd_party
  title: 'Third party services'
  base_route: example.admin
  weight: 100

```

But, it's also possible to define dynamic local tasks.

Per @Matt in the comments, if you want to place this as a tab on the /admin/content page, use `base_route: system.admin_content`.
> 4 votes

---
Tags: entities, 9
---


# Question
Title: How can Commerce Stores be imported with Feeds?
I'm trying to set up a feed to import Commerce store entities.

I installed the Feeds module and the Commerce Feeds module.

I then created a CSV file feed with the following mappings:

* Name: The store name
* Email: Store email notifications
* Currency: Default currency
* Timezone: Store timezone

However, when I try to import the feed, I get an error:

> Address (address): This value should not be null. Please check your mappings.

This makes sense because I did not set a mapping for the address.

However, in the mappings, I don't see any option for the address:

Feeds has support for Address fields, so what do I need to do to set the store entity address field?

# Answer
> 1 votes
At present, there is no support for importing stores with Feeds or Commerce Feeds. I made a feature request in the Commerce Feeds issue queue.

In the meantime, I set up a feed type for importing Commerce stores that uses mappings for every field except address (because there is no support for address).

I want to be able to update my stores, so I am now using this feed to update them, but creating the store entities manually in `hook_module_update()` as shown below.

```
use \Drupal\commerce_store\Entity\Store;

MYMODULE_update_9001() {
  // The default address value to use.
  $address_default = [
    'country_code' => 'JP',
    'administrative_area' => 'Tokyo',
    'locality' => 'Place',
    'postal_code' => '111-1111',
    'address_line1' => 'Someplace',
    'address_line2' => 'Somewhere',
  ];

  // Find the ID for the store feed type that we want to use to update this store.
  $store_feed_id_query =
 \Drupal::entityQuery('feeds_feed')
    ->condition('type', 'store_feed_type_machine_name');
  $store_feed_result = $store_feed_id_query->execute();
  $store_feed_id = 0;
  if (isset($store_feed_result)) {
    // Need to iterate through the results; there should only be one result, but if there are multiple, take the most recent.
    foreach ($store_feed_result as $only_result) {
      $store_feed_id = $only_result;
    }
  }
  if ($store_feed_id > 0) {
    $store = Store::create([
      'type' => 'store_type_machine_name',
      'name' => 'My Awesome Store',
      'mail' => 'store@example.com',
      'default_currency' => 'JPY',
      'address' => $address_default,
      'timezone' => 'Asia/Tokyo',
      'is_default' => 1,
      'path' => '/store',
      'uid' => 2,
    ]);
    $store->feeds_item->target_id = $store_feed_id;
    $store->feeds_item->guid = 'my-store-id'; // Optional, only set if you are using GUID to make your feed unique.
    $store->save();
  } else {
    throw new \Exception("Failed to get store feed id: $store_feed_id");
  }
}

```

Note that in my mappings for the **Feeds Item** field, I have set **GUID** to be the unique value. This allows me to use my feed type to update the store values. More information on working with Feed Items programmatically.

---
Tags: commerce, feeds
---


# Question
Title: How do I import/add terms to content without removing the existing ones?
currently when importing term with feeds all the existing term of of a content are removed and then the terms are imported.

Is there a way to add terms during an import and keep the existing ones?

# Answer
> 0 votes
In processor settings, make sure you select "Update existing content items" and not "Replace ..."

---
Tags: feeds
---


# Question
Title: How does importing a contrib module's translations work?
Drupal version: 9.3.13

Basically, I'm trying to understand how using a contrib module's translation works. I want to be able to download and use the translations from the Drupal infrastructure, and can't seem to get this to work.

I have a site with two languages, English and German (Default). I did run "drush locale-check" and "drush locale-update", and that imported the German core language file (which now is saved at "web/sites/default/files/translations/drupal-9.3.13.de.po"). If the current interface language is German, I do see all kinds of core features translated to German.

Active modules:

* Configuration Translation
* Interface Translation
* Language

I then installed a module, first loading it via composer and then installing it via the "admin/modules" page. I made sure that a string of the module was used in a page, that this string is translated on localize.drupal.org for the current version of the module and that it showed up under "admin/config/regional/translate" as untranslated afterwards. Then I ran both the translation commands again. The output says, that translations for one project were checked and that nothing was changed. No translation showed up for my test string.

I just tested this on a fresh Drupal installation with the "drupal/cookies" module (version 1.0.18, https://www.drupal.org/project/cookies). The module's page on localize.drupal.org shows lots of translated Strings: https://localize.drupal.org/translate/languages/de/translate?project=cookies&status=2&release=531668&search=&author&context=all&limit=10&sid=0

What I am aware of:

* My own custom modules use .po files, and those are loaded just fine.
* There seems to be a bug that causes new versions of modules not being picked up (https://www.drupal.org/project/drupal/issues/2575945). That is also bad, but here no translation for the module is loaded in the first place.

I tried to debug this and got as far as checking "locale.project" and "locale.translation\_status" from the "key\_value" table. Both only contain Drupal core on my test site. In the production site, all the custom modules are also contained, but none of the contributed modules.

So the question is: What am I missing here? How is this supposed to work?

# Answer
After much debugging I solved this issue by comparing Drupal's behavior with a completely fresh installation. Of course "drush locale-update" is supposed to get translations for contrib modules!

What happened here was this line in the composer.json:

```
"config": {
     "discard-changes": true,
     "preferred-install": "source",
     "sort-packages": true
},

```

The offending line is **"preferred-install": "source"**. This was committed some time ago, nobody knows why and it gets composer to checkout the code from git instead of downloading the zip file from Drupal.

This doesn't make much difference, except that Drupal normally adds information to the info.yml file of the modules:

```
# Information added by Drupal.org packaging script on 2021-04-02
version: '8.x-1.2'
project: 'foobar'
datestamp: 1617351415

```

With a git checkout, this is missing! And when Drupal later checks for translations, it goes through all modules and tries to get the project name. Apparently, in Drupal projects are translated, not individual modules. Some modules contain lots of sub-modules, which all share the same project name and therefore the same translation base. Since all my contrib modules came from git rather than from the enhanced zip file, this meant that Drupal skipped them all on "drush locale-update"! No information about this was output, they were simply quietly skipped.

The solution for me was to change the offending line to this:

```
"preferred-install": {
    "drupal/*": "dist",
    "*": "source"
},

```

Also note that you need to delete the modules from web/modules/contrib and reinstall them via composer. Just changing the above and running "composer install" is not enough!
> 2 votes

---
Tags: i18n-l10n
---


# Question
Title: How can I load a migration in a KernelTest?
I'm trying to test a migration with a KernelTest, but I'm running into an issue when I try to load the migration plugin.

My migration is defined in *my\_module/migrations/my\_migration.yml*. In my KernelTest, I've listed `my_module` and `migrate` in the `$modules` static property.

In a custom form, I use the following to load a migration plugin:

```
/** @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface $plugin_manager */
$plugin_manager = \Drupal::service('plugin.manager.migration');
$migration = $plugin_manager
  ->createInstance('MY_MIGRATION');
// Next, create MigrateExecutable, etc...

```

However, when I use this same code in my KernelTest, `$migration` is always `FALSE`. I feel like this is because my migration is not loaded (?) when I enable my module in the test, but I'm not sure what to do about it. What am I missing here? How can I load my migration in the test?

# Answer
> 0 votes
The migrate module provides a base Kernel test class, `Drupal\Tests\migrate\Kernel\MigrateTestBase`, which has a `getMigration()` method baked in.

For example, this works and the test passes:

```
<?php

namespace Drupal\my_module\tests\Kernel;

use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\Tests\migrate\Kernel\MigrateTestBase;

class MyMigrationTest extends MigrateTestBase {

  protected static $modules = [
    'my_module',
    'migrate',
    // etc...
  ];

  public function testMigration(): void {
    $migration = $this->getMigration('MY_MIGRATION');

    $this->assertInstanceOf(MigrationInterface::class, $migration);
  }

}

```

---

However, it's not necessary to extend *MigrateTestBase*, this also works and test passes:

```
<?php

namespace Drupal\my_module\tests\Kernel;

use Drupal\KernelTests\KernelTestBase;
use Drupal\migrate\Plugin\MigrationInterface;

class MyMigrationTest extends KernelTestBase {

  protected static $modules = [
    'my_module',
    'migrate',
    // etc...
  ];

  public function testMigration(): void {
    /** @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
    $plugin_manager */
    $plugin_manager = \Drupal::service('plugin.manager.migration');
    $migration = $plugin_manager
      ->createInstance('MY_MIGRATION');

    $this->assertInstanceOf(MigrationInterface::class, $migration);
  }

}

```

---
Tags: migrations, testing
---


# Question
Title: How to get the field name in a validation handler?
I have a custom `class TextWidget extends WidgetBase`

Inside it I have a custom validation handler that looks like this:

```
public function validate($element, FormStateInterface $form_state) {
  $value = $element['#value'];
  $label = 'This field'; // What method is there to get the human facing field name?
  if (strlen($value) === 0) {
    $form_state->setError($element, $this->t('@label cannot be empty.', ['@label' => $label]));
  }
}

```

It outputs the error "This field cannot be empty." if the field is empty.

I want to replace the static text 'This field' with the actual human facing name of the field.

Is there a public method that lets me do that?

# Answer
> 7 votes
A class that extends `WidgetBase` can get the label with `$this->fieldDefinition->getLabel()`. That is used, for example, from `WidgetBase::form()`.

```
$element = [
  '#title' => $this->fieldDefinition->getLabel(),
  '#description' => $this->getFilteredDescription(),
];

```

---
Tags: 9
---