# Question
Title: buildForm: how differentiate between page reload and ajax callback?
I'm building a custom form in Drupal 9, which has some ajax callbacks.

During the `buildForm` I need to load some extra data via a rest call to an external service, which then I put inside a `private_tempstore` variable.

I'd like to avoid to call the rest end-point during the ajax callbacks, and rely on the stored variable.

However, I can't find a way to differentiate between the "load page" case and the "ajax case". Is it possible?

I've found this answer that seems to generally work:

> ```
> // Example for brevity only, inject the request_stack service and call
> // getCurrentRequest() on it to get the request object if possible.
> $request = \Drupal::request();
> $is_ajax = $request->isXmlHttpRequest();
>
> ```

But I'd like to know if there's some helper\solution using the form API.

# Answer
Since Drupal 8 the form object instantiated with buildForm() is not preserved between the request rendering the form and the first Ajax request. So be prepared that buildForm() is called again and has to produce the exact same result. When you get data from $form\_state this is not the data you expect from the first buildForm() because this is never cached. Adding to the complexity the rendered result of the first build is cached, so what you store in the first build elsewhere, for example in tempStore, might be outdated in the Ajax request. The only data which works as expected are form values, which can be hidden if you want to have them in the submitted form and not visible to the user.

TLDR: buildForm() is called more often than you think and you shouldn't put code in it which is expensive to run. Refactor the external API call to a service, with proper caching, so that it doesn't matter how often it is called. Invalidate the service cache the same way as the rendered form, so that neither of them has outdated data.
> 5 votes

---
Tags: forms, ajax
---


title: Unable to pull image inside twig file

text:
# Question
Title: Unable to pull image inside twig file
I am trying to show image via view twig file and below is my lin eof code:

```
<img width="220" height="112" src="{{ file_url(content.field_thumbnail_new[key]['#item'].entity.uri.value )}}" alt="{{ item.alt }}" />

```

When inspecting, I see the below:

any help on how this can be fixed pls?! I am using D9.

# Answer
> 1 votes
I would recommend to use https://www.drupal.org/project/twig\_tweak module.

```
<img src="{{ drupal_field('field_thumbnail_new', 'node', node.id, {type: 'image_url', settings: {image_style: 'YOUR_IMAGE_STYLENAME'}}) }}"  />

```

---
Tags: views, theming, 9
---


# Question
Title: Set the menu link description in hook_entity_presave()
How do I update the menu link description with `hook_ENTITY_TYPE_presave()`?

I can print out the menu link title and menu link description with the following code.

```
kint($entity->menu['title']);
kint($entity->menu['description']);

```

I only want to update the menu link description when the menu link title is not NULL so the menu link will exist. In fact, I'm wanting to copy the menu link title into the menu link description (when the menu link title is not empty).

The following code updates the node title, but I would like to know how to update the menu link description.

```
/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {

  if ($entity->bundle() == 'page') {

    // save a different value as title
    $entity->title = 'New Title';

    // The below outputs the 'title' and 'description' of the menu link
    kint($entity->menu['title']);
    kint($entity->menu['description']);

    // how do I update the menu description?
    // the below doesn't work?
    $entity->menu['description'] = "New menu link description";

  }
}

```

# Answer
Menu links are entities themselves. Unless you've done something special to create a new menu link entity type, they will be entity type menu\_link\_content.

You can use hook\_ENTITY\_TYPE\_presave() to make your change. Note that when you see an all-caps section of a hook, that means it should be replaced by a specific value, e.g. hook\_node\_presave() or hook\_menu\_link\_content\_presave(). The difference between these and hook\_entity\_presave() is that the latter will fire when **any** entity is saved, while the entity type specific hooks will only fire when an entity of that specific type is saved.

Given all of this, something like the following should work:

```
// Top of file.
use Drupal\menu_link_content\MenuLinkContentInterface;

/**
 * Ensure that any menu link with a title has a description that matches.
 *
 * Implements hook_ENTITY_TYPE_presave().
 */
MY_MODULE_menu_link_content_presave(MenuLinkContentInterface $menu_link) {
  if (!$menu_link->title->isEmpty()) {
    $menu_link->set('description', $menu_link->title->value);
  }
}

```
> 0 votes

---
Tags: 8, entities, hooks
---


# Question
Title: Custom form password validation / strength enforcement
I have a custom form that would create user. The form is rendered with Form API and is using PasswordConfirm element, but it doesn't seem to validate the password against the default password rules (e.g. number of characters, combinations of characters).

How do I apply the default Drupal password rules to my custom form's password confirm field in the form validation method?

# Answer
> 2 votes
Built in is only recommendation. But there are several contrib modules like https://www.drupal.org/project/password\_policy

Use such a module.

If you have created your own custom form, just use the usual

> public function validateForm(array &$form, FormStateInterface $form\_state)

method to implement your rules.

---
Tags: 8, forms
---


title: How to replace default value of field?

text:
# Question
Title: How to replace default value of field?
I have a custom module.

This is form\_alter function:

```
 $form['article'] = [
    '#type' => 'textfield',
    '#weight' => -1,
    '#title' => t('Search Product from Magento: '),
    '#autocomplete_route_name' => 'magento_drupal.autocomplete',
    '#ajax' => [
      'callback' => '_select_ajax_form',
      // 'wrapper' => 'my_unique_id',
    ],
  ];

```

In the `_select_ajax_form` function, how can I automatically fill in the data for the field 'price' and 'sku'?

`price` is Number (integer) and `sku` is Text (plain, long).

# Answer
> 0 votes
If you don't have a huge backend logic for the auto-fillins, you may do it with much more simple javascript in the "#attributes" value. Here's a sample of my code:

```
$form['laufzeit_in_monaten'] = [
      '#type' => 'number',
      '#title' => $this->t('Laufzeit in Monaten ('.$produkt->get('min_stk')->value.' - '.$produkt->get('max_stk')->value.')'),
      '#default_value' => floor($produkt->get('max_stk')->value/2.0),
      '#attributes' => array('onchange' =>
        'document.getElementById("vollpreis").innerHTML = (document.getElementById("edit-laufzeit-in-monaten").value * document.getElementById("pprc").value).toFixed(2)'),
    ];

```

But this is only frontend. You obviously need to validate the input later in your backend.

---
Tags: 9
---


# Question
Title: How to expose custom webform fields to GraphQL?
I would like to use https://www.drupal.org/project/captcha with Webforms. For exposing Webforms via GraphQL I use https://github.com/duartegarin/graphql\_webform.

As CAPTCHA is not a standard field https://github.com/duartegarin/graphql\_webform does not expose it via GraphQL. As I did not find any documentation on how to expose custom webform fields to GraphQL I thought I ask about it here.

Thank you.

# Answer
> 1 votes
The CAPTCHA module doesn't implement a webform component. It just adds a form element to the forms for which it has been configured to add its CAPTCHA.

If the CAPTCHA module implemented a webform component, then implementing a few classes (starting from a plugin like `WebformElementPhone`) would allow to integrate the modules together.

```
/**
 * A GraphQL type for textfield form item.
 *
 * @GraphQLType(
 *   id = "webform_element_phone",
 *   name = "WebformElementPhone",
 *   interfaces = {"WebformElementTextBase"},
 * )
 */
class WebformElementPhone extends TypePluginBase {

  /**
   * {@inheritdoc}
   */
  public function applies($object, ResolveContext $context, ResolveInfo $info) {
    return $object['plugin'] instanceof Telephone;
  }

}

```

---
Tags: webforms
---


# Question
Title: Drush issue duplicating includes/ directory
Using drush either globally or with a composer installed version, I get this double includes showing up in my fatal error (/includes/includes/):

> include\_once(/srv/www/htdocs/sites/drupal/includes/includes/entity.inc): failed to open stream: No such file or directory bootstrap.inc:3492 \[warning\] include\_once(): Failed opening '/srv/www/htdocs/sites/drupal/includes/includes/entity.inc' for inclusion (include\_path='.:/opt/php7.3/lib') bootstrap.inc:3492 \[warning\] Drush command terminated abnormally due to an unrecoverable error. \[error\] Error: Class 'DrupalDefaultEntityController' not found in include\_once() (line 300 of /srv/www/htdocs/sites/drupal/modules/user/user.module).

Anyone ever see this before or have any ideas on why this is happening?

The site is located in the /drupal directory.

# Answer
I think you might want to use Registry Rebuild to fix this, as it's most likely a problem with a borked registry.
> 3 votes

---
Tags: 7, drush
---


# Question
Title: Why does installing from an existing configuration fail?
I am struggling to install a drupal site from an existing configuration. Here the two approaches I tried:

**OPTION 1: Import the config by changing the UID:**

* `drush cex` on existing site
* `drush site:install` to install new site
* `drush cset system.site uuid 478e7e74-fea3......` to set UUID on new site equal to exisiting site
* `drush cim` on new site

**RESULT:**

```
  The import failed due to the following reasons:

  Unexpected error during import with operation delete for taxonomy.vocabulary.tags: Attempt to create a field body that does not exist on entity type node.
  Unexpected error during import with operation delete for shortcut.set.default: Attempt to create a field body that does not exist on entity type node.
  Unexpected error during import with operation delete for contact.form.personal: Attempt to create a field body that does not exist on entity type node.

.... (There are many more of these errors, but I stripped them here for better readability)

```

**OPTION 2: Provide existing config during installation already**

`drush site:install --existing-config` with config from existing site being avilable in config directory of new site.

**RESULT:**

```
The selected profile has a hook_install() implementation and therefore can
not be installed from configuration.

```

# Answer
I think option 1 is more of a hacky workaround than a recommended approach. I would avoid it in favor of option 2.

Re: option 2 failing, the error message is pretty clear - you can't use the `--existing-config` option with a profile that implements an install hook.

From the change record introducing the ability to install from existing configuration:

> If the profile implements hook\_install() configuration install is not supported. This might be addressed in #2982052: Allow an install hook in profiles installing from configuration. Possible workarounds for now are to either change the install profile to minimal or follow option 2 and create a new profile that does not implement the hook.

Drupal 8: Install Site From Existing Configuration walks through how to change your installation to use the minimal profile instead of your current profile. Spoiler: you just need to make two updates to the `core.extension.yml` file in your config directory:

1. Change the `profile` key's value to `minimal`
2. Under the `modules` key, replace your existing profile's key with `minimal`. (Profiles will typically be near the bottom of the list.)
> 4 votes

---
Tags: 8, configuration, installation, installation-profiles
---


# Question
Title: Eliminate results from a relationship (add an ON condition to JOIN)
I need to add an ON condition to a views JOIN. I cannot use a contextual filter, as it will filter out results altogether, and I need to get a result regardless (there are other joins). So I need to ensure the filter happens on the JOIN, and not as a WHERE condition.

To be more specific, I want to show a value when no relationship exists. The relationship is from one NODE type to another NODE of the same type, and I don't want the current node retrieved. So the ON condition should be `AND join_table.id != original_table.id`.

I'm new to altering views queries. Can anyone provide assistance either on how to add an ON condition to a Views query either through the admin UI (if possible) or through a query alter?

Thank you

# Answer
Thanks to help from sonfd above, I was able to come up with a solution of sorts. I was not able to compares the two columns as I was trying to, but I was able to use `$view->args` to come up with the result I wanted.

To answer the question on how to add an additional ON condition to JOIN, you can do the following:

```
function HOOK_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  if ($view->id() == VIEW_ID && $view->current_display === DISPLAY_ID) {
    $table = $query->getTableInfo(TABLE_NME);
    $table['join']->extra = empty($table['join']->extra) ? [] : $table['join']->extra;
    $table['join']->extra[] = [
      'field' => FIELD_NAME,
      'operator' => '!=',
      'value' => VALUE, // In my case $view->args[0],
    ];
  }
}

```
> 4 votes

---
Tags: views, 9
---


# Question
Title: Front and backend public files not found
I'm trying to display some image in my front and my backend, a simple image, not a media, but I'm always receiving a 404.

For example, I'm trying to display the icon from my paragraph, to i'm extracting the URL, but when I call it, I have a 404. Where does this error come from ?

# Answer
Got it, for some reason, the permission of **web/site/default** was this (change to **755**)

> drwxrwx--- 4 vagrant vagrant 4096 juil. 2 15:45 default
> 0 votes

---
Tags: files, 9
---


# Question
Title: Display all the nodes from a specific content type on the front page
I have a custom content type (*news*). I want to show all those nodes on the front page.

How can I achieve this?

# Answer
As Kevin said in the comments, you could try using Views. In order for you to be able to create a new view for your content type, Views UI module should be enabled. After that, you can navigate to Admin/Structure/Views (`/admin/structure/views`), and create a new view.

On the new view creation page you should check under Views settings to show `Content` of type `News`, and on the next section, you can create a page for it with the path of `/news` for example. Then you can add your desired fields to show, with lots of other options like filtering and sorting. **Here** is the user guide on Drupal.org how to do this.

Once you have created the view, you can change your site configuration, to have the `/news` path as your default home page, **if you only want to show the content from this view**. (Configuration/System/Basic site settings - `admin/config/system/site-information`)

If you already have a front page, and you want to show the content of the news content type in a block, you can create a block view by either ticking the checkbox upon the views creation in the section 'Block settings', or by adding a new display on the view configuration page. This way, you would have a block you can place anywhere in your site, by navigating to Structure/Block layout `/admin/structure/block` and adding it to the desired region.

Hope this helps, please read the user guide above for further instructions.
> 0 votes

# Answer
There is a simple way to show content on the front page.

Go to **Admin** -\> **Structure** -\> **Content Types**. (`/admin/structure/types/manage/`)

For your content type *News*, click **Edit**. (You may need to click the flippy triangle next to **Manage fields** to get the **Edit** option.)

Scroll down to **Publishing options**. Make sure **Promoted to front page** is checked.

Note: If you change your front page to something other than the default, this setting may not work depending on what you changed the front page to.
> -1 votes

---
Tags: nodes, 9
---


title: How do I enable breadcrumbs?

text:
# Question
Title: How do I enable breadcrumbs?
I have a page showing a list of *Article* nodes, where I need to display breadcrumbs as *Homepage / Tag title / Article title*, instead of *Homepage / Article title* Drupal uses by default.

I installed the *Menu Breadcrumbs* module, but I don't understand how to display its breadcrumbs. Are they shown in a block?

# Answer
Breadcrumb block relies on URL aliases to build its content. To have your breacrumb display "Home \> Tag title" when you are on your article page, you need your article URL alias to "include" the tag URL alias.

Example:

* In /admin/structure/block, make sure that the Breadcrumbs block is enabled and displayed in a region of your theme,
* Create a "Tag" taxomony term called "Test tag" with "/test-tag" URL alias
* Create an "Article" with "/test-tag/my-article" URL alias
* That's it! Now when you visit "/test-tag/my-article", your breadcrumb block should display "Home \>\> Test tag"

Now, for having your breadcrumbs block display the current page title as well (e.g. "Home \>\> Test tag \>\> My Article"), this is no default configuration and you have to rely either on custom code (see this thread) or a module (https://www.drupal.org/project/current\_page\_crumb for a simple solution or, as leymannx mentioned it, https://www.drupal.org/project/easy\_breadcrumb for a more customizable solution).
> 3 votes

---
Tags: 8, breadcrumbs
---


# Question
Title: How do I automatically fill the subject in the contact forms?
I created 2 types of contact form. I disabled *Subject* in *Manage form*. I want the fake *Subject* field not to be displayed in the contact form, and I want it to be filled in automatically.

How do I automatically fill the subject in the contact forms?

There is nothing in the contact form settings to enter static text in the subject field.

# Answer
If working with Drupal contact forms (and not Webform), it would be something like:

```
  // Replace HOOK with 'yourThemeName' or 'yourModuleName' depending on where you put this code
  function HOOK_form_alter(&$form, FormStateInterface $form_state, $form_id) {
    if($form_id == "your_contact_form_id") {
      $form["subject"]["widget"][0]["value"]["#default_value"] = "Hi, how are you?";
      $form["subject"]["widget"][0]["value"]["#type"] = "hidden"; // Hide field from display
  }

```
> 1 votes

# Answer
Set default value for the form either in settings or you can do it via hook\_form\_alter(). Then set the filed as disabled.
> -1 votes

---
Tags: entities, forms, 9
---


# Question
Title: How do I programmatically set a database connection?
Hello can anybody help with a external Database Connection.

```
$postgis_database = array(
        'database' => $drugis_postgis_connection->getdatabase(),
        'username' => $drugis_postgis_connection->getusername(),
        'password' => $drugis_postgis_connection->getpassword(),
        'host' => $drugis_postgis_connection->gethost(),
        'driver' => 'pgsql',

    );
    Database::setActiveConnection('postgis','default', $postgis_database);
    \Drupal::database();
    $info = Database::getConnection();
    dpm($info);

```

$info is the default connection, i don't know how to connect to 'postgis' connection

# Answer
> 0 votes
`Database::setActiveConnection()` just sets as active connection a connection defined in the settings.php file, or added from a previous call to `Database::addConnectionInfo()`.

The correct code would be the following one.

```
$postgis_database = [
  'database' => $drugis_postgis_connection->getdatabase(),
  'username' => $drugis_postgis_connection->getusername(),
  'password' => $drugis_postgis_connection->getpassword(),
  'host' => $drugis_postgis_connection->gethost(),
  'driver' => 'pgsql',
];

//                          $key      $target
Database::addConnectionInfo('postgis','default', $postgis_database);
//                            $target    $key
Database::setActiveConnection('default', 'postgis');

```

Notice the parameters order in the last two method calls. Notice also the array index order used in the `$database` array set in the settings.php file.

```
//         $key       $target
$databases['default']['default'] = [
  'database' => 'databasename',
  'username' => 'sqlusername',
  'password' => 'sqlpassword',
  'host' => 'localhost',
  'port' => '3306',
  'driver' => 'mysql',
  'prefix' => '',
  'collation' => 'utf8mb4_general_ci',
 ];

```

The connections added with `Database::addConnectionInfo()` aren't permanent; they are added to the static property of the `Database` class. All the functions/methods that want to use the connection defined in `$postgis_database` needs to execute the code I showed before querying the database or saving values in the database.
It's probably better to add the extra connections in the settings.

An error to avoid is calling Drupal functions that query a specific Drupal database table after calling `Database::setActiveConnection('default', 'postgis')`. For example, calling `taxonomy_term_load_multiple_by_name()` after `Database::setActiveConnection('default', 'postgis')` won't work, except in the case the postgis/default database contains a copy of the tables used from Drupal. (Usually, that isn't the case, as a module using a different database isn't going to make a copy of the tables Drupal expects to find, in that database.)
Before calling functions like `taxonomy_term_load_multiple_by_name()`, the code should call `Database::setActiveConnection()`, which restores the active connection to the default one used by Drupal, which is for a database containing all the tables used from Drupal.

---
Tags: database, 9
---


# Question
Title: Automatically have an email sent to page author 11 months after its published date
Hello I was wondering if anybody could help.

I'm using Drupal 8 and for every page that exists I need a custom email to automatically get sent to the page author 11 months after that page was published. It's just to act as a reminder to the author that their page is still published incase they have forgot.

I can't find any info online that outlines exactly what i'm trying to achieve however anything remotely similar I found seems to be using the 'Rules' and 'Scheduler' modules however i'm really not sure how I can achieve what I need to do using them.

Absolutely any help would be amazing, many thanks in advance.

# Answer
> 0 votes
There isn't a scheduler or Rules available for D8/9 anymore which would've made this easy, but you can build a somewhat simple module that creates a cron job, and in that job you can query each piece of content you want to send emails for, check the 'published' date, find out if it was 11 months ago, and if so email the 'author' of the published content. Then set up a local system cron task to run cron once a day.

You'd obviously want to put checks in place to make sure the email only sends once, and that the user still exists. Setting the conditional to check to make sure that it's 11 months to do the day, and only checking once a day should prevent it from sending more than once for each piece of content.

---
Tags: 8, rules
---


# Question
Title: How do I get the current destination URL query parameter?
Does anyone know to how to get the destination in a template file?

At the moment I an getting the destination parameters in a preprocess function.

```
// Get destination params.
$variables['destination_params'] = \Drupal::destination()->getAsArray();

```

The template file uses the following code.

```
<p>
You can try <a href="{{ path('user.login', {}, {'query': destination_params}) }}">logging in</a> to see if you have access.
</p>

```

# Answer
> 5 votes
You can use `path()` function with `'<current>'` pseudo URI to generate current page relative URL.

For example:

```
{# in hard-coded path (bad practice) #}
<a href="/user/login?destination={{ path('<current>') }}" class="btn btn-sm btn-primary icon-before"><i class="fad fa-sign-in"></i> Sign-In</a>

{# more proper twig-like way #}
<p>
You can try <a href="{{ path('user.login', {}, {'query': {'destination': path('<current>') }}) }}">logging in</a> to see if you have access.
</p>

```

More about Drupal's twig built-in functions here: https://www.drupal.org/docs/theming-drupal/twig-in-drupal/functions-in-twig-templates

# Answer
> 0 votes
Adding this here which expands on the answer given here by @MiSHuTka (that answer work perfectly for most scenarios with cache data)

Noting that both answers will not provide any extra query parameters in the `destination` query parameter. (if you wanted them to persist)

Sometimes you need to add the html link to an render array item instead of the template itself to get cache data to work correctly (I believe this has something to do with `#theme_wrappers` and `#theme` on the same render array?). So use `'#type': 'inline_template'` \+ `verbatim` tag to force string, so it be reparsed to bubble cache data.

```
{% set login_link %}
  {# verbatim used to force a string, so it can be reparsed as twig later on, keeping cache metadata in the correct context #}
  {% verbatim  %}
    <a href="{{ path('user.login', {}, {'query': {'destination': path('<current>')} }) }}">{{ 'Login'|t }}</a>
  {% endverbatim %}
{% endset %}

{% set extra_render = {'#type': 'inline_template', '#template': login_link} %}

```

Use like so:

```
{% extends "field.html.twig" %}
{% for key, item in items %}
    {# Add markup to the the render array - assume `extra_render` variable. #}
    {% set item_content = item.content|merge( {'extra_render': extra_render} ) %}
    {% set item = item|merge({'content': item_content }) %}
    {# Prepend to render array #}
    {% set items = {(key): item} + items %}
  {% endfor %}

```

Edit: I have noted that for some reason. If variable is printed via twig white space control `{{- render_var -}}` then the `verbatim` string is not rendered, just printed as is. (regular set/end set works fine but renders too early of course for caching) Solution: Use `inline_template` \+ `#context: _context`. E.g. `{% set extra_render = {'#type': 'inline_template', '#template': mysetverbatimstring, '#context': _context }`

For `{{- render_var -}}` \- twig white space control @see https://www.drupal.org/docs/theming-drupal/twig-in-drupal/comparison-of-phptemplate-and-twig-theming-paradigms#whitespace

For `_context` @see https://twig.symfony.com/doc/2.x/templates.html#global-variables

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


# Question
Title: How to restore layout builder override layouts from old DB snapshot?
After upgrading from Drupal v9.1.7 to v9.2.0, on a lot of nodes the custom layout builder override layouts were reset to the default layout, resulting in a massive data loss. To make things worse, this only happened on live and not on stage, and was only noticed a few days later. I don't know what has caused the issue, the customer is pretty upset, and I quickly and selectively need to restore the override layouts from a DB snapshot the night before the update (and leave the rest of the data untouched).

So far I know two things:

* All affected nodes have a `node.changed` timestamp matching the time of the update deployment.
* On all affected nodes `node__layout_builder_layout` has been trimmed to one section (same as the default, non-override layout)
* On all affected nodes only the last revision is lost, without generating a new revision id.
* The override layouts usually consist of custom, non-reuseable `block_content` blocks. All the blocks still seem to exist in the DB.

I'd like to know:

1. How can I check if a node has an override layout, or is using the default layout of the layout builder (if possible with a plain SQL query, without PHP)
2. What else do I need to restore except the `node__layout_builder_layout` table (assuming custom content blocks used by the override layouts still seem to exist) to restore a node's override layout
3. Can I savely use SQL `where a <> b` or SQL `where a = b` with `a` and `b` being the blob content of `node__layout_builder_layout.layout_builder__layout_section` ?

# Answer
> 0 votes
I can quickly answer the first question. There is a table called node\__layout\_builder\__layout that holds just the nodes that have overridden the default layout for that node. So if you create 2 nodes with IDs 1 and 2 and you use default layout for node 1 but override layout for node 2, in node\__layout\_builder\__layout you will see only the node 2. So you can get all nodes and discriminate the ones found in that table. Be sure you check the delta field to review the differences between revisions.

# Answer
> 0 votes
Answering my question 2:

(IF the referenced custom content blocks, etc. still exist in the DB...)
Restoring the `node__layout_builder__layout` table does restore the override layouts, no other tables required.

---
Tags: layout-builder
---


# Question
Title: How do I show the result on same page after submitting the form?
How do I show the result on same page after submitting the form in Drupal 8?

# Answer
> 6 votes
Request a rebuild in `submitForm()` and then display the result in `buildForm()`:

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

  // build form

  if ($form_state->isRebuilding()) {

    // display result

  }
}

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

  $form_state->setRebuild();

}

```

# Answer
> 1 votes
I've written a tutorial to explain how to do this: https://www.jaypan.com/tutorial/drupal-form-api-ajax-form-and-results-same-page

---
Tags: forms, 8
---


# Question
Title: how to block internal Drupal paths for anonymous users?
Is it possible to block internal Drupal paths for anonymous users and leave only paths generated by pathauto? For example:

* block path: /taxonomy/term/5
* leave path: /products/books

In google webmaster tools for my site, all taxonomy pages have an issue called "**Pages with duplicate title tags**" and google is showing both paths for each term, which is a problem. How to block the internal Drupal path for anonymous users?

By the way, apart from this, some taxonomy terms are purely for config and their paths should be blocked not because googlebot has a problem but generally, those paths make no sense for non-admins and should never be accessed directly via url.

# Answer
> 0 votes
To prevent those pages from being crawled, add the following to your robots.txt:

```
 Disallow: /taxonomy/
 Disallow: /taxonomy/*

```

For more details, see https://drupal.org/node/22265

Alternatively, you can also use the module disable\_term\_node\_listings to hide node listings for a paricular taxonomy vocabulary.

# Answer
> 1 votes
If you have clean URLs enabled, and are using the Global Redirect module, the users should never actually see the default paths (sometimes also called the internal path).

If a user goes to node/123 or taxonomy/term/456, and a path alias exist, then they will get an HTTP 301 and then redirect the the path alias. Google and won't index the paths that 301.

In addition, Drupal will add a `rel='canonical'` to the header, to notify the world about the offical URL.

However, if you ever had you site without Global Redirect enabled, then you could at one point access pages from multiple paths. Once Google starts seeing 301 responses for paths, it will eventually delist the page. You can speed up the process by also disallowing the paths in your robots.txt and/or submitting page/directory removal requests. Just remember to backup your robot.txt (or better yet put it in your VCS) because it will get nuked during core updates.

# Answer
> 0 votes
When I did this, the only way I could find to make this work without breaking core Drupal functionality was to use LocationMatch inside the Apache vhost configuration

```
<LocationMatch ^/taxonomy/term>
   SetHandler server-status
   Order Deny,Allow
   Deny from all
</LocationMatch>

```

# Answer
> 0 votes
Simple! Add disallow in robots.txt file

```
Disallow: /taxonomy/

```

& Add no follow no index on taxonomy pages using the metatags module (/admin/config/search/metatag)

```
<meta name="robots" content="noindex, nofollow" />

```

---
Tags: 7, path-aliases
---


# Question
Title: Reformat Date Argument in Contextual Filter
I have an argument in a view, contextual filter - {{ arguments.field\_news\_date\_value }}. How can I reformat a date value from YYYY-MM-DD to DD Month Year in the view

# Answer
> 0 votes
Select the custom format in the field's configuration and d m y there. Refer https://www.php.net/manual/en/function.date.php to see php date format.

---
Tags: views
---


# Question
Title: Should drush configuration export automatically update core.extension.yml?
The Drupal 8 documentation seems to be lacking in regards to the core.extension.yml file, so I'm a little confused on the right way of updating it.

1. Should drush be populating it on config export, or are you supposed to manually update it?
2. Do I need to move it from core to my config/sync folder, or leave it in core?

My file's contents are this, even though I have a handful of modules enabled on the site and have exported my config numerous times:

```
module: {}
theme: {}
profile: ''

```

On the site I am exporting from (site a) I am using composer to download modules and `drush en` to enable them, then `drush cex` to export the configuration to my sync folder. When I copy the sync folder contents over site b and import via `drush cim` I run into errors that the modules are not installed / enabled. Manually enabling each module then re-importing was successful.

Both sites are 8.3.7.

# Answer
> 2 votes
I think that the problem comes from where you have the config files, to be sure that they are really in the config/sync folder go to check if you have this following line in the settings.php file:

```
$config_directories = array(CONFIG_SYNC_DIRECTORY => 'config/sync');

```

Keep in mind that this line will have the location of the site configuration files.

Each time you use the `drush cex` or `drush cex sync` command the core.extension.yml file will be updated (if needed) with the actual modules (and others) configuration.

# Answer
> 1 votes
*core.extension.yml* is a YAML file listing all installed and enabled modules, themes, and profiles and their respective weight (if specified).

The correct way of declaring the sync directory in *settings.php* changed with Drupal 8.8.0 as follows:

Before:

```
$config_directories['sync'] = 'sites/default/files/config_YLZJmmpOqc_KBWbMc2I58ky3-8c7qtg4G-OpSqFClHs5E0NL9YMFgyF4RRTv8IFdl_kAMs_Bdw/sync';

```

After:

```
$settings['config_sync_directory'] = 'sites/default/files/config_YLZJmmpOqc_KBWbMc2I58ky3-8c7qtg4G-OpSqFClHs5E0NL9YMFgyF4RRTv8IFdl_kAMs_Bdw/sync';

```

See: https://www.drupal.org/node/3018145

---

In terms of location, it's generally considered to be more secure if it's below the webroot, e.g.:

```
$settings['config_sync_directory'] = '../config/sync';

```

Further reading: https://www.drupal.org/docs/configuration-management/changing-the-storage-location-of-the-sync-directory

---
Tags: drush, configuration
---


# Question
Title: Import your own interface translations automatically during profile or module installation
I have been trying to import my custom interface translation during profile installation using a .po file that is put inside the translations folder in my custom module. After running:

> drush locale-update && drush cr

All I get is community translations which are not accurate sometimes (no translation is imported from my .po file).

How can I import translations only from my local .po file?

Thank you.

# Answer
To import your own translations you should use the interface translation properties on your module.

I'm using a folder **`translations`** in my modules where my language files like **`de.po`** or **`fr.po`** can be found. To load the translations you have to insert the following lines into your *example\_module.info.yml*:

```
'interface translation project': example_module
'interface translation server pattern': modules/custom/example_module/translations/%language.po

```

And to update your translations use this:

```
drush locale-check && drush locale-update && drush cr

```

EDIT: To update existent translations you should take a look at the settings page (/admin/config/regional/translate/settings):

You can try to use local translation files only or to overwrite any existing translation.
> 12 votes

# Answer
Just import your own custom translations after importing the official ones:

```
drush locale:update -y
drush locale:import de ../translations/custom-translations.de.po --type=customized --override=all -y

```

you could do this in an update.sh after site install has run. Check the flags like --override=all
> 2 votes

---
Tags: 8
---


# Question
Title: How can I add a boost to a search_api_solr query if a field has a value?
I'm trying to add a boost to a search api Solr query when a field has a particular value, e.g. when its nid = 123. Looking at Solr version 8.7 docs for boosting (my solr server version), this looks pretty straightforward. I just need to add a bq parameter like:

```
bq=nid:123^10

```

When I go to my Solr server's admin UI and add a query there - first checking the edismax parser checkbox, and then adding `nid:123^10` into the bq field - I see results where my node with nid is at the top of the list (as I'd expect) with all other results after it. If I remove the option, my node with nid 123 is no longer at the top (also as I'd expect).

The search\_api\_solr module provides a hook to alter queries, hook\_search\_api\_solr\_query\_alter(), where I can add my boost. (Side note, I've used this hook in the past to boost results based on a date basically as documented in this bkosborne comment.)

My understanding is that I should be able to implement something like:

```
function MY_MODULE_search_api_solr_query_alter(\Solarium\Core\Query\QueryInterface $solarium_query, \Drupal\search_api\Query\QueryInterface $query) {
  $solarium_query->addParam('bq', 'nid:123^10');
}

```

However, this has no impact on the relevancy scores of my results (I'm printing the relevancy score in my view and my node with nid 123 has the same score whether I add this parameter or not), nor, predictably, the order of the results.

**What am I missing here?**

Version Information:

* Drupal core: 9.1.10
* Search API: 8.x-1.19
* Search API Solr: 4.1.12
* Solr Server: 8.7.0

p.s. my nid field key is actually `its_nid` in the index, but I just used `nid` in this question for readability.

# Answer
> 7 votes
I just needed to read more closely. All of the information is in the example code in the hook\_search\_api\_solr\_query\_alter() documentation. (I think the format I was using may have been recommended for much older versions of search\_api\_solr, versions that are only recently no longer required on certain enterprise hosts.)

The simplest way to get this to work was to add the defType parameter to my query to tell it to use the edismax parser. This is documented in hook\_search\_api\_solr\_query\_alter(). The following works:

```
function MY_MODULE_search_api_solr_query_alter(\Solarium\Core\Query\QueryInterface $solarium_query, \Drupal\search_api\Query\QueryInterface $query) {
  $solarium_query->addParam('bq', 'nid:123^10');
  // Avoid the conversion into a lucene parser expression, keep edismax.
  $solarium_query->addParam('defType', 'edismax');
}

```

However, reading the hook documentation, it shows an alternative approach that seems preferable:

```
function MY_MODULE_search_api_solr_query_alter(\Solarium\Core\Query\QueryInterface $solarium_query, \Drupal\search_api\Query\QueryInterface $query) {
  $boost_queries['special_node'] = [
    'query' => 'nid:123^10.0',
  ];
  $boost_queries['some_less_special_node'] = [
    'query' => 'nid:321^5.0',
  ];
  /** @var \Solarium\Component\EdisMax $edismax */
  $edismax = $solarium_query->getEDisMax();

  $edismax->addBoostQueries($boost_queries);

  // Avoid the conversion into a lucene parser expression, keep edismax.
  $solarium_query->addParam('defType', 'edismax');
}

```

---
Tags: search
---


# Question
Title: How to make view display plugin translatable?
I have a custom view display plugin which extends from the block plugin. When I add a display on the view, the fields or anything in the display is not translatable (see image below)

How can I make the fields in the view display plugin translatable?

# Answer
> 1 votes
You need to define a schema (where `products_block` is the plugin ID):

*/config/schema/mymodule.views.schema.yml*

```
views.display.products_block:
  type: views.display.block
  label: 'Products block display options'
  mapping:
    ...

```

This extends `views.display.block` of /core/modules/views/config/schema/views.display.schema.yml, which extends `views_display` of /core/modules/views/config/schema/views.data\_types.schema.yml

More info Block configuration form values are not translated?

---
Tags: 8, views
---


# Question
Title: Get third party settings in paragraph node edition
I'm adding a third party settings in my **.module** file, in the `mymodule_form_alter` function. I did this is order to add an image to my paragraph.

```
function my_module_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  if ($form_id != "paragraphs_type_edit_form") {
    return;
  }

  //////// definition paragraphe
  $entity = $form_state->getFormObject()->getEntity();

  $third_party_settings = $entity->getThirdPartySettings('my_module');
  $illustration = $entity->getThirdPartySetting('my_module', 'paragraph_illustration');
  $form['third_party_settings']['#tree'] = TRUE;

  $form['third_party_settings']['my_module']['paragraph_illustration'] = [
    '#type' => 'managed_file',
    '#title' => 'Illustration du paragraphe',
    '#name' => $form_state->getValue('paragraph_illustration'),
    '#upload_location' => 'public://',
    '#default_value' => !empty($illustration) ? [$illustration] : NULL,
  ];

  $form['#entity_builders'][] = 'my_module_form_node_type_form_builder';

}

```

So far, this is working well, the settings well saved and retrived

Now, I want to display this image on my node edition, where the paragraph is added. This image is used to show what technicaly, the paragraph would render.

But for some reason, the getThirdPartySettings is always empty (\[\]). In the first place, I thought using the icon to display "fake preview". With the icon, it works great. But of course, the target image will be quite big, not an icon.

where is my mistake ? Should I change the hook ?

```
function my_module_field_widget_paragraphs_form_alter(&$element, FormStateInterface &$form_state, $context) {
  $paragraphRendering = [
    'push_produit',
  ];
  $type = $element['#paragraph_type'];
  $illustationClass = "paragraph-illustration";

  if (in_array($type, $paragraphRendering)) {
    $icon = $element['top']['type']['icon']['#uri'];
    $description = "Fake preview";
    $field_definition = $context['items']->getFieldDefinition();
    if($field_definition instanceof Drupal\field\Entity\FieldConfig) {
      $mymodule_settings = $field_definition->getThirdPartySetting('my_module', 'paragraph_illustration');
      dump($mymodule_settings);
      // dump return []
    }
    $entity = $form_state->getFormObject()->getEntity();
    $element['#prefix'] = str_replace('id="', 'class="paragraph-' . $type . '" id="', $element['#prefix']);
    $element['#prefix'] .= '<div class="' . $illustationClass . '"><p>' . $description . '</p><img src="' . $icon . '"></div>';
  }
}

```

# Answer
You're adding a 3rd party setting to a paragraph type entity, but trying to retrieve it from a field entity. You need to retrieve it from the same entity you set it on, e.g.

```
function my_module_field_widget_paragraphs_form_alter(&$element, FormStateInterface &$form_state, $context) {
  ...
  $setting = $form_state->get('paragraph')->getParagraphType()
    ->getThirdPartySetting('my_module', 'paragraph_illustration');
  ...
}

```
> 0 votes

---
Tags: paragraphs, 9
---


# Question
Title: Show Taxonomy Name not TID in Views Query String
I'm using Views exposed filters (dropdown) based on Term Reference (taxonomy Fields.)

It works but the query string it generates uses the Term ID (TID) instead of using the more readable and clean term name.

How do I change the query string to use the term name instead of TID? For example:

Current: http://test.com/test?gender=1

Desired: http://test.com/test?gender=female

# Answer
You can use taxonomy term names with this filter by adjusting Specify validation criteria settings. here's a screenshot:

Make sure Specify validation criteria is checked and you should be presented with more options. Under Validator choose Taxonomy term. You can optionally select with vocabularies to allow. Under Filter value type choose Term name converted to Term ID and check the Transform dashes in URL to spaces in term name filter values checkbox.
> 2 votes

# Answer
Use that module it will help views\_contextual\_filter\_query

> Allows url query values to be used as contextual filter arguments. This module is an answer to the many stackoverflow topics where the solution is to fetch query parameters by using the default PHP argument filter in Views (yucks!).

Use exposed form tpl to alter the select list to use term name as value

Configure validation criteria to use term name instead term Id.

The module will help you use contextual filters from query strings.
> 2 votes

# Answer
Two steps:

1. Create a relationship between your base table and the 'taxonomy terms on node':

2. Filter by Taxonomy term **name**:

The relationship allows the view to access parts of the taxonomy term other than the ID, such as its name.
> 2 votes

# Answer
AFIK, you will need to alter the way exposed filters lists the terms. If you inspect, you will see term ids as values. You will need to replace them with actual term names. You can use views API to do this. There is no other quick way to achieve this.

Regards.

\[Edit\]

In addition to altering the term values in filter, you will also need to write the code that map the taxonomy names to term id when you perform an operation.

\[/Edit\]
> 1 votes

# Answer
This is an ancient discussion, but still pertinent to Drupal 8 (and I presume 9).

I was able to solve it for my particular scenario with a minimal amount of code, only hooking into form\_alter.

1. Add a relationship to the view for the taxonomy term
2. Add the taxonomy term name as a filter. This will make the URL argument work as expected, but the form field will be a text field instead of a select
3. In the form\_alter hook, change the text field to a select. Do a query to get all of the relevant taxonomy terms and add them as options.

Hacky, but relatively lightweight and no issues with functionality. Here's my form alter code, yours might look something like this.

```
function your_module_form_views_exposed_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id){

  switch($form['#id']){
    case 'views-exposed-form-your-view':

      $term_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');

      $form['topic']['#type'] = 'select';
      $form['topic']['#attributes'] = []; // Optional, I had to remove a better exposed filters attribute that stopped auto submit
      $form['topic']['#options'] = [
        '' => t('All Topics')
      ];

      foreach ($term_storage->loadTree('topics') as $term) {
        $form['topic']['#options'][$term->name] = t($term->name);
      }

      break;
  }
}

```
> 1 votes

---
Tags: 7, views
---


# Question
Title: Set "select" field on a node programatically
I am creating nodes programmatically on a specific content type. The content type has a "select field" that I am trying to set value with and cannot do it. Below is my code:

```
 $node = \Drupal::entityTypeManager()->getStorage('node')->create(array(
      'type'  => 'level3',
      'title' => $file_name,
      field_level2_title => [
        'value' => 'Assessment'
      ],
      field_level3_title => $file_name,
      field_level3_readmore => [
        'uri' => $file_uri,
        'title' => $file_name
      ],
    ));

```

The select field name is "field\_level2\_title and I am unable to assign this. Any help?

# Answer
Thanks for the comments above. the solution worked for me is as below:

field\_level2\_title =\> \[ 'target\_id' =\> $ref\_id\_field \]
> -1 votes

---
Tags: nodes, 9
---


# Question
Title: Securing admin account, silly "solution" found
Hello fellow Drupalers,

I've been given the task of securing our admin account, on our websites (drupal 7) from outsiders.

My first thought was 2FA and I looked at some of the modules (tfa, google auth, etc) and they seem to be doing the job okay.

But as I was fiddling around I accidentally deleted the admin password.

Now I cannot login through the website with the admin account, but I can via `drush uli`.

Do you guys consider this to be an okay solution for securing the admin account? I personally have my doubts about it, because it seems so simple...

# Answer
Definitely not a solution I would rely on. "Securing admin account" is a wide topic that needs to be handled carefully, but answering specifically to your question, if what you want is to "protect" the password, you can run a cronjob that changes the password string to a random, SHA value, every X time. I've seen that in some clients.

Talking about MFA (2FA), yes, this adds a pretty solid and common layer of security. Also implemented it for some clients.
> 0 votes

---
Tags: 7, authentication-authorization
---


# Question
Title: how to add custom font files to template
I like to add my custom font to my custom theming. All the font-files are in the file FONTS. And I also have a fonts.css file. Where do I have to declare all this stuff?

# Answer
> 2 votes
You need to use libraries. Take a look here for a detailed explination: https://www.kinetasystems.com/blog/adding-google-fonts-to-a-drupal-8-theme

# Answer
> 0 votes
Since the accepted answer is a link to a dead site I have copy and pasted the article here from the waybackmachine

all credits to 'Nik' who submitted the article on 16 December 2015 - 3:04pm

> This took a bit more work to figure out than in Drupal 7! Bear in mind, this example is for installing a theme-wide (every page) font. There's references at the bottom where you might find further information on other methods.
>
> Here's the old way of inserting Google Fonts (for every page using this theme):
>
> ```
> function MYTHEME_preprocess_html(&$variables) {
>   // this function is deprecated in D8 because, caching, I think
>   drupal_add_css('//fonts.googleapis.com/css?family=Oxygen:300', array('group' => CSS_THEME));
> }
>
> ```
>
> In Drupal 8, however, we have to use the libraries method, which is "a bit" more involved. Firstly, we need to add a library to our theme.info.yml (see last two lines). Here, I've made a subtheme of Bartik to implement the feature against. Side note: the base theme name is not capitalised. This didn't work when I tried it, but is ok all lower case. Seems a bizarre thing, when the original theme is declared like `name: Bartik` but there you go.
>
> ```
> name: Blah
> description: It's a theme
> type: theme
> base theme: bartik
> core: 8.x
> libraries:
>   - themeName/fonts
>
> ```
>
> Then we need to create the library file. For whatever reason, the library is defined as `themeName/libraryName` in the `.info.yml`. The library file is called `themeName.libraries.yml`. The library file opens with a declaration of `libraryName`:
>
> ```
> fonts:
>   license:
>     name: SIL Open Font License, 1.1
>     url: http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL
>   css:
>     theme:
>       //fonts.googleapis.com/css?family=Oxygen:300: { type: external }
>       css/myStyles.css: {}
>
> ```
>
> This YML file actually works fine without the license section, but it would be a bit poor to not even attempt to honour it... NB The font url has had the **http:** removed so that it is agnostic to secure-or-not connections at runtime.
>
> If all that has worked, you should be able to view source on your site and see a comforting line of code like All that remains is to implement the font in your CSS by inserting a rule in the myStyles.css file in the css folder, like:
>
> ```
> font-family: 'Oxygen', sans-serif;
>
> ```
>
> **References**
>
> Adding stylesheets (CSS) and JavaScript (JS) to a Drupal 8 theme
>
> Defining a theme with an .info.yml file
>
> Creating a Drupal 8 sub-theme

---
Tags: theming, 8
---


# Question
Title: Form submission field not available in form action
I have the following form submission handler.

```
function mymod_form_submit(&$form, FormStateInterface $form_state) {
  $ka_selected = $form_state->getValue('ka_types');
  \Drupal::state()->set('ka_types', $ka_selected);
  return $ka_selected;
}

```

It returns the *ka\_types* field value. I want to use `$ka_selected` in custom action code.

```
public function execute(ContentEntityInterface $entity = NULL) {
    //Read all the fields from entity
    $comment = $entity->get('comment_body')->getValue();
    $file_uri = file_create_url($entity->field_attachment->entity->getFileUri());
    $file_name = $entity->field_attachment->entity->getFileName();
    $ka = $entity->ka_selected->entity->getValue(); **//error thrown here**
    dd($ka);
}

```

I am able to read other view entities but not just this field.

How can I use the value of `$ka_selected` in my custom action?

# Answer
Alright, I am able to figure out the answer from the below link: https://www.drupal.org/forum/support/module-development-and-code-questions/2021-07-04/read-view-row-entities-and-create-a#comment-14154305

```
public function execute(ContentEntityInterface $entity = NULL) {
    //Read all the fields from entity
    $comment = $entity->get('comment_body')->getValue();
    $file_uri = file_create_url($entity->field_attachment->entity->getFileUri());
    $file_name = $entity->field_attachment->entity->getFileName();
    $ka = \Drupal::state()->get('ka_types');
    dd($ka);
}

```
> 0 votes

---
Tags: views, 9, actions
---


# Question
Title: How can I get the path alias from a node ID or node object?
I have a node object, and I am trying to use it to get a given path in Drupal 8.

There was `drupal_lookup_path()` in Drupal 7 but I'm not seeing any equivalent or documentation for Drupal 8.

What's the new "Drupal" way to get a path from a node object?

Would it be something simple like `$node->get('path')`?

This seems like a simple question, but I'm just absolutely not finding any documentation on it.

Notice I do not want the path alias for the current path; I want the path alias for an arbitrary node, given a node object or a node ID.

# Answer
> 85 votes
To get the path for a node id use AliasManager::getAliasByPath:

**Drupal 8**

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

```

**Drupal 9**

```
$alias = \Drupal::service('path_alias.manager')->getAliasByPath('/node/'.$nid);

```

See comment from Felix Eve.

# Answer
> 37 votes
If you only have the nid, 4k4's solution of

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

```

Works great. But if you already have a node object you can skip a step or two. Nodes actually have built in methods for getting urls.

```
$node->toUrl()->toString();

```

Would return the aliased url of the node.

toUrl() returns a url object. See here https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Url.php/class/Url/8.2.x

and toString() is a method of the url object that returns the string representation of the url.

# Answer
> 23 votes
What about using Url:

```
use Drupal\Core\Url;

...

$url = Url::fromRoute('entity.node.canonical', ['node' => $nid])->toString();

```

# Answer
> 12 votes
Best way to get node URL from node object-

* **Absolute Path** : $node-\>toUrl()-\>setAbsolute()-\>toString();
* **Relative Path** : $node-\>toUrl()-\>toString();

It will also handle node language.

# Answer
> 4 votes
You can also use the load method from `path.alias_storage` to return an array of the alias details or boolean false if there wasn't a path found for that node.

`$aliasArray = \Drupal::service('path.alias_storage')->load(['source' => '/node/' . $nid]);`

# Answer
> 3 votes
If you want to get the node alias url by **languages** dont forget to use the language like this.

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

```

If you are using it in a class do not forget to use the dependencies injection correctly.

# Answer
> 1 votes
As per the new change record in Drupal 8.8.0 `path.alias_manager` is deprecated and `path_alias.manager` is introduced.

New syntax is as follows :

```
$url_alias = \Drupal::service('path_alias.manager')->getAliasByPath('/node/'. $nid, $langcode);

```

# Answer
> 1 votes
Surprisingly, as of Drupal 9.2, none of the current answers work in a multilingual site that uses path prefixes for language detection.

This is what I ended up using:

```
// Note: using dependency injection to get the language code.
$lang_code = $this->languageManager
  ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)
  ->getId();

// Note: using dependency injection to load the node.
$test_nid = 1
$test_node = $this->entityTypeManager->getStorage('node')->load($test_nid);

// If the node has a translation, load it.
if ($test_node->hasTranslation($lang_code)) {
  $test_node = $test_node->getTranslation($lang_code);
}

// Get the localized URL for that node.
$localized_url = $test_node->toUrl('canonical', [
  'language' => $test_node->language(),
])->toString();

```

# Answer
> -8 votes
I was hoping for a more "Drupalesque" solution, but here's what I made myself to do the job:

```
  function getPathFromNID($nid) {
    $db = \Drupal::database();

    $data = $db
        ->select('url_alias', 'u')
        ->fields('u', ['alias'])
        ->condition('source', '/node/' . $nid)
        ->execute()
        ->fetchField();
    return $data;
  }

```

---
Tags: 8, nodes, path-aliases
---


title: How do I include a PHP library?

text:
# Question
Title: How do I include a PHP library?
In Drupal 7, there are `hook_library()` and `drupal_add_library()` that can be used to manage JavaScript and CSS libraries. I am looking for how to include the PHPExel library (now moved on GitHub) in my distribution.

How can I achieve this?

# Answer
> 8 votes
`hook_library()` is thought only for Javascript and CSS files; for PHP libraries, you should consider the Libraries API module.

> This module introduces a common repository for libraries in sites/all/libraries resp. sites//libraries for contributed modules.

### External libraries

> Denotes libraries ("plugins") that are neither shipped nor packaged with a project on drupal.org. We do not want to host third-party libraries on drupal.org for a multitude of reasons, starting with licensing, proceeding to different release cycles, and not necessarily ending with fatal errors due to conflicts of having the same library installed in multiple versions. Drupal 7 only has built-in support for non-external libraries via `hook_library()`. But it is only suitable for drupal.org projects that bundle their own library; i.e., the module author is the creator and vendor of the library. Libraries API should be used for externally developed and distributed libraries. A simple example would be a third-party jQuery plugin.

The *Libraries API* module implements an API that can be used from third-party modules to load libraries installed on a Drupal site; the pro of using Library API is that it handles dependencies between libraries, and versioning.

The documentation explains which files can be loaded from a library defined using the *Libraries API* hooks. In particular, the documentation for `hook_libraries_info()` explains that, if `$libraries` is the value returned from the hook implementation, `$libraries['files']['php']` is an array containing a list of PHP files that will be loaded when the library is loaded.
The Grammar Parser Library module defines a PHP library in `gplib_libraries_info()`.

```
function gplib_libraries_info() {
  $libraries['grammar_parser'] = array(
    'title' => 'Grammar Parser Library',
    'vendor url' => 'http://drupal.org/project/grammar_parser',
    'download url' => 'http://drupal.org/project/grammar_parser',
    'version arguments' => array(
      'file' => 'CHANGELOG.txt',
      'pattern' => '/pgp \(grammar parser\) (\d+\.x-\d+\.x)/',
    ),
    'versions' => array(
      '7.x-1.x' => array(),
    ),
    'files' => array(
      'php' => array(
        'engine/parser.inc',
        'engine/editor.inc',
        'engine/list.inc',
        'engine/object.inc',
        'engine/reader.inc',
        'engine/writer.inc',
      ),
    ),
  );

  return $libraries;
}

```

# Answer
> 1 votes
I am not too sure if this operation is going to work for custom php libraries but I have used this procedure for importing custom css and js files into my project.

1. Download and install the libraries module from here https://drupal.org/project/libraries and enable it (do not forget to download, install and enable all dependencies as needed)
2. A directory sites/all/libraries should have been created. If not, just create the libraries directory in sites/all/
3. now create your php includes director in the sites/all/libraries directory.
4. Copy all your custom php files into the sites/all/libraries/includes directory.

In summary, I guess the libraries module should enable you to automatically import custom php, css and js libraries and so on into your project

# Answer
> 0 votes
Since now there is a package for the PHPExcel on packagist.org, the alternative to using the *Libraries API* module is creating a composer.json file describing all the dependencies the module has. Supposing the only dependency for the module is the PHPExcel library, the content of the composer.json file could simply be the following one. (I only show the dependencies part.)

```
{
    "require": {
       "phpoffice/phpexcel": "^1.8.2"
    }
}

```

I am using the release 1.8.2 because previous releases are affected by a XXE vulnerability reported in CVE-2018-19277.

Since the PHPExcel library is deprecated, the module should use the PHPSpreadsheet library.

```
{
    "require": {
       "phpoffice/phpspreadsheet": "^1.18"
    }
}

```

The latest version is 1.18.0, but any version higher than 1.15.0 is fine. Previous versions are affected by a XSS vulnerability described in CVE-2020-7776.

Once the module has its composer.json file, the *Composer Manager* module (required for this approach) will be able to save its dependencies in the directory defined in the *Composer Manager* settings.

In its documentation, the *Libraries* module suggests to use the Composer approach for Drupal 8.

> For feature parity with the Drupal 7 version of this module, a PHP file library type is provided, that can load a list of PHP files on demand.
> Generally, it is encouraged to use Composer instead of this library type and avoid Libraries API altogether for PHP libraries. See PhpFileLibraryInterface for more information.

---
Tags: 7
---


# Question
Title: How to create a view showing Users who have flagged AND are flagged by the current user
I'm trying to display a list of users who have flagged the current user, and are flagged by the current user. So a two-way flagging.

I've tried using different relationships and arguments in views, but can't seem to get the combination right. Any tips? Thanks!

Here's my views config from @pkros's instructions as requested.

Also, here is a quick screencast showing the issue in action... https://drive.google.com/file/d/1MOXKZSq\_cjPRv6moim1a5ikKeeD8mjY9/view?usp=sharing

# Answer
> 0 votes
Flags are one way, so you can't have a "two-way flagging".

In Drupal 8/9, a flag always has a target entity.

So, if user A flags user B and user B flags user A, you have two flags:

* User A's flag of User B
* User B's flag of User A

I can't think of a good way to do this in Views without custom code.

An alternative would be something like the Friend Flag module, which implements "friending" functionality (or Tinder mutual-swipe-to-match functionality).

Having implemented functionality like this before in Drupal 7, in Drupal 8/9, I would consider writing code in the `_flagging_insert()` hook that checks when a user flags another user and determines whether the flagged user has flagged the flagging user. If so, create an entity (could be a node with entity references to both users or a custom entity if you want to get fancy) of type **Friend** or **Match** or whatever, and then sort the matches that way in Views. Of course, if users can unflag each other and break the match, you have to add code to support that case, too.

# Answer
> 0 votes
Here's how you can do this with Views:

1. Create User Views, the username field is usually already there, you can keep it for now
2. Add the Flag Relationship and set it to `Include only flagged content`, your particular Flag name, and `Any user`
3. Add the Field `User ID` from the **Flagging** Category (not the User Category)

Now you should see the list of all Flagging "connections". The username field is showing which user has been flagged, and the Flagging user field is showing who flagged them.
4. Now add the `User ID` Contextual filter from the `User` Category, and configure it:
`When the filter value is NOT available`
**Provide default value**
**User ID from logged in user**
`When the filter value IS available or a default is provided`
**Specify validation criteria**
**User ID**
**Single ID**
Adjust all other options to your needs.

This shows only the "connections" that are made towards the current user.
5. Remove the username field since you don't need it anymore since it's always showing the current user.

What is left is the user field from Flagging context showing who flagged the current user, while at the same time that user has been flagged by the current user.

---
Tags: 8, views, flags
---


# Question
Title: Locked to version problem when upgrading
Every time I run the composer command to upgrade Drupal 8.9.16 to Drupal 9, it notifies me that there is a problem with a module.

For example, I run:

```
composer require drupal/core --with-all-dependencies

```

I get:

```
Using version ^9.2 for drupal/core
./composer.json has been updated
Running composer update drupal/core --with-all-dependencies
Gathering patches from patch file.
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - drupal/twig_tweak is locked to version 2.9.0 and an update of this package was not requested.
    - drupal/twig_tweak 2.9.0 requires drupal/core ^8.7 || ^9.0 -> satisfiable by drupal/core[9.2.0-alpha1, ..., 9.3.x-dev].
    - drupal/core[9.2.0-alpha1, ..., 9.3.x-dev] require symfony/routing ^4.4 -> satisfiable by symfony/routing[v4.4.0-BETA1, ..., 4.4.x-dev].
    - symfony/routing v4.4.25 conflicts with symfony/routing v4.4.25.
    - symfony/routing v4.4.24 conflicts with symfony/routing v4.4.24.
    - symfony/routing v4.4.22 conflicts with symfony/routing v4.4.22.
.....
.....

```

In this case, twig\_tweak is already at 2.9.0, which supports Drupal 9, but it is complaining about it. I have been removing the problem module from composer.json and then running `composer update`, but every time I run `composer require drupal/core --with-all-dependencies` another module shows up with the same issue. I feel like I may be doing something wrong.

# Answer
Once you need to update the current code follow the below steps:

Step 1: Run command:

**composer update**

Step 2: You need to update the current code with an update to Drupal 8 and update using custom theme and module version

**core\_version\_requirement: ^8.9 || ^9**

SO current code and modules are ready to be upgraded with Drupal 9. This way we can reduce errors.

Step 3: Create a default folder and set the file to be editable.

chmod 777 web/sites/default find web/sites/default -name "\*settings.php" -exec chmod 777 {} ; find web/sites/default -name "\*services.yml" -exec chmod 777 {} ;

Step 4: Run These Commands (This Command Edits Your Composer File to Be Upgrade Ready)

**composer require drupal/core-recommended:^9 drupal/core-composer-scaffold:^9 drupal/core-project-message:^9 --update-with-dependencies --no-update**

If you have drupal/core-dev installed.

**composer require drupal/core-dev:^9 --dev --update-with-dependencies --no-update**

Step 5: Run command

**composer require "drupal/core:9.2.1 as 8.9.16" --no-update && composer update**

Step 6: Run **Drush updatedb command**

If you face any problem with core then

Step 6.1: Run **Composer outdated "drupal/\*"** and update this listed module into the Drupal 9 version and upgrade the appropriate custom modules and themes with Drupal 9.

Step 6.2: **$config\_directories\['sync'\]** change to **$settings\["config\_sync\_directory"\]**

https://www.drupal.org/docs/upgrading-drupal/upgrading-from-drupal-8-to-drupal-9-or-later
> -1 votes

---
Tags: composer, 9, upgrading
---


# Question
Title: How to add an external link inside form actions?
I want to programmatically add an external link next to my submit button in a form that I have created.

# Answer
> 1 votes
The solution that worked for me was adding a link element within the actions array

```
$form['actions']['google_search'] = [
      '#type' => 'link',
      '#title' => $this->t('Google Search'),
      '#url' => Url::fromUri('https://www.google.com/search?whatever'),
      '#attributes' => ['target' => '_blank', 'class'=> 'button'],
    ];

```

Ps: Directly adding the url to the #url element does not work, I had to use the Url component

---
Tags: forms, actions
---


# Question
Title: How to get the value / URL of a Link field in a Twig template?
I have a custom block Type with a Link field called "field\_link" (for internal links only). Within my block Twig template I want to extract the URL of the link field. How can I do that? I read some post with similar problems, but none of the solutions seems to work so far.

What I tried so far:

```
{{ file_url(content.field_link.uri) }}
{{ file_url(content.field_link.0.url) }}

```

I only get "/" but there should be "/node/1"...

This is my standard block template:

```
<div{{ attributes.addClass(classes) }}>
      {{ title_prefix }}
      {% if label %}
        <h2{{ title_attributes }}>{{ label }}</h2>
      {% endif %}
      {{ title_suffix }}
      {% block content %}
        {{ content }}
      {% endblock %}
</div>

```

# Answer
You can get the URL and the value (text) this way:

```
{{ content.field_link.0['#url'] }}

{{ content.field_link.0['#title'] }}

```
> 6 votes

# Answer
I'm not sure you need to use file\_url(), but you can use `{{ content.field_link.0['#url'] }}` as described in this question on stackoverflow.
> 1 votes

# Answer
`item.content['#url']` gives a render array :

However, if you need to extract only the URL which can be anything like frontpage, a node in your site or external, you need to use the `.toString()` utility.

`item.content['#url'].toString()`

Title can be accessed from `item.content['#title']`

Remember that it's all inside the loop:

```
    {% for item in items %}
      <div{{ item.attributes }}>
        {{ dsm((item.content['#title'])) }}
        {{ dsm((item.content['#url'].toString())) }}
        <a href="{{ item.content['#url'].toString() }}">{{ item.content['#title'] }}</a>
      </div>
    {% endfor %}

```
> 1 votes

# Answer
In most templates (node, paragraph,...) you can access raw field values using
`{{ entity_type.field_name.0.value }}`. Sadly this does not work block templates. To make it work for custom content blocks you need to add a preprocess function:

```
function YOURTHEME_preprocess_block(array &$variables) {
  if ($variables['base_plugin_id'] == 'block_content') {
    $variables['block_content'] = $variables['elements']['content']['#block_content'];
  }
}

```

Now you can access your fields using `{{ block_content.field_name.0.value }}` (in case of link fields use `{{ block_content.field_name.0.url }}` as described here)
> 0 votes

# Answer
This code will be work properly for printing separate **URL** and **Title** of the link field in twig.

```
{{ content.field_link.0.['#url'] }}

{{ content.field_link.0.['#title'] }}

```
> -1 votes

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


# Question
Title: Programmatically publish unpublished nodes
I want to publish unpublished nodes in a custom action. To do this, I query the database on a specific condition and want to use 'exists' condition to find the node IDs to publish. This is the code I am using.

```
$query = \Drupal::entityQuery('node');

foreach($i_selected as $is) {
  $nids = $query->andConditionGroup()
    ->condition('type', 'level3')
    ->condition('title', $file_name)
    ->condition('status', '0')
    ->exists('nid')
    ->execute();

  $nids->setPublished(TRUE)->save();
}

```

I get this error,

> Error: Call to undefined method Drupal\Core\Entity\Query\Sql\Condition::execute()

The SQL query I am trying to achieve is:

```
   select nid, status, title from node_field_data where status = '0' and title = $filename

```

of the result, I want to see if the nids exists and publish those nids.

How do I fix that error?

# Answer
> 4 votes
The code is calling `execute()` on the object returned from `$query->andConditionGroup()`, but that object doesn't implement any `execute()` method.

The correct way to use `andConditionGroup()` is shown in `QueryBase::andConditionGroup()`.

```
$query = \Drupal::entityQuery('drawing');
$group = $query->andConditionGroup()
  ->condition('figures.color', 'red')
  ->condition('figures.shape', 'triangle');
$query->condition($group);
$group = $query->andConditionGroup()
  ->condition('figures.color', 'blue')
  ->condition('figures.shape', 'circle');
$query->condition($group);
$entity_ids = $query->execute();

```

In your case, using `andConditionGroup()` isn't necessary, as the query executed by that code returns all nodes for which:

* The content type is *level3*
* The title is `$file_name`
* The status is 0

It doesn't return all the nodes for which at least one of those conditions is true. It's similar to what the following code does, which returns all the *page* nodes where the value of *field\_some\_field* is higher than 14.

```
$query = \Drupal::entityQuery('node')
  ->condition('type', 'page')
  ->condition('field_some_field', 14, '>');
$results = $query->execute();

```

`$query->execute()` returns an array of entity IDs, not an entity nor an array of entities. `$nids = $query->execute(); $nids->setPublished(TRUE)->save();` is still wrong, as an array doesn't implement the `setPublished()` method.
Given an array of node IDs `$nids`, the correct code to load the nodes is the following one.

```
$nodes = \Drupal::entityTypeManager()->getStorage('node')->loadMultiple(array_values($nids));

```

`$nodes` will contain an array of entities. Publishing them can be achieved with the following code.

```
foreach ($nodes as $node) {
  $node->setPublished(TRUE)->save();
}

```

The object returned from `\Drupal::entityQuery()` verifies the currently logged-in user has view access to the returned nodes. In most of the cases, the user doesn't have access to unpublished nodes. To avoid the query returns only the nodes the currently logged-in user can view, it's necessary to call `$query->accessCheck(FALSE)`, as in `$query = \Drupal::entityQuery('node')->checkAccess(FALSE);`

Furthermore, the `exists('nid')` call isn't necessary, as the node ID is always saved for nodes.

Leaving out the loop on `$i_selected`, the code I would use is the following one.

```
$query = \Drupal::entityQuery('node')->checkAccess(FALSE);

$nids = $query->condition('type', 'level3')
  ->condition('title', $file_name)
  ->condition('status', '0')
  ->execute();

$nodes = \Drupal::entityTypeManager()->getStorage('node')->loadMultiple(array_values($nids));

foreach ($nodes as $node) {
  $node->setPublished(TRUE)->save();
}

```

---
Tags: nodes, 9
---


# Question
Title: Providing menu route parameter values from url
Suppose I have the following route in my ej.routing.yml file:

```
ej.form.user.profile:
 path: '/user/{user}/ej_profile'
 defaults:
   _title: 'EJ Profile'
   _form: '\Drupal\ej\Form\User\ProfileForm'
 requirements:
   _role: 'authenticated'
   user: \d+

```

Now I want to add a menu based on the above route to Tools menu. So I use the following in ej.links.menu.yml file:

```
ej.user.profile:
  title: 'EJ Profile'
  description: 'EJ Profile'
  route_name: ej.form.user.profile
  menu_name: tools
  weight: 100

```

However this gives me an exception saying: Symfony\Component\Routing\Exception\MissingMandatoryParametersException: Some mandatory parameters are missing ("user") to generate a URL for route "ej.form.user.profile".

The same works as a task entry. Basically I have a custom form that extends user profile to integrate with a third-party system and I need the user id from the url to fetch appropriate user's information.

How can I have the menu to pick route parameter from the url?

# Answer
As @Eyal mentioned, "You can try using a custom class for the menu item. And then add your route parameter as you like."

I've done this by extending the MenuLinkDefault class and then assigning my menu link to use the class in my MY\_MODULE.links.menu.yml.

For example my ExampleMenuLink class:

```
namespace Drupal\my_module\Plugin\Menu;

use Drupal\Core\Menu\MenuLinkDefault;

class ExampleMenuLink extends MenuLinkDefault {

  /**
   * Determine my dynamic parameter and add it to the route's parameters.
   */
  public function getRouteParameters() {
    $original_params = $this->pluginDefinition['route_parameters'] ?: [];

    $my_dynamic_params = [
      'example_param' => $this->getMyDynamicRouteParameter(),
    ];

    return $my_dynamic_params + $original_params;
  }

  /**
   * Disable my menu link if a real dynamic parameter can't be determined.
   */
  public function isEnabled() {
    // If we can't determine our route parameter, disable the link.
    if ($this->canDetermineMyRouteParameter() !== TRUE) {
      return FALSE;
    }

    return parent::isEnabled();
  }

}

```

Then, my MY\_MODULE.links.menu.yml file:

```
my_module.my_custom_route_link:
  title: 'My Custom Link'
  route_name: my_module.my_custom_route
  route_parameters:
    example_param: 0 # Dynamically set in ExampleMenuLink.
  class: Drupal\my_module\Plugin\Menu\ExampleMenuLink

```

Since the route parameter is required, I could only get this to work by passing a dummy parameter in my link definition, e.g. `example_param: 0`. In my case, I was passing an entity id so 0 would never be valid. This parameter will never be used anyway because in the ExampleMenuLink::isEnabled() method, I disable the link if I can't get an appropriate value for my dynamic parameter. Additionally, I implement ExampleMenuLink::getRouteParameters() to add my dynamic parameter and pass it to the route.
> 0 votes

---
Tags: 8, routes, navigation
---


# Question
Title: Entity Browser Modal closes on Exposed Filter Submit Button
I've set up a commerce shop that uses Entity Browser to select product images. I set up a view to display the selectable images which has an exposed filter for the filename, so the user can search for the name of an image and then select it.

The entity browser works as desired, but if the user clicks the "apply"-button of the filter, the modal closes. Same behaviour with an iframe as well.

When I set the theme to Bartik it works. When I set the theme to Olivero, the modal isn't closed, but the filter is not applied.

Would be great, if someone could point me any way to resolve this issue or just give me a hint where and how to investigate this further. Thank you very much in advance!

# Answer
> 1 votes
It was my fault all along, since I have overwritten views-view.html.twig in my custom theme and removed the div where the "js-view-dom-id-xxx" is set. This one is obviously needed when the exposed filter relies on AJAX.

But why it doesn't work in Olivero I didn't figure out tho.

---
Tags: views, entities, 9, modal-dialogs
---


# Question
Title: In a hook, how can I distinguish between web users and JSON:API users?
I have a Drupal website that also hosts an Ionic app via JSON:API. I want website users to be redirected on entity insert, so I added a redirect like this:

```
function MYMODULE_flagging_insert(FlaggingInterface $flagging) {
  $redirect_url = Url::fromRoute(MYCLASS::SECRET_ROUTE)->toString();
  $response = new RedirectResponse($url);
  $response->send();
}

```

This code will redirect web users as expected when they add a flag. However, this code breaks the JSON:API app. When I add a flag with a user from JSON:API, I get this error:

```
    RuntimeException: Failed to start the session because headers have already been sent by "/app/vendor/symfony/http-foundation/Response.php" at line 384. in Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->start() (line 152 of /app/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php)
#0 /app/web/core/lib/Drupal/Core/Session/SessionManager.php(162): Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->start()
#1 /app/web/core/lib/Drupal/Core/Session/SessionManager.php(193): Drupal\Core\Session\SessionManager->startNow()
#2 /app/vendor/symfony/http-foundation/Session/Session.php(189): Drupal\Core\Session\SessionManager->save()
#3 /app/web/core/lib/Drupal/Core/StackMiddleware/Session.php(60): Symfony\Component\HttpFoundation\Session\Session->save()
#4 /app/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#5 /app/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#6 /app/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#7 /app/vendor/asm89/stack-cors/src/Asm89/Stack/Cors.php(60): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#8 /app/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Asm89\Stack\Cors->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#9 /app/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(52): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#10 /app/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#11 /app/web/core/lib/Drupal/Core/DrupalKernel.php(716): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#12 /app/web/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#13 {main}

```

So is there a way to detect in an insert hook (or other hooks) whether the user is logged in through the Drupal website or through JSON:API?

I want to add a redirect if the user is accessing Drupal through the website, but I don't want to use a redirect if the user is accessing Drupal through the app.

# Answer
> 3 votes
Using redirects with `$response->send()` like this used to work:

```
  $response = new RedirectResponse($url);
  $response->send();

```

But, this no longer works in Drupal 9.2. Also, it breaks JSON:API in versions before 9.2. The correct way to do it is described in detail in this excellent answer.

Basically, you need to create your own custom `http_middleware` to handle the redirects. Since `http_middleware` only applies to http/web requests, it doesn't interfere with JSON:API, so the problem is solved.

---
Tags: hooks, redirection
---


title: Taxonomy term save very slow

text:
# Question
Title: Taxonomy term save very slow
I have a vocabulary with around 15k+ terms in multi-level hierarchies. Recently I noticed that with this amount of data, when I try to save a term of a higher level (parent to many), it takes a lot of time to save.

I checked with the webprofiler module and saw there was around 10k queries running for such a single term including the queries it is running for it's children. I am not sure if this is expected, but is there a way I can speed up the process? These queries includes tables like cache, path\_alias, taxonomy\_term\_data, taxonomy\_term\_revision, key\_value etc.

I have tried applying memcached that considerably reduces the queries, specially from the cache tables, but still the child term queries are run slowing down the process.

I also considered running the process in background, but in that case also, it supposedly should take the same amount of server resources. The problem is so much so that my entire application is going into a halt state (sometimes unavailable) when I am updating some terms through a drush command.

Any help?

# Answer
I found the reason from where the problem is originating. It is from the pathauto module which has an entity update hook that loads all the children every time a taxonomy term is being saved. It is done to update the children's alias along with the parent that is being saved. I am thinking of opening a ticket in their issue queue. The idea should be to update the child aliases only when their is a dependency on the a parent attribute. Like /term/\[parent-term-name\]/\[child-term-name\]. Not only that, it should ideally be processed in a queue worker with a transaction lock maybe. Hope this helps somebody.
> 2 votes

---
Tags: entities, taxonomy-terms
---


# Question
Title: How can I render a view as JSON inside a template file?
I would like to render a view as JSON, within the page template. I would hide it with CSS and use it with JavaScript.

Is there a way to alter the *Format* field used when creating a view, which normally shows options like *Grid*, *HTML List*?

I did try the *Rest Export* core module, but it seems to render the view as JSON with no other page content.

# Answer
Though originally I wanted to avoid making subsequent requests to the server, it seems its the easiest way to get around this. Just make some views that output json and load them with ajax.
> 0 votes

---
Tags: 8, views
---


# Question
Title: Hook_form_alter for changing field labels doesn't work of user registration page
Can anyone tell me why this isn't working (in the below code, or other factors preventing the insert by the hook)? I don't get an error message or page, the field labels are simply not overwritten...

I created my own module with the following hook on Drupal 8.5.7:

```
function MYMODULE_form_alter(&$form, Drupal\Core\Form\FormStateInterface $form_state, $form_id){

  if ($form_id == 'user_register_form') {

    $form['field_user_first_name']['widget']['0']['#title'] = 'First Name';
    $form['field_user_last_name']['widget']['0']['#title'] = 'Last Name';
    $form['field_user_phone_number']['widget']['0']['#title'] = 'Phone Number';
    $form['field_user_country_of_residence']['widget']['0']['#title'] = 'Country (of residence)';
  }
}

```

# Answer
> 9 votes
1. Simple Solution just change `['0']['#title']` by `[0]['value']['#title']`.

```

/**
 * @param $form
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 * @param $form_id
 */
function MYMODULE_form_alter(&$form, Drupal\Core\Form\FormStateInterface $form_state, $form_id){
    if ($form_id == 'user_register_form') {
        $form['field_user_first_name']['widget'][0]['value']['#title'] = 'First Name';
        $form['field_user_last_name']['widget'][0]['value']['#title'] = 'Last Name';
        $form['field_user_phone_number']['widget'][0]['value']['#title'] = 'Phone Number';
        $form['field_user_country_of_residence']['widget'][0]['value']['#title'] = 'Country (of residence)';
    }
}

```
2. This solution a little bit complicated.
After i test your code, i did some search, i found this Post say
> It is apparent that we modify any form in drupal by implementing hook\_form\_alter(). But there are cases when even the hook\_form\_alter() cannot offer a solution in altering the form fields.

I tried to use hook\_element\_info\_alter as it suggested to alter fields. In your case Here is the code bellow.

```

/**
* Implements hook_element_info_alter().
*/
function MYMODULE_element_info_alter(&$type) {
  if (isset($type['textfield'])) {
    $type['textfield']['#process'][] = 'MYMODULE_process_textfield';
  }
}

`/**
* Process Callback Function
*
* Callback to process the User fields.
*/
function MYMODULE_process_textfield($element) {
  //- get the current route name
  $route_name = \Drupal::routeMatch()->getRouteName();
  if ($route_name == 'user.register' && isset($element['#array_parents'][0])) {
    switch ($element['#array_parents'][0]) {
      case 'field_user_first_name':
        $element['#title'] = 'New first name label';
        break;
      case 'field_user_last_name':
        $element['#title'] = 'New last name label';
        break;
      case 'field_user_phone_number':
        $element['#title'] = 'New phone numbe label';
        break;
      case 'field_user_country_of_residence':
        $element['#title'] = 'New country of residence label';
        break;
    }
  }
  return $element;
}`

```

**Note** : all the four fields should be of type `textfield` `Text (plain)`, otherwise you should add another process to other `type`, see the example in the article for `password_confirm` type.

# Answer
> 2 votes
following the link posted by @leymannx I clicked through to another question, which had the solution somewhere in the comments.

I forgot to put **\['value'\]** in the string, so it had to be :

```
$form['field_user_first_name']['widget']['0']['value']['#title'] = 'First Name';

```

I can confirm it works with both :

* \['0'\] and \[0\]
* = t('first name') and = 'first name'

I doesn't work, at least for me, with omitting **\['widget'\]\['0'\]\['value'\]**, as suggested in alter the labels used on the login form – berramou

# Answer
> 0 votes
Try it without `[0]`, I don't think you need this.

---

**Edit** Okay let me rephrase my words per @leymannx. I have tested the code on my machine and removing `[0]` solves the problem and updates the label text. I was providing an answer and was not asking for more information or anything from the author.

# Answer
> 0 votes
In this approach, the hook is fired for all forms To avoid extra firing of the hook, use this approach (module name and form id)

```
function MYMODULE_user_register_form_alter(&$form, Drupal\Core\Form\FormStateInterface $form_state, $form_id){
  //do your alteration
}

```

---
Tags: 8, forms, hooks
---


# Question
Title: drush config-status on translation / language config files?
Similar with but not the same as How to use drush config:set for translations?, is there a way to scan for a site's language config changes via drush or so?

I have a lot of sites on the same server (multi-site), and I would rather check on this via a drush command than having to log in each of the sites to look at the output of `/admin/config/development/configuration`.

For normal config changes I could run `drush cst | config-status` but this doesn't appear to work for language config and puts the site at risk of accidentally wiped out language config when not captured.

**Example:**

```
$ drush cst -- returns nothing

```

```
$ drush cget language.fr:block.block.claro_breadcrumbs
settings:
  label: 'Breadcrumbs FR'

```

# Answer
The `config-status` command doesn't show the config's relevant collection, which is how I got confused, but @Patrick Kenny is right, the output does list the language config files.

One solution would be to create a custom drush command similar to `Drush\Drupal\Commands\config\ConfigCommands`, and alternatively `config-import` does highlight the collection. So one can run `drush cim | config-import` without proceeding after the confirmation prompt, so you don't lose the config:

```
$ drush cst -- does not show collection
------------------------------- ------------
 Name                            State
------------------------------- ------------
 block.block.claro_breadcrumbs   Only in DB
------------------------------- ------------

```

```
$ drush cim -- does show collection
+-------------+-------------------------------+-----------+
| Collection  | Config                        | Operation |
+-------------+-------------------------------+-----------+
| language.fr | block.block.claro_breadcrumbs | Delete    |
+-------------+-------------------------------+-----------+

Import the listed configuration changes? (yes/no) [yes]:

```
> 1 votes

---
Tags: 8, drush, configuration
---


title: How do I migrate users passwords?

text:
# Question
Title: How do I migrate users passwords?
I want to migrate some users from my Drupal 7 installation to a new Drupal 8 installation. I do not want to migrate the whole site or any content. And I also do not want to migrate all users.

The problem is the password; I can export from Drupal 7 and import users to Drupal 8, but the passwords do not work anymore. I've also tried to update the hashes (password) in the database directly; so I copied the password fields from Drupal 7 to Drupal 8. That also doesn't work; I think the salt changed in Drupal 8.

Is there any solution for this?

# Answer
> 4 votes
Sorry for the confusion. **Clarification**:

Copying over the hashes from D7 to D8 works (I made a mistake with a backslash in the JSON output)!

So just copy over the D7 hashes (starting with $S$) from the D7.users.pass field to the D8.users\_field\_data.pass field. It will work. The first time, that the users logs in to the new D8 site, the password gets rehashed with the D8 algorithm (PhpassHashedPassword.check() and PhpassHashedPassword.needsRehash() are doing the magic).

Everything is fine :-) Thanks.

EDIT: Someone requested the code for this...

Here is my controller class that imports all the Drupal 7 users found in the file asde2.users.json:

```
  public function importAsde2Users() {
    // load asde2 user file
    $usersfile = $_SERVER['DOCUMENT_ROOT']."/".drupal_get_path('module', 'preosuser')."/asde2.users.json";
    PxLog::debug($this, "Loading asde2 users file ".$usersfile);
    // decode json array of objects
    $users = json_decode(file_get_contents($usersfile));
    PxLog::debug($this, "Found ".count($users)." Users in that file");
    $database = \Drupal::database();
    // import all of them
    foreach ($users as $user) {
      $newuser = \Drupal\user\Entity\User::create([
          'name' => $user->name,
          'pass' => $user->pass,
          'mail' => $user->mail,
          'status' => $user->status,
          'init' => $user->init,
          'created' => $user->created,
          'login' => $user->login,
          'access' => $user->access,
          'uid' => $user->uid,
        ]);
      $newuser->addRole("xx");
      $newuser->addRole("yy");
      $newuser->save();
      // dirty overwrite re-hashed hash
      $database->merge('users_field_data')
        ->fields(['pass' => $user->pass])
        ->keys(array('uid' => $user->uid))
        ->execute();
    }

    return ['#markup' => "Created ".count($users)." Users with that file", '#cache' => ['max-age' => 0]];
  }

```

Have fun.

# Answer
> 0 votes
This issue appears to have been resolved in: https://www.drupal.org/node/2598038

which was merged into core as of 8.1.4.

In order to preserve pre-hashed passwords, add the following to your migration YAML file:

```
destination:
  plugin: entity:user
  pre_hashed: true

```

---
Tags: users, 8, migrations
---