# Question
Title: Email does not contain a link to the file attached to the contact form
I am using the following code that programmatically creates a file and attaches it to a file field when a contact form is submitted.

```
function mymodule_form_alter(&$form, &$form_state, $form_id) {
  $form['actions']['submit']['#submit'][] = 'custom_submit_handler';
}

function custom_submit_handler(&$form, &$form_state) {
  $file_contents = '777';
  $filename = 'my_file.txt';
  $file = File::create([
    'uri' => 'public://' . $filename,
    'filename' => $filename,
  ]);

  $file->save();
  file_put_contents($file->getFileUri(), $file_contents);

  $entity = $form_state->getFormObject()->getEntity();
  $entity->get('my_field_file')->appendItem($file);
  $entity->save();
}

```

The code works as expected, but there is no link to the new file in the sent email.

What should I do to change the email message?

# Answer
The solution is to use hook\_entity\_presave() instead of hook\_form\_alter()

```
function mymodule_entity_presave(\Drupal\Core\Entity\EntityInterface $entity) {
  if ($entity->getEntityTypeId() == 'contact_message') {
    //create and save file
            ...
    //then
    $entity->set('my_field_file', $file);
  }
}

```
> 0 votes

# Answer
In order to enhance the content of our outgoing emails, I strongly recommend utilizing the hook\_mail\_alter function. This function allows us to modify the email content dynamically just before it is sent. By leveraging this feature, we can personalize and optimize our messages to better engage our recipients.

To learn more about hook\_mail\_alter and how to implement it effectively, I encourage you to visit the following link: hook\_mail\_alter.

The provided documentation will guide you through the process of using hook\_mail\_alter to tailor the content of our emails to suit specific scenarios and recipients. It's a powerful tool that can help us improve the effectiveness of our communication efforts.

```
 function hook_mail_alter(&$message) {
   if ($message['id'] == 'modulename_messagekey') {
    if (!example_notifications_optin($message['to'], $message['id'])) {

     // If the recipient has opted to not receive such messages, cancel
     // sending.
     $message['send'] = FALSE;
     return;
   }
   $message['body'][] = "--\nMail sent out from " . \Drupal::config('system.site')
  ->get('name');
    }
 }

```
> -2 votes

---
Tags: emails, 10
---


# Question
Title: Can I use Views Bulk Operations or something similar to create an archive of files generated by Views data export?
Using Views Data Export, I have multiple CSV files generated/provided by several different displays. Rather than setting up something where the user clicks a "Download CSV" button corresponding to each Views display, I'd like to have a single button where all of the files are zipped into a single archive file that is downloaded.

I know Views Bulk Operations has the ability to take multiple managed files and create a zip archive from them... Is it possible to use custom actions or VBO somehow to achieve what I'm looking to do? Or is there a better way to do something like this? Any advice would be appreciated!

# Answer
You can apply the patch from #1436726 which adds VBO integration into Views Data Export module, however it's for Drupal 7.x.

```
diff --git a/views_data_export.module b/views_data_export.module
index 0a8c90b..9b7b784 100644
--- a/views_data_export.module
+++ b/views_data_export.module
@@ -272,6 +272,84 @@ function views_data_export_clear($export_id) {
   views_data_export_view_clear($export_id);
 }

+/**
+ * Implements hook_action_info().
+ */
+function views_data_export_action_info() {
+  return array(
+    'views_data_export_action_csv_export' => array(
+      'type' => 'entity',
+      'label' => t('Export to CSV'),
+      'configurable' => FALSE,
+      'aggregate' => TRUE,
+      'behavior' => array('views_data_export_export_csv'),
+    ),
+  );
+}
+
+/**
+ * CSV export action callback.
+ */
+function views_data_export_action_csv_export($entity, &$context) {
+
+  if (isset($context['view_info'])) {
+    $view = views_get_view($context['view_info']['name']);
+    $display_id = FALSE;
+
+    foreach ($view->display as $display) {
+      if ($display->display_plugin == 'views_data_export') {
+        $display_id = $display->id;
+        break;
+      }
+    }
+
+    if ($display_id) {
+      $args = array();
+      // If a subset of the available entities was selected, provide the list
+      // of selected IDs to the view as a contrived argument, which we'll
+      // use later to alter the query.
+      // Extra code for backward/forward compatibility.
+      // @see https://www.drupal.org/node/2488146.
+      if (isset($context['view_info']['total_rows'])) {
+        $total_rows = $context['view_info']['total_rows'];
+      }
+      else {
+        $countView = clone $view;
+        $countView->execute($context['view_info']['display']);
+        $total_rows = $countView->total_rows;
+      }
+      $entity_ids = array_keys($entity);
+      if (count($entity_ids) < $total_rows) {
+        $args['entity_ids'] = implode('+', $entity_ids);
+      }
+      $view->execute_display($display_id, $args);
+      // If the export is configured to run as a batch job, it will handle the
+      // display of progress & result/download pages, deliver the generated
+      // file, and never return here. Otherwise, executing the display here
+      // won't cause the file to be delivered to the browser for download.
+      // Dying here ensures that it does, but there must be a better way.
+      die();
+    }
+    else {
+      drupal_set_message(t("Can't export data, because the !view view does not have a !display display.", array('!view' => $view->name, '!display' => 'views_data_export')), 'error');
+    }
+  }
+}
+
+/**
+ * Implements hook_views_query_alter().
+ */
+function views_data_export_views_query_alter(&$view, &$query) {
+  if ($view->display_handler->plugin_name == 'views_data_export') {
+    // If an explicit list of entity IDs was provided, use that to refine the
+    // query.
+    if (isset($view->args['entity_ids'])) {
+      $query->add_where(0, $view->base_table . '.' . $view->base_field, explode('+', $view->args['entity_ids']), 'IN');
+      // Now remove this fake argument to avoid confusion.
+      unset($view->args['entity_ids']);
+    }
+  }
+}

 /**
  * Store a view in the object cache.

```
> 1 votes

# Answer
For Drupal \>=8.x you can use VBO export module which extends VBO.

Then you can write your own plugin. Here is the example for a class:

```
<?php

namespace Drupal\my_module\Plugin\Action;

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

/**
 * Generates ZIP with exported files.
 *
 * @Action(
 *   id = "vbo_export_generate_zip_action",
 *   label = @Translation("Generate ZIP from selected view results"),
 *   type = ""
 * )
 */
class VboExportZip extends \Drupal\vbo_export\Plugin\Action\VboExportBase {

  const EXTENSION = 'zip';

  /**
   * {@inheritdoc}
   *
   * Settings for preliminary config.
   */
  public function buildPreConfigurationForm(array $form, array $values, FormStateInterface $form_state) {
    $form = parent::buildPreConfigurationForm($form, $values, $form_state);
    return $form;
  }

  /**
   * Output generated string to file. Message user.
   *
   * @param string $output
   *   The string that will be saved to a file.
   */
  protected function sendToFile($output) {
    if (!empty($output)) {
      $rand = substr(hash('ripemd160', uniqid()), 0, 8);
      $filename = $this->context['view_id'] . '_' . date('Y_m_d_H_i', $this->time->getRequestTime()) . '-' . $rand . '.' . static::EXTENSION;

      $wrappers = $this->streamWrapperManager->getWrappers();
      if (isset($wrappers['private'])) {
        $wrapper = 'private';
      }
      else {
        $wrapper = 'public';
      }

      $destination = $wrapper . '://' . $filename;

      $zip = new \ZipArchive();

      foreach ($output as $row) {
        // Adding one file at once.
        $opened = $zip->open(drupal_realpath($destination), \ZIPARCHIVE::CREATE);

        if (!$opened) {
          // Error.
          $this->messenger()->addStatus($this->t('Export failed!'));
          return;
        }

        $zip->addFile($row['file_path_abs'], $row['file_name']);
        $zip->close();
      }

      // ZIP file will be managed by Drupal. Also marking file as temporary.
      $file = File::create([
        'filename' => \basename($destination),
        'filemime' => 'application/zip',
        'uri' => $destination,
        'uid' => \Drupal::currentUser()->id(),
        'status' => 0,
      ]);
      $file->save();

      // Get relative url to prevent mixed content errors when using HTTPS + HTTP.
      $relative_url = \file_url_transform_relative(file_create_url($file->getFileUri()));
      $this->messenger()->addStatus($this->t('Export file created, <a href=":url" target="_blank">Click here</a> to download.', [':url' => $relative_url]));
    }
  }

  /**
   * Generate output string.
   */
  protected function generateOutput() {
    $rows = $this->getRows();

    // Generate output.
    $output = [];

    // @todo: Customize below.
    $output[] = [
      'file_name' => strip_tags($row['some_file_field']),
      // 'file_url' => $attachment['url'],
      'file_path_abs' => str_replace(["\\", '//'], '/', $attachment['path']),
      'file_mime_type' => $attachment['mime_type'],
    ];

    return $output;
  }

}

```

Place the code under `src/Plugin/Action/` in your `my_module` module (e.g. `VboExportZip.php`). Ensure you've `php-zip` extension installed (e.g. `apt install php-zip`).
> 1 votes

---
Tags: views, actions, importing-exporting
---


# Question
Title: How to disable a CKEditor5 package loaded by core?
Is there a way to disable a CKEditor5 package loaded by core? I would like to disable `paste-from-office`, but I can see the question here applying to different packages.

In the file `web/core/core.libraries.yml` we see this code:

```
ckeditor5.pasteFromOffice:
  remote: https://github.com/ckeditor/ckeditor5
  version: "35.4.0"
  license:
  name: GNU-GPL-2.0-or-later
  url: https://raw.githubusercontent.com/ckeditor/ckeditor5/v35.4.0/LICENSE.md
  gpl-compatible: true
js:
  assets/vendor/ckeditor5/paste-from-office/paste-from-office.js: { minified: true }
dependencies:
  - core/ckeditor5

```

I tried removing it but now when CKEditor loads on an edit page it complains about the missing library.

We also have in `web/core/modules/ckeditor5/ckeditor5.ckeditor5.yml`

```
ckeditor5_pasteFromOffice:
  ckeditor5:
    plugins: [pasteFromOffice.PasteFromOffice]
  drupal:
    label: Paste From Office
    library: core/ckeditor5.pasteFromOffice
    elements: false
    conditions: []

```

# Answer
> 0 votes
I was able to disable rich-text paste from office365.com by adding this code to one of my custom CKE5 modules:

```
editor.editing.view.document.on('clipboardInput', (evt, data) => {
  data.content = editor.data.htmlProcessor.toView(data.dataTransfer.getData('text/plain'));
});

```

I was able to disable rich-text paste from the Word app by removing the reference to it in `ckeditor5.ckeditor5.yml` quoted above.

No errors!

---
Tags: 10
---


# Question
Title: The specified database connection is not defined: default for Drupal drush
I have the following configurations for my Drupal site:

`sites/mysite/settings.local.php`

```
$databases['default']['default'] = array(
  'database' => 'mydb',
  'username' => 'root',
  'password' => 'password',
  'prefix' => '',
  'host' => '127.0.0.1',
  'port' => '',
  'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
  'driver' => 'mysql',
);

```

and for drush, I have : `drush/sites/local.site.yml`

```
mysite:
  root: /Users/me/Desktop/Work/Projects/mysite/docroot
  uri: mysite.local

```

Now when I run `drush @local.mysite cr` , I am getting:

```
The specified database connection is not defined: default

```

If I run `drush @local.mysite status`, I get:

```
Drupal version : 9.5.9
Site URI       : http://mysite.local
PHP binary     : /usr/local/Cellar/php@8.1/8.1.19/bin/php
PHP config     : /usr/local/etc/php/8.1/php.ini
PHP OS         : Darwin
Drush script   : /usr/local/bin/drush
Drush version  : 10.6.1
Drush temp     : /tmp
Drush configs  : /Users/me/Desktop/Work/Projects/mysite/vendor/drush/drush/drush.yml
Drupal root    : /Users/me/Desktop/Work/Projects/mysite/docroot
Site path      : sites/default

```

From this error, I assume that Drush is using the default settings and not the one specified for my site. But I have added the same database configurations to the default settings, which is not working. Also, I have copied the `settings.local.php`, but it also gives me the same error. I am new to Drupal, and it is an existing codebase that I am working on. It would be very helpful if someone could help me use Drush correctly so I can set up my local development environment.

I have tried to connect to database from the command line, and it is working and also I am able to access the database from PHPMyAdmin

# Answer
> 1 votes
I assume that the reason you get

```
The specified database connection is not defined: default

```

is because `sites/mysite/settings.local.php` isn't included by any `settings.php` file.

Look for example at the end of `sites/default/settings.php` (or `sites/default/default.settings.php`) to see how the local settings are normally loaded.

---
Tags: database, drush
---


title: Computed multiplication

text:
# Question
Title: Computed multiplication
I have a webform where I am using the *Twig Computed* module to calculate an amount. It is simple and straight forward: I have a field that captures the amount and I'm using Twig to multiply it to find the fee; the fee amount is a fixed rate

The Computed Value/Markup is `{{ data['license_amount']|number_format(2) * 0.019 }}`. It works when `data['license_amount']` is lower than 999; it shows a wrong total when `data['license_amount']` is higher than 999.

If the amount is 500 the value is 9.5 as it should.

If the amount is 5000 the value is returned as 0.095

# Answer
You should drop the `number_format` altogether (not sure what the requirement is), or place it at the end of the calculation, i.e.

`{{ (data['license_amount'] * 0.019)|number_format(2) }}`

`number_format` is a wrapper around PHP's number\_format function

From PHP's documentation page:

```
// english notation (default)
$english_format_number = number_format($number);
// 1,235

// French notation
$nombre_format_francais = number_format($number, 2, ',', ' ');
// 1 234,56

```

It seems like you are running the calculation on something like 5'000 or 5,000 (depending on your locale), which would explain the results you are getting.

Good luck!
> 1 votes

---
Tags: webforms, 9
---


# Question
Title: Token [current-page:url] is missing the language prefix in multi-language site setup
Using Drupal v9.4 and Token v1.10.0, the `[current-page:url]` doesn't seem to include the language prefix.

The setup is I have two languages: English and Spanish. I created a View where the path is `/articles` so I am able to access the View page using `/en/articles` and `/en-gb/articles`. I then added a Canonical URL using the Metatags module using the said token but it doesn't work.

# Answer
> 0 votes
If you need to use current page url, you could use `[current-request:uri]` for multilingal page.

e.g.

* access to `https://example.com/en`, `[current-request:uri]` reveals `https://example.com/en`

---
Tags: views, 9, tokens
---


# Question
Title: block_content routes have ambiguous paths
I'm trying to convert block forms (the content entity forms) into Gin Admin theme forms. Gin theme provides a hook for this:

```
function hook_gin_content_form_routes(): array {
  return [
    'entity.block_content.edit_form',
    'block_content.add_form',
  ];
}

```

This worked fine for new blocks (add\_form), but it did not work for existing blocks (edit\_form). After digging around, I found out that the content block edit form actually does not use this route. Instead the debugger told me the route name is `entity.block_content.canonical`. And digging in core's `block_content.routing.yml` I found two routes with ambiguous path names and parameters:

```
entity.block_content.canonical:
  path: '/block/{block_content}'
  defaults:
    _entity_form: 'block_content.edit'
  options:
    _admin_route: TRUE
  requirements:
    _entity_access: 'block_content.update'
    block_content: \d+

entity.block_content.edit_form:
  path: '/block/{block_content}'
  defaults:
    _entity_form: 'block_content.edit'
  options:
    _admin_route: TRUE
  requirements:
    _entity_access: 'block_content.update'
    block_content: \d+

```

While adding `entity.block_content.canonical` solved my problem, I don't understand what's going on here.

First, how can one path with identical options and parameters be part of 2 different routes? Isn't the 2nd route just dead weight?

And why is a *canonical* route used for editing? I thought canonical routes are meant to be used for frontend/view display, not for admin forms (e.g. `entity.node.canonical` and similar).

I'm asking those two questions because I am afraid of unintented side effects when adding a canonical route to Gin's form preprocessing.

# Answer
> 1 votes
First, you can define multiple routes for the same path. If more than one route matches the path the route is selected using different criteria like access, protocol, format, fit (the number of fixed path elements) or the alphabetical order of the route names.

And then, a block doesn't have a view route. Drupal duplicated the edit route so that they don't get errors from code expecting all entities to have a default aka canonical route. It's safe to add both routes to Gin. See https://www.drupal.org/project/drupal/issues/2873529

# Answer
> 2 votes
This acts like an alias - two routes to the same path. Routes are allowed to share paths. As Block Content, which are content entities, don't actually have a display page, the canonical link for the Block Content is set as the edit form. The edit form is also set as the edit form, because it's the edit form! If there was no canonical path for the block, scripts that loop through entity types and output their links would have a fatal error, so creating a canonical route standardizes block content to be able to be used in scripts the same as other content entities.

---
Tags: routes
---


# Question
Title: Returning long-running api response as a "download"
I'm working on a REST api endpoint which takes in an array of IDs, loads all of the entities associated with those IDs, does some processing on them, then returns them in a chosen format (csv, xls etc.).

This processing could take a long time with a large number of IDs, so I want to start returning data to the user immediately as if they are downloading a file (which they sort of are) and finish the download when the last entity is processed.

Is there a way to do that?

# Answer
Excellent comment by @Kevin. Drupal core doesn't use StreamedResponse, but as always the Webform module is a good resource for examples, which also shows the difference between viewing and downloading the streamed result:

*/modules/contrib/webform/modules/webform\_submission\_export\_import/src/Controller/WebformSubmissionExportImportController.php*

```
  /**
   * Returns the Webform submission export example CSV view.
   */
  public function view() {
    return $this->createResponse(FALSE);
  }

  /**
   * Returns the Webform submission export example CSV download.
   */
  public function download() {
    return $this->createResponse(TRUE);
  }

  /**
   * Create a response containing submission CSV example.
   *
   * @param bool $download
   *   TRUE is response should be downloaded.
   *
   * @return \Symfony\Component\HttpFoundation\Response
   *   A response containing submission CSV example.
   */
  protected function createResponse($download = FALSE) {
    $webform = $this->importer->getWebform();

    // From: http://obtao.com/blog/2013/12/export-data-to-a-csv-file-with-symfony/
    $response = new StreamedResponse(function () {
      $handle = fopen('php://output', 'r+');

      $header = $this->importer->exportHeader();
      fputcsv($handle, $header);

      for ($i = 1; $i <= 3; $i++) {
        $webform_submission = $this->generateSubmission($i);
        $record = $this->importer->exportSubmission($webform_submission);
        fputcsv($handle, $record);
      }

      fclose($handle);
    });

    $response->headers->set('Content-Type', $download ? 'text/csv' : 'text/plain');
    $response->headers->set('Content-Disposition', ($download ? 'attachment' : 'inline') . '; filename=' . $webform->id() . '.csv');
    return $response;
  }

```

When testing this module you won't see much of a streaming effect when viewing the result in the browser because of the buffering enabled in most web servers. You need much higher numbers of items, like `$i <= 3000`, to fill up the buffers and get a streaming effect for a few seconds.
> 0 votes

---
Tags: 9
---


# Question
Title: How to get a menu link UUID from a menu tree item?
I'm trying to create a select box like the one that allows the selection of a menu parent on the node form. I might be barking up the wrong tree in my approach. I figured if I can get an array of menu link titles and UUIDs I will have what I need.

I tried this:

```
$menus = Menu::loadMultiple();
$menu_tree_service = \Drupal::service('menu.link_tree');
foreach($menus as $menu) {
  $id = $menu->id();
  $parameters = new \Drupal\Core\Menu\MenuTreeParameters();
  $parameters->setMaxDepth(2);
  $tree = $menu_tree_service->load($id, $parameters);
  foreach ($tree as $item) {
    $title = $item->link->getTitle();
  }
}

```

This does give me the menu link title, but I see no path to the UUID, and I believe I need that downstream to dynamically add a child link at that position.

# Answer
The UUID of menu links defined in content, not in code, is the derivative ID of the menu link plugin:

```
$item->link->getDerivativeId();

```

For setting a parent you probably want the entire plugin ID, which includes the UUID for a content menu link:

```
$item->link->getPluginId();

```
> 1 votes

---
Tags: 9, navigation
---


# Question
Title: Cascade dropdown list aka dependent dropdown list
Is there any way to make a cascade dropdown list aka dependent dropdown list for a "survey" content type?

Apart from the "survey" content type. I have three other content types: country, state and district. Each of these types are linked by entity references.

In the "survey" content I have created 3 dropdownlists, one for country, state and district. I am filling these lists with content types that I created specially for each one, that is to say, one content type for country, another for state and another for district.

So far so good. But I would like that when I change one of them, the others change dynamically. I have been able to do it with views, but not dynamically. Is there any solution without programming?

Or is there another way to do this?

I have read countless blogs and sites. However, I have not been able to achieve this.

# Answer
Yes, there is a way to achieve this. One of the best options is to use AJAX dependent drop-down. It requires custom code however. There are some good articles in the net which I saw solving this. You may find a very decent example in the `examples` module here

What it does is to build one dropdown and on changing its value, to calculate the options for the next one and so on. I used such technique several times in my projects already.

Good luck!
> 0 votes

---
Tags: views
---


title: Style image is not created

text:
# Question
Title: Style image is not created
## I have a D7 (7.72) news website (multi-lingual), it started on 2023-06-07, that no image upload or update could create style in sites/default/files/styles although it uploads to the sites/default/files folder. It is the same on all content types. The path and also itok is being generated but the styled file is not there! Web server is LiteSpeed (php 7.73 , db: MariaDB 10), I have 19968 nodes, 21397 images with a total size of 4.18G in sites/default/files folder. I have also checked permission 777, also updated all core (to 7.97) with all modules, but none helped. I wrote a small php code to copy a file to the folder, manually copied files with no problem, and I get no php error in the php-log file. I cleared all image caches but lost all the images and none could be re-generated, so I had to go back to back up and a day ago. I have 3 other domains running D7 on the same hosting plan, all of them are ok. Can you please help me or give me a clue? Thank you,

ps. Now I have installed HTTPRL and I get this: Core drupal\_http\_request() Your system or network configuration does not allow Drupal to access web pages. This could be due to your webserver configuration or PHP settings. Debug info: Array ( \[0\] =\> Array ( \[0\] =\> Array ( \[count\] =\> 1 \[time\] =\> 7289.85 \[mode\] =\> 2 \[blocking\] =\> FALSE \[url\] =\> https://191.101.104.233/httprl\_async\_function\_callback?count=1 \[request\] =\> Array ( \[https://191.101.104.233/httprl\_async\_function\_callback?count=1\] =\> stdClass Object ( \[url\] =\> https://191.101.104.233/httprl\_async\_function\_callback?count=1 \[status\] =\> Connecting. \[code\] =\> -1004 \[chunk\_size\] =\> 1024 \[data\] =\> \[request\] =\> POST /httprl\_async\_function\_callback?count=1 HTTP/1.0 Host: www.iranstar.com Connection: closed User-Agent: Drupal (+http://drupal.org/) Content-Type: application/x-www-form-urlencoded Content-Length: 554

# Answer
The problem was on the strange behavior of the built-in CDN on the server. I turned that off and everything went back to normal. Also please consider adding "Options +SymLinksIfOwnerMatch" to /sites/default/files/.htaccess and apply to its subdirectories
> 0 votes

---
Tags: 7, media
---


title: "Most popular" tags of the day

text:
# Question
Title: "Most popular" tags of the day
How can I create a list of the most popular tags of the day, based on the actual date, using view?

The most voted answer for Most popular tags in a list as a block helped me to set a list of the "most popular" tags using contextual filters and aggregation, but I couldn't find a way to show only the tags of the day.

Can you help me?

# Answer
> 1 votes
I've built something similiar to this in the past with Redis. Each time a 'tag' is hit, it gets one point. Every hour, the value of all scores, for everything hit *ever* is dropped by 10%. Then you order by points.

So a tag that gets hit 10 times in the first hour, will have 10 points. After an hour, those points are degraded 10%, leaving 9 points. An hour later, it's 8.1 points, then 7.2 points and so on. Of course, more views adds more points.

Since all scores are degraded 10% every hour, the value of previous hits received drops over time, and anything that is being hit regularly, or even going viral, will have more undegraded points.

In Drupal terms for example, consider a tag that is a taxonomy term attached to a comment. When new comments are saved, you can loop through any attached terms in hook\_comment\_insert() to add a point for each tag:

```
function HOOK_comment_insert(\Drupal\Core\Entity\EntityInterface $comment) {
  foreach ($comment->get('field_tag')->value as $tag) {
    some_php_function_that_adds_a_point_for_a_tag_in_reds($tag);
  }
}

```

Then, you would want to create a cron implementation that degrades the points stored in Redis:

```
function HOOK_cron() {
  some_function_that_deletes_all_tag_scores_by_10_percent();
}

```

And you set the cron to run every hour. Although, in a real-world setting, I would actually integrate my module with the Ultimate Cron module for more granular control over cron runs, to better ensure that my process is run every hour.

---
Tags: views, taxonomy-terms, 9
---


# Question
Title: How to save a customer profile to address book in Drupal Commerce using JSON:API
In the commerce order checkout page, if you use "Save to my address book" checkbox in the billing address section, the address is getting saved to the user's address book. But if I am doing this using JSON request, how can I save the address to the user's address book and how can I load the saved addresses.

# Answer
> 0 votes
How you save depends somewhat on your desired UX. If you look at the code in the `BillingInformation` checkout pane (in the checkout module) or the `CustomerProfile` inline form plugin (in the order module), you'll see some properties used to instruct Commerce how and when to copy addresses to the addressbook.

If it's fine for your addresses to be copied when the order is placed (i.e. not immediately upon them being entered on a checkout form), then you can simply get by with setting `copy_to_address_book` in the profile's data array to `TRUE`. This will get picked up by the `AddressBookSubscriber` (in the order module), resulting in the address being copied to the user's addressbook upon order placement.

Other options would be discoverable through the way the checkout pane functions. There is no way, as far as I know, to trigger an immediate copy merely by the save of the profile, but I haven't looked deeply at Commerce API to confirm.

---
Tags: 8, commerce
---


# Question
Title: Programmatically saving data in a field under user account
QR codes have been printed out for a bunch of students in a university. When they visit the site via those QR codes, and they are logged-in, the *refcode* query parameter used in the link needs to be saved for their account in a *field\_usr\_ref\_code* field (a *Text (plain)* field).

In a .module file I am using the following code.

```
use Drupal\user\Entity\User;

/**
 * Implements hook_entity_load().
 */
function my_custom_module_entity_load() {
  $refcode = \Drupal::request()->query->get('refcode');
  $user_id = \Drupal::currentUser()->id();
  if ($user_id > '0' && isset($refcode)) {
    $account = User::load($user_id);
    $account->set('field_usr_ref_code', $refcode);
    $account->save();
  }
}

```

However, for some reason no data is being saved, without any logged error.

What is wrong with the code I am using?

# Answer
> 1 votes
Use a request event subscriber with a priority of 299:

*/src/EventSubscriber/MymoduleSubscriber.php*

```
<?php

namespace Drupal\mymodule\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\RequestEvent;

/**
 * Mymodule event subscriber.
 */
class MymoduleSubscriber implements EventSubscriberInterface {

  /**
   * Kernel request event handler.
   *
   * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
   *   The request event.
   */
  public function onKernelRequest(RequestEvent $event) {
    if (!$event->isMainRequest()) {
      return;
    }
    // put here your code
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      KernelEvents::REQUEST => ['onKernelRequest', 299],
    ];
  }
}

```

*mymodule.services.yml*

```
services:
  mymodule.event_subscriber:
    class: Drupal\mymodule\EventSubscriber\MymoduleSubscriber
    tags:
      - { name: event_subscriber }

```

Drupal runs authentication with priority 300.

This code is for Drupal 9/10.

For Drupal 8 you need to use Symfony\Component\HttpKernel\Event\GetResponseEvent and $event-\>isMasterRequest().

---
Tags: 8, users
---


# Question
Title: InvalidArgumentException... Class not Found in Custom Module
Here is the simplified error:

> InvalidArgumentException: Class "\Drupal\prepcart\Controller\PrepCartController" does not exist. in Drupal\Core\DependencyInjection\ClassResolver-\>getInstanceFromDefinition() (line 24 of core/lib/Drupal/Core/DependencyInjection/ClassResolver.php).

*Full Stack Trace:*

> The website encountered an unexpected error. Please try again later. InvalidArgumentException: Class "\Drupal\prepcart\Controller\PrepCartController" does not exist. in Drupal\Core\DependencyInjection\ClassResolver-\>getInstanceFromDefinition() (line 24 of core/lib/Drupal/Core/DependencyInjection/ClassResolver.php). Drupal\Core\Controller\ControllerResolver-\>createController('\Drupal\prepcart\Controller\PrepCartController::content') (Line: 74) Drupal\Core\Controller\ControllerResolver-\>getControllerFromDefinition('\Drupal\prepcart\Controller\PrepCartController::content', '/cart') (Line: 91) Drupal\Core\Controller\ControllerResolver-\>getController(Object) (Line: 132) Symfony\Component\HttpKernel\HttpKernel-\>handleRaw(Object, 1) (Line: 64) Symfony\Component\HttpKernel\HttpKernel-\>handle(Object, 1, 1) (Line: 57) Drupal\Core\StackMiddleware\Session-\>handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\KernelPreHandle-\>handle(Object, 1, 1) (Line: 98) Drupal\page\_cache\StackMiddleware\PageCache-\>pass(Object, 1, 1) (Line: 77) Drupal\page\_cache\StackMiddleware\PageCache-\>handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\ReverseProxyMiddleware-\>handle(Object, 1, 1) (Line: 50) Drupal\Core\StackMiddleware\NegotiationMiddleware-\>handle(Object, 1, 1) (Line: 23) Stack\StackedHttpKernel-\>handle(Object, 1, 1) (Line: 628) Drupal\Core\DrupalKernel-\>handle(Object) (Line: 19)

**Relevant information**: Drupal Core 8.1.8 (I know 8.2 is out but this shouldn't matter I believe - we are pinned to this version due to Lightning)

And here is the relevant files involved:

**PrepCartController.php**

```
<?php
/**
 * @file
 * Contains \Drupal\prepcart\Controller\PrepCartController.
 */
namespace Drupal\prepcart\Controller;
use Drupal\Core\Controller\ControllerBase;
class PrepCartController extends ControllerBase {
  public function content() {
    return array(
      '#type' => 'markup',
      '#markup' => $this->t('Hello, IHM!'),
    );
  }
};

```

To make life easier this is the directory structure:

```
drwxr-xr-x   170B Oct 18 07:05 ./
-rw-r--r--   222B Oct 18 06:36 ./prepcart.info.yml
-rw-r--r--   195B Oct 18 07:05 ./prepcart.routing.yml
drwxr-xr-x   102B Oct 18 06:53 ./src/
drwxr-xr-x   102B Oct 18 06:54 ./src/Controller/
-rw-r--r--   349B Oct 18 06:54 ./src/Controller/PrepCartController.php

```

For some reason the module won't show on the modules page but I can interact with it fine on the CLI using drush?

Trust me when I say I have been ALL over Google and Stack for this. Major love to whomever can help me here.

# Answer
I had the same problem once, clearing caches from drush was not sufficient. I cleared them from the drupal interface and the error message was gone...
> 4 votes

# Answer
I am facing Similar Kind of Issue once at drupal 10

My code:

Routing File:

```
learning.learningpage:
  path: "myworld"
  defaults:
    _controller: 'Drupal\learning\Controller\MyLearningWorldController::showData'
    _title: "This is my learning World"
  requirements:
    _permission: "content access"

```

Controller:

```
<?php
namespace Drupal\learning\Controller;
use Drupal\Core\Controller\ControllerBase;

class MyLearningWorldController extends ControllerBase{

    public function showData(){
        return [
            '#markup' => 'Enter My learning World'
        ];
    }
}

```

I got error :

`InvalidArgumentException: Class "Drupal\learning\Controller\MyLearningWorldController" does not exist. in Drupal\Core\DependencyInjection\ClassResolver->getInstanceFromDefinition() (line 24 of C:\xampp\htdocs\d10\web\core\lib\Drupal\Core\DependencyInjection\ClassResolver.php).`

I have clear cache using Drush , but error still not solved.

After that I have clear cache from admin panel (admin/config/development/performance). Then issue solved for me.
> 0 votes

---
Tags: 8
---


# Question
Title: How can I change the query string used in pages showing search results from keys=football to keyword=football?
Search results are given in a page whose URL is, for example, https://example.com/search/node?keys=football. This URL is not recognized by Google Analytics as a search result URL.

How can I change the search URL to https://example.com/search/node?keyword=football?

# Answer
URLs output by Drupal can be altered by a tagged service that uses a class which implements two interfaces: `OutboundPathProcessorInterface` and `InboundPathProcessorInterface`. (I use links for Drupal 9 documentation pages simply because the Drupal 10 documentation pages do not yet show all the parameter descriptions.)

You can use the code used for the path\_alias.path\_processor service (the one that handles path aliases) as example code.

### .services.yml

```
services:
  path_alias.path_processor:
    class: Drupal\path_alias\PathProcessor\AliasPathProcessor
    tags:
      - { name: path_processor_inbound, priority: 100 }
      - { name: path_processor_outbound, priority: 300 }
    arguments: ['@path_alias.manager']

```

### Service class

```
class AliasPathProcessor implements InboundPathProcessorInterface, OutboundPathProcessorInterface {

  /**
   * An alias manager for looking up the system path.
   *
   * @var \Drupal\path_alias\AliasManagerInterface
   */
  protected $aliasManager;

  /**
   * Constructs a AliasPathProcessor object.
   *
   * @param \Drupal\path_alias\AliasManagerInterface $alias_manager
   *   An alias manager for looking up the system path.
   */
  public function __construct(AliasManagerInterface $alias_manager) {
    $this->aliasManager = $alias_manager;
  }

  /**
   * {@inheritdoc}
   */
  public function processInbound($path, Request $request) {
    $path = $this->aliasManager->getPathByAlias($path);
    return $path;
  }

  /**
   * {@inheritdoc}
   */
  public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
    if (empty($options['alias'])) {
      $langcode = isset($options['language']) ? $options['language']->getId() : NULL;
      $path = $this->aliasManager->getAliasByPath($path, $langcode);

      // Ensure the resulting path has at most one leading slash, to prevent it
      // becoming an external URL without a protocol like //example.com. This
      // is done in \Drupal\Core\Routing\UrlGenerator::generateFromRoute()
      // also, to protect against this problem in arbitrary path processors,
      // but it is duplicated here to protect any other URL generation code
      // that might call this method separately.
      if (strpos($path, '//') === 0) {
        $path = '/' . ltrim($path, '/');
      }
    }
    return $path;
  }

}

```

`processOutbound()` changes the URLs output by Drupal. The query values are passed in `$options['query']`. To change the *keys* value to *keyword*, you just need to use code similar to the following one.

```
if (isset($options['query']['keys'])) {
  $keys = $options['query']['keys'];
  unset($options['query']['keys']);
  $options['query']['keyword'] = $keys;
}

```

You also need to check the path is the one you expect, for example with `if ($path == '/search/node') { /* … */ }`.

`processInbound()` changes the URLs received from Drupal before it can handle them. The query parameters are returned from `$request->query->get()` (for example, `$request->query->get('keyword')`). A query parameter is set with `$request->query->set()` (for example, `$request->query->set('keyword', $request->query->get('keys'))`).

You will also need to set the priority of your *path\_processor\_inbound* lower than the one used by *path\_alias.path\_processor* (so it is executed after it), and the priority of your *path\_processor\_outbound* higher than the one used by *path\_alias.path\_processor* (so it is executed before it, and it gets the original path, not the path alias, in `$path`).

This method works also in the case the search page showing the results is overridden by a view.
> 4 votes

---
Tags: search, uri, 10
---


# Question
Title: Double values (products) in Commerce cart form
I use Drupal Commerce version `8.x-2.15`. I have a multilingual Drupal site with multiple languages based on domain.

mystic.com -\> EN language mystic.eu -\> NL language

etc

I added relationships:

```
(order_items: Order item) Product variation
(Product variation) Product

```

To get the `image_field` available to show a thumbnail in my cart form. This works fine.

After I added those relationships and I add **one** product to my shopping cart and I see now the number of times that I translated my product back in the shopping cart, like: My product My product My product My product

(so above product is translated into 4 languages).

I've fixed this by adding a filter to the view:

```
Product: Translation language Is one of Content language selected for page

```

It looks like this is working but I see now 2 values (see screenshot)

It doubled the added product. But the price and quantity shows 1.

# Answer
In the `commerce_cart _form` view under **Advanced**, edit the **Query Settings**, and set it to `DISTINCT`.
> 0 votes

# Answer
I just ran into the same situation and in my case the solution was to filter the products on the current language or neutral / not applicable language.

The duplicate result was a translation of that related product. Afterwards the "DISTINCT" option could be removed.

So try filtering on current language and language neutral / not applicable.
> 0 votes

---
Tags: 8, commerce, i18n-l10n, domain-access
---


title: Get all nodes of given type

text:
# Question
Title: Get all nodes of given type
I would like to get all nodes that are of `my_custom_type` type **in Drupal 8**.

I know I can get all the nodes (of any type) with `\Drupal\node\Entity\Node::loadMultiple()` and the list of all types by `\Drupal\node\Entity\NodeType::loadMultiple()`.

But **how to get only the nodes of given node type?**

I really don't want to use specialized module for it (if it's possible), just keep it as simple as possible. I will use the solution in my custom module.

And loading all the nodes with `\Drupal\node\Entity\Node::loadMultiple()` and then check their type in `foreach` would hit the performance too much.

# Answer
You can use `Drupal::entityQuery()` & `Node::loadMultiple()` to load all the nodes of your given type:

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

```
> 61 votes

# Answer
Another way to do this would be using this snippet of code:

```
// Set properties to filter.
$values = [
  'type' => 'page',
];

// Get the nodes.
$nodes = \Drupal::entityTypeManager()
  ->getStorage('node')
  ->loadByProperties($values);

```
> 31 votes

# Answer
Its actually very easy,

```
\Drupal::entityTypeManager()->getStorage('node')
  ->loadByProperties(['type' => 'content_type', 'status' => 1])

```

If you would like all nodes also unpublished just use:

```
\Drupal::entityTypeManager()->getStorage('node')
  ->loadByProperties(['type' => 'content_type'])

```
> 20 votes

# Answer
Usually you need published nodes, not all.

```
$nids = \Drupal::entityQuery('node')
  ->condition('status', 1)
  ->condition('type', 'YOUR-NODE-TYPE')
  ->execute();
$nodes = \Drupal\node\Entity\Node::loadMultiple($nids);

```
> 8 votes

# Answer
You want to use entity storage.

```
$storage = \Drupal::service('entity_type.manager')->getStorage('node');

```

There are two main ways to query for entities:

1. Using entity storage's getQuery() method

```
$my_entity_ids = $storage->getQuery()
  ->condition('type', 'article')
  ->condition('status', 1)
  ->execute();

$my_entities = $storage->loadMultiple($my_entity_ids);

```
2. Using entity\_storage's loadByProperties() method

```
$my_entities = $storage->loadByProperties([
  'type' => 'article',
  'status' => 1,
]);

```

Either one is perfectly acceptable and just use whichever makes more sense in your situation.

Additionally, since it looks like you're doing this in a class of some sort, you can use Dependency Injection to inject the *entity\_type.manager* service. This is well documented in this related post: How to inject a service in another service?
> 5 votes

# Answer
Something that was, at one time, fairly simple to figure out and find documentation for has become quite a bit more confusing and hard to find. This is one of the top search results for this topic, so I want to take the time to post a solution I was able to put together using the new Methods.

My use case is getting a list of published nodes of a certain content type and publishing them to a page as XML to be consumed by a third party.

Here are my declarations. Some of them might be superfluous at this point, but I'm not done upgrading the code as of yet.

```
<?php
namespace Drupal\my_events_feed\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Component\Serialization;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\Response;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Entity\EntityTypeManager;

```

Here's the code to just feed the object into the XML

```
/**
 * Class BuildXmlController.
 */
class BuildXmlController extends ControllerBase {
  /**
   * Builds the xml from an object
   */
  public function build() {
    $my_events = \Drupal::entityTypeManager()
    ->getStorage('node')
    ->loadByProperties([
      'status' => '1',
      'type' => 'submit_an_event',
    ]);

    $thisSerializer = \Drupal::service('serializer');
    $serializedData = $thisSerializer->serialize($my_events, 'xml', ['plugin_id' => 'entity']);

    $response = new Response();
    $response->headers->set('Content-Type', 'text/xml');
    $response->setContent($serializedData);
    return $response;
  }
}

```

If you need to massage the data, then you'll have to fill an array and make edits there. Of course, you can still serialize a standard library array.

```
/**
 * Class BuildXmlController.
 */
class BuildXmlController extends ControllerBase {
  /**
   * Builds the xml from an array
   */
  public function build() {

    $my_events = \Drupal::entityTypeManager()
    ->getStorage('node')
    ->loadByProperties([
      'status' => '1',
      'type' => 'submit_an_event',
    ]);

    $nodedata = [];
    if ($my_events) {
      /*
      Get the details of each node and
      put it in an array.
      We have to do this because we need to manipulate the array so that it will spit out exactly the XML we want
       */
      foreach ($my_events as $node) {
        $nodedata[] = $node->toArray();
      }
    }

    foreach ($nodedata as &$nodedata_row) {
      /* LOGIC TO MESS WITH THE ARRAY GOES HERE */
    }

    $thisSerializer = \Drupal::service('serializer');
    $serializedData = $thisSerializer->serialize($nodedata, 'xml', ['plugin_id' => 'entity']);

    $response = new Response();
    $response->headers->set('Content-Type', 'text/xml');
    $response->setContent($serializedData);
    return $response;
  }
}

```

Hope this helps.
> 0 votes

# Answer
Drupal 9.2 onwards, now requires **Access checking** to be explicitly specified on content entity queries

```
// This will trigger a deprecation error.
$ids = \Drupal::entityQuery('node')
  ->condition('type', 'article')
  ->execute();

// Unchanged: This gets all articles the current user can view.
$ids = \Drupal::entityQuery('node')
  ->accessCheck(TRUE)
  ->condition('type', 'article')
  ->execute();

// Unchanged: This gets all articles that exist regardless of access.
$ids = \Drupal::entityQuery('node')
  ->accessCheck(FALSE)
  ->condition('type', 'article')
  ->execute();

```

Reference: https://www.drupal.org/node/3201242
> 0 votes

---
Tags: nodes, 8
---


# Question
Title: How do I disable ONLY_FULL_GROUP_BY in MySQL 8?
Is it possible to disable `ONLY_FULL_GROUP_BY` in MySQL 8?

I saw suggestions on how to do this on the MySQL server directly, as well as hacking up Drupal core, but none of them have been successful so far. I suspect either because the options do not apply to MySQL 8 or Drupal is hard coded to force this option (even though I cannot find any reference to this in core).

The issue comes from a view not properly handling duplicate results. A common solution is to use `hook_views_query_alter()` to add a GroupBy clause. This works well unless your view has a sort. In that case Views code inserts extra GroupBys for each field in the sort to prevent getting an error for violating the `ONLY_FULL_GROUP_BY` rule within MySQL. These extra GroupBys break the purpose of the added GroupBy and the view returns duplicates.

I can easily make a Views patch to provide a view option to not add the aggregate GroupBys; but then the view fails with the SQL error. Even though pasting this resulting SQL directly into the database console does not give an error and returns the correct results.

In `hook_views_query_alter()`, I could use the following code.

```
case 'policies_by_user':
  // Fix duplicates.
  $query->addField('node_field_data', 'nid', '', ['function' => 'groupby']);
  $query->addGroupBy('node_field_data.nid');
  break;

```

That code adds this `GROUP BY` to the view query.

```
GROUP BY node_field_data.nid,
  node__field_policy_effective_date_field_policy_effective_dat,
  field_policy_node_field_data_completed

```

The two additional terms are from the sort fields added in the view and forced by the Views module to meet the `ONLY_FULL_GROUP_BY` requirements.

Modifying the *Sql.php* file where it *Assembles the group by clause* fixes it; the additional `GROUP BY` elements are not added. This generates an error, although it creates the correct query.

> SQLSTATE\[42000\]: Syntax error or access violation: 1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'sia.node\__field\_policy\_effective\_date.field\_policy\_effective\_date\_value' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql\_mode=only\_full\_group\_by

GROUP BY clause and contains nonaggregated column and incompatible with sql\_mode=only\_full\_group\_by suggests a couple of different methods to use with Drupal.

* Add `init_command` to the database connection array in the *settings.php* file
* Hack the SQL mode setting in the *Connection.php* file (although the code mentioned to hack it is no longer there)

Alternatively, there is the server approach mentioned on Disable ONLY\_FULL\_GROUP\_BY to modify `@@sql_mode` directly in SQL and remove the `ONLY_FULL_GROUP_BY` option. In my MySQL 8 setup, that is not listed as an option, though.

# Answer
You can modify this property by going to your MySQL instance \> Server parameters \> look for sql\_mode property \> you can then select/unselect required property values from the drop down like ONLY\_FULL\_GROUP\_BY, STRICT\_TRANS\_TABLES etc
> -1 votes

---
Tags: views, 9
---


title: Migrate user roles with static_map

text:
# Question
Title: Migrate user roles with static_map
I am trying to migrate D7 users into D10. I have enabled the following migrate modules:

* migrate
* migrate drupal
* migrate plus
* migrate tools

The migration yml is as follows:

```
id: create_user_account
migration_group: site_import
label: 'Create User accounts'
source:
  plugin: d7_user
process:
  uid:
    - plugin: skip_on_value
      equals: true
      source: uid
      method: row
      value:
        - 1
  name: name
  pass: pass
  mail: mail
  created: created
  access: access
  login: login
  status: status
  timezone: timezone
  langcode:
    - plugin: default_value
      default_value: 'en'
  preferred_langcode:
    - plugin: default_value
      default_value: 'en'
  preferred_admin_langcode:
    - plugin: default_value
      default_value: 'en'
  init: init
  field_user_picture:
    - plugin: sub_process
      source: field_photo
      process:
        target_id: fid
        alt: alt
        title: title
        width: width
        height: height
  field_area:
    - plugin: extract
      source: field_area
      default: null
      index:
        - 0
        - value
  field_name/value:
    - plugin: extract
      source: field_name
      default: null
      index:
        - 0
        - value
  field_phone_number_1/value:
    - plugin: extract
      source: field_phone_number_1
      default: null
      index:
        - 0
        - value
  field_phone_number_2/value:
    - plugin: extract
      source: field_phone_number_2
      default: null
      index:
        - 0
        - value
  field_position:
    - plugin: extract
      source: field_position
      default: null
      index:
        - 0
        - value
  roles:
    - plugin: callback
      callable: var_dump
      source: roles
    - plugin: sub_process
      process:
        target_id:
          plugin: static_map
          bypass: true
          source: roles
          map:
            "1": anonymous
            "2": authenticated
            "3": administrator
            "4": housing_member
            "7": content_editor
destination:
  plugin: 'entity:user'

```

Everything migrates as expected EXCEPT the roles.

roles var\_dump outputs something like:

```
string(1) "3"
string(1) "7"

```

for each user, but the users fail to import with the following error:

create\_user\_account:roles:sub\_process: Input array should hold elements of type array, instead element was of type 'NULL'

which I though would be managed by 'bypass: true'.

My initial map used \[without quotes\]

```
1: anonymous

```

etc

But had the same error.

If I disable the roles element, the users will import as expected. How do I create the required static\_map structure for the migration to work as expected?

# Answer
> 1 votes
The way I've been migrating users and user roles is to have two separate migrations - one for user roles, which looks like this:

```
id: user_roles
label: "Users roles"
migration_group: site_migration
migration_tags:
  - users
  - roles

source:
  plugin: d7_user_role

process:
  id:
    -
      plugin: machine_name
      source: name
    -
      plugin: user_update_8002

  permissions:
    -
      plugin: static_map
      source: permissions
      bypass: true
      map:
        'use PHP for block visibility': 'use PHP for settings'
        'administer site-wide contact form': 'administer contact forms'
        'post comments without approval': 'skip comment approval'
        'edit own blog entries': 'edit own blog content'
        'edit any blog entry': 'edit any blog content'
        'delete own blog entries': 'delete own blog content'
        'delete any blog entry': 'delete any blog content'
        'create forum topics': 'create forum content'
        'delete any forum topic': 'delete any forum content'
        'delete own forum topics': 'delete own forum content'
        'edit any forum topic': 'edit any forum content'
        'edit own forum topics': 'edit own forum content'
    -
      plugin: flatten

  label: name
  weight: weight

  skip_missing_permission_deprecation:
    -
      plugin: default_value
      default_value: true

destination:
  plugin: 'entity:user_role'

```

and the user migration itself which looks like this:

```
id: users
label: "Users"
migration_group: site_migration
migration_tags:
  - users

source:
  plugin: d7_user

process:
  uid:
    - plugin: skip_on_value
      equals: true
      source: uid
      method: row
      value:
        - 1
  name: name
  mail: mail
  pass: pass
  created: created
  access: access
  timezone: timezone
  login: login
  status: status
  init: init
  preferred_langcode: language
  preferred_admin_langcode: language
  roles:
    - plugin: migration_lookup
      migration: users_roles
      source: roles

destination:
  plugin: 'entity:user'

migration_dependencies:
  required:
    - user_roles

```

This came from config generated by the Migrate Drupal module and seems to work perfectly well. Have your user roles changed in the target site which means you're having to map the roles differently?

---
Tags: users, migrations, 10
---


# Question
Title: "User warning: The following theme is missing from the file system: media in drupal_get_filename()"
What does this error message mean? How can I fix it?

> User warning: The following theme is missing from the file system: media in drupal\_get\_filename() (line 268 of core/includes/bootstrap.inc).
> drupal\_get\_filename('theme', 'media') (Line: 291)
> drupal\_get\_path('theme', 'media') (Line: 394)
> Drupal\Core\Asset\LibraryDiscoveryParser-\>drupalGetPath('theme', 'media') (Line: 85)
> Drupal\Core\Asset\LibraryDiscoveryParser-\>buildByExtension('media') (Line: 87)
> Drupal\Core\Asset\LibraryDiscoveryCollector-\>getLibraryDefinitions('media') (Line: 66)
> Drupal\Core\Asset\LibraryDiscoveryCollector-\>resolveCacheMiss('media') (Line: 149)
> Drupal\Core\Cache\CacheCollector-\>get('media') (Line: 44)
> Drupal\Core\Asset\LibraryDiscovery-\>getLibrariesByExtension('media') (Line: 58)
> Drupal\Core\Asset\LibraryDiscovery-\>getLibraryByName('media', 'form') (Line: 54)
> Drupal\Core\Asset\LibraryDependencyResolver-\>doGetDependencies(Array, Array) (Line: 56)
> Drupal\Core\Asset\LibraryDependencyResolver-\>doGetDependencies(Array) (Line: 31) Drupal\Core\Asset\LibraryDependencyResolver-\>getLibrariesWithDependencies(Array) (Line: 104)
> Drupal\Core\Asset\AssetResolver-\>getLibrariesToLoad(Object) (Line: 116)
> Drupal\Core\Asset\AssetResolver-\>getCssAssets(Object, ) (Line: 291)
> Drupal\Core\Render\HtmlResponseAttachmentsProcessor-\>processAssetLibraries(Object, Array) (Line: 161)
> Drupal\Core\Render\HtmlResponseAttachmentsProcessor-\>processAttachments(Object) (Line: 45)
> Drupal\Core\EventSubscriber\HtmlResponseSubscriber-\>onRespond(Object, 'kernel.response', Object) call\_user\_func(Array, Object, 'kernel.response', Object) (Line: 111)
> Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher-\>dispatch('kernel.response', Object) (Line: 191)
> Symfony\Component\HttpKernel\HttpKernel-\>filterResponse(Object, Object, 1) (Line: 173)
> Symfony\Component\HttpKernel\HttpKernel-\>handleRaw(Object, 1) (Line: 68)
> Symfony\Component\HttpKernel\HttpKernel-\>handle(Object, 1, 1) (Line: 57)
> Drupal\Core\StackMiddleware\Session-\>handle(Object, 1, 1) (Line: 47)
> Drupal\Core\StackMiddleware\KernelPreHandle-\>handle(Object, 1, 1) (Line: 99)
> Drupal\page\_cache\StackMiddleware\PageCache-\>pass(Object, 1, 1) (Line: 78)
> Drupal\page\_cache\StackMiddleware\PageCache-\>handle(Object, 1, 1) (Line: 47)
> Drupal\Core\StackMiddleware\ReverseProxyMiddleware-\>handle(Object, 1, 1) (Line: 50)
> Drupal\Core\StackMiddleware\NegotiationMiddleware-\>handle(Object, 1, 1) (Line: 23)
> Stack\StackedHttpKernel-\>handle(Object, 1, 1) (Line: 664)
> Drupal\Core\DrupalKernel-\>handle(Object) (Line: 19)

# Answer
Had same issue. Resolved with:

* search THEME-NAME string in themes folder
* remove reference to the useless theme

In my case, I was having

```
User warning: The following theme is missing from the file system: pxrflx in drupal_get_filename()

```

This warning disappeard once I removed

```
libraries:
  - pxrflx/global-styling

```

from the **a\_differnt\_theme\_from\_pxrflx.yml** file
> 2 votes

# Answer
This warning generally occurs if Drupal can't find the folder of the related module or theme. There is a manual page on how to get rid of this error: How to fix "The following module is missing from the file system..." warning messages.

Looking at the date of the question, there is a big chance this is happening because of version conflict between the *Media entity* module and source provider modules. If the installed version of the *Media entity* module is 1.x, then your core media module is not installed. If you are using the 2.x version of the media source provider modules like the *Media entity video* module or the *Video Embed Field* module, they are probably looking for the core *Media* module.

If you're building a new site, you should start over with the core Media module. If you're upgrading your existing site, you should follow the upgrade path. Instructions for both are given on the *Media entity* project page.
> 1 votes

# Answer
Another possibility to why this problem exists is when a module or theme is installed, but doesn't enable all the required dependencies it needs to operate. That's often what throws an error like this.

The error can be a bit confusing, since it lists a theme as missing, when the problem could lie with a missing or yet-to-be-enabled module.

In this particular case, you could probably run `drush pm:enable media` to resolve the issue.
> 0 votes

# Answer
Used this reference https://www.drupal.org/node/2940438 and found the deprecated functions and this fixed the issue.
> -1 votes

---
Tags: 8, media
---


# Question
Title: How do I load taxonomy terms basing on the current language?
I am using the following code.

```
$language =  \Drupal::languageManager()->getCurrentLanguage()->getId();
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree('category', 0, 1);

```

How can I change it so it load the taxonomy terms basing on `$language`?

# Answer
> 3 votes
Use EntityRepositoryInterface::getTranslationFromContext:

```
$terms_translated = [];
foreach ($terms as $key => $term) {
  $terms_translated[$key] = \Drupal::service('entity.repository')
    ->getTranslationFromContext($term, $language);
}

```

BTW, you don't need to provide a language code, because the current content language is the default value for the second parameter in getTranslationFromContext() and in a standard multilanguage site this is equal to the current language.

# Answer
> 0 votes
You can also use:

```
foreach ($terms as $term) {
  if ($term->hasTranslation($langcode)) {
    $term = $term->getTranslation($langcode);
  }
  ...
}

```

probably more convenient as you dont have to inject entity.repository

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


title: How can I add a class to a label?

text:
# Question
Title: How can I add a class to a label?
I need to add a class name to certain labels created by Drupal's form API like this:

```
$form['name'] => array(
  '#type' => 'textfield',
  '#title' => 'Prénom'
);

```

If I use the following, the `<textarea>` gets a class, but not the label.

```
$form['name']['#attributes']['class'] = array('myClass');

```

I'm looking for something similar that will add a class to the `<label>`.

# Answer
You cannot set a class to the label tag of the form element using Form API's properties. However, you can set a prefix and a suffix to wrap the element (label + textarea) and use some nested CSS selector to accomplish what you are trying to do.

```
$form['name'] => array(
  '#type' => 'textfield',
  '#title' => 'Prénom'
  '#prefix' => '<div class="myClass">',
  '#suffix' => '</div>'
);

```

and in the CSS, you can select the label tag like this:

```
.myClass label {
  text-transform: uppercase; /* just for example */
}

```

Not a decent solution but that's how I usually do this, and have seen others do. `#attributes` is for the input element itself so it's correct your code adds the `myClass` class to the `textarea`.
> 6 votes

# Answer
This post on StackOverflow says that the Drupal Form API does not support adding classes to labels, but it does contain a decent workaround:

> Instead, you could target it using the wrapper class for the field and label:
>
> ```
> .form-item-field-foo label {
>   /* CSS here */
> }
>
> ```

The API documentation for theme\_form\_element\_label() shows why labels aren't possible (at least not out-of-the-box): the attributes array is initialized in the theme function and populated with just two optional classes ('option' and 'element-invisible').

So, is it completely impossible? In fact, I think it can be done, but I must add that I haven't tried this myself. You could try to:

* Add a new `#label_attributes` property to some (or all) form elements using hook\_element\_info\_alter() in a custom module;
* Override theme\_form\_element\_label() and make it merge the `$attributes` array with the value of `$element['#label_attributes']`.

If you're going to give this a try, please let us know if it worked.
> 6 votes

# Answer
On Drupal 8, do that simply by adding in your\_module.module file

```
function your_module_preprocess_form_element(&$variables) {

  $element = $variables['element'];
  if (isset($element['#label_attributes'])) {
    $variables['label']['#attributes'] = array_merge(
      $variables['attributes'],
      $element['#label_attributes']
    );
  }
}

```

and add the #label\_attributes on form creation :

```
$form['some_field'] = [
  [...]
  '#label_attributes' => [
    'some_attr' => 'some_value',
  ]
]

```
> 5 votes

# Answer
Expanding on Ayesh's answer I have included an example use case for such code. While marvangend's answer is much more Drupalesk it's a lot of digging for a very simple result. Keeping form specific elements & CSS bundled with said form is the general use case, allowing us to target & act on inner elements is a tiny bit more specific.

http://legomenon.io/article/drupal-7-adding-form-placeholder-attributes

```
function mymodule_form_alter(&$form, $form_state, $form_id) {
  switch ($form_id) {
    // Waterfall.
    case 'webform_client_form_16':
    case 'webform_client_form_51':
    case 'webform_client_form_64':
    case 'webform_client_form_78':
      $exclude = array('select', 'radios', 'checkboxes', 'managed_file');
      foreach ($form['submitted'] as $name => $component) {
        if (!in_array($component['#type'], $exclude) && $name != '#tree') {
          $form['submitted'][$name]['#prefix'] = '<span class= "label-invisible">';
          $form['submitted'][$name]['#suffix'] = '</span>';
          $form['submitted'][$name]['#attributes']['placeholder'] = $component['#title'];
        }
      }
      $form['#attached']['css'] = array(
        drupal_get_path('module', 'mymodule') . '/css/mymodule.form.css',
      );
    break;
  }
}

```
> 2 votes

# Answer
I found a relatively easy way to accomplish this using the Fences D7 module. This module comes with a lot of template files to customize the fields. Edit the field that you would like to give a unique class to and change the wrapper markup to something relevant for you. After that, find the corresponding template file within the module and copy it into your sites/all/themes/THEME\_NAME.

Before

```
<span class="field-label"<?php print $title_attributes; ?>>
  <?php print $label; ?>:
</span>

```

After

```
<span class="<?php print $label; ?> field-label"<?php print $title_attributes; ?>>
  <?php print $label; ?>:
</span>

```

By adding in `<?php print $label; ?>` , it prints the name of the field as a class, allowing you to target all of the field-labels individually. I hope this helps someone else!
> 0 votes

# Answer
It's dirty, but you can add HTML to the '#title'-property:

```
$form['some_element'] = array(
  '#type'          => 'textfield',
  '#title'         => '<span title="HELP!">'.t($subchildlabel).'</span>',
  '#default_value' => …
)
…
);

```

I'm surprised myself it works. I would think Drupal would filter this out, but no. So, you can wrap the label with another class:

```
<label for="edit-m-vernacularname" class="inline"><span title="HELP!">Common name
</span> </label>

```
> 0 votes

# Answer
I think the easiest way to do tis is to write a bit of jQuery that finds the label for the field and uses the addClass method to add the class.

Drupal puts a unique class in the the div wrapper for each field. Inspect your source to find the class, and you can then jQuery for the child label.

For example in Drupal 7

Create a js file for your theme.

Add in this

```
(function ($) {
Drupal.behaviors.addLabelclass = {
    attach: function (context, settings) {
        $(document).ready( function () {
            $("div.uniquefieldclass label").addClass("mylabelclass");
            }
            );
        }
};
}(jQuery));

```

Substitute uniquefieldclass for your class. This jQuery will add the class mylabelclass to the label
> 0 votes

---
Tags: 7, forms
---


# Question
Title: How to import a boolean value in a migration
I'm trying to run a migration and one of the fields in Drupal is a boolean. For some reason I cannot get it to import the boolean value.

**In Drupal**

The field type is boolean, the on/off labels are yes/no (I've also tried setting them to on/off). the machine name is `field_release_compilation`

**In my data source** (Google sheets the data is stored as:

`"gsx$compilation":{"$t":"1"}`

I have also tried values of "TRUE", "on", "Yes" as well as "1"

**In my migration**

I'm using the google sheets plugin, along with migrate plus and migrate tools. The rest of the data pulls in fine so there's no issue connecting to sheets or that it's viewing the wrong doc/worksheet.

I remap the field using (I'm remapping every field, the others work fine)

```
fields:
- name: Compilation
  label: Compilation
  selector: compilation

```

I've tried the following ways of processing the field, all to no avail:

```
field_release_compilation:
  - type: bool
    source: Compilation

field_release_compilation:
  - fieldtype: bool
    source: Compilation

field_release_compilation:
  - type: boolean
    source: Compilation

field_release_compilation:
  - fieldtype: boolean
    source: Compilation

field_release_compilation:
  - callable: boolval
    source: Compilation

```

I'm not sure what to try next...

# Answer
The convert\_boolean process plugin is a good option https://git.drupalcode.org/project/migration\_tools/-/blob/8.x-2.x/src/Plugin/migrate/process/ConvertBoolean.php
> 0 votes

---
Tags: migrations, importing-exporting
---


# Question
Title: Where is the "Install Profile" value in the Status report set?
I am using Drupal 7. If I go to Reports --\> Status Report, the "Install Profile" value is incorrect (it has an extra dash at the end). Where is this value stored? I wish to correct it.

# Answer
The displayed name comes from the `name` key in the profile's `.info` file. If you change `name` you must clear the site caches to see a change on the report.
> 0 votes

---
Tags: 7, installation-profiles
---


# Question
Title: Programmatically get current multi-site instance name
Let's say I have the following multi-site setup:

```
$sites['hello-world-a.com']       = 'a';
$sites['stage.hello-world-a.com'] = 'a';
$sites['dev.hello-world-a.com']   = 'a';
$sites['hello-world-a.localhost'] = 'a';

$sites['hello-world-b.com']       = 'b';
$sites['stage.hello-world-b.com'] = 'b';
$sites['dev.hello-world-b.com']   = 'b';
$sites['hello-world-b.localhost'] = 'b';

```

Works fine. Both share the same theme and more or less the same features. Now let's say I have a very simple preprocess function that adds a CSS class to the body:

```
/**
 * Implements template_preprocess_html().
 */
function MYTHEME_preprocess_html(&$variables) {

  $variables['attributes']['class'][] = 'foo';

}

```

### How can I now add the multi-site instance's name as body class dynamically?

* Without going through all possible domain names and string comparison?
* Also possibly without working with the human readable site name, which may change?
* Maybe with cache contexts?
* Or UUID?

---

```
/**
 * Implements template_preprocess_html().
 */
function MYTHEME_preprocess_html(&$variables) {

  $variables['attributes']['class'][] = 'foo';

  // Basically along the following pattern.
  if ( @@@ SITE A @@@ ) {
    $variables['attributes']['class'][] = @@@ SITE A @@@;
  }

}

```

# Answer
> 16 votes
Thanks to @Clive for telling me about `DrupalKernel::findSitePath` which takes the current `$request` to then return the path of the matching multi-site directory.

And thanks to @4k4 for the tip that there's also a service for that. But this service got deprecated in Drupal 9 and will have been removed from Drupal 10, so back to to `DrupalKernel::findSitePath`. This works in Drupal 8, 9 and 10:

```
/**
 * Implements template_preprocess_html().
 */
function MYTHEME_preprocess_html(&$variables) {

  // This will get you a string for example: 'sites/default'.
  $site_path = \Drupal\Core\DrupalKernel::findSitePath(\Drupal::request());

  // Explode it to only get the 'default' part in the next step.
  $site_path = explode('/', $site_path);
  $site_name = $site_path[1];

  // Add current site name as CSS class to the body.
  $variables['attributes']['class'][] = 'site-' . \Drupal\Component\Utility\Html::cleanCssIdentifier($site_name);
}

```

# Answer
> 1 votes
A quicker alternative is to add a `$settings['current_multisite']` with the desired value on each `setting.php` then use it for checkings:

```
<?php
# settings.php of "bar" site
$settings['current_multisite'] = 'foo';

# settings.php of "bar" site
$settings['current_multisite'] = 'bar';

```

Then you can access it anywhere:

```
<?php
// Fallbacks to "null" if some multisite did not specified "current_multisite"
$multisite = Settings::get('current_multisite');

```

---
Tags: 8, multi-sites
---


# Question
Title: Have Leaflet marker popup open on page load
Has anyone used Leaflet to display a single location, while making the "popup" open when the map is loaded? This is really easy to do in Leaflet, but the module's JS is a little hard to decipher. Any help would be appreciated.

# Answer
> 2 votes
The leaflet module fires an event after a map is created, called "leaflet.map".
You should be able to listen for this event and get the map object like this:

```
(function ($) {
  Drupal.behaviors.openMarker = {
    attach:function (context, settings) {
      $(document, context).on('leaflet.map', function(event, map){
        // console.log(map);
        // logic to open marker goes here
      })
    }
  };
})(jQuery);

```

Leaflet module also fires an event called 'leaflet.feature'.

NOTE: the above code is untested

# Answer
> 0 votes
@2pha solution proves that, this might work, I've got map object, but no methods there. I think better is to search in settings.leaflet.mymap.lMap - there is the openPopup method. You just have to find marker to open popup on it, even with jQuery selector.

But you can also use poorman's solution, just click on existing markers:

```
(function ($) {
    Drupal.behaviors.customLeafletPopup = {
      attach: function (context, settings) {
        var existCondition = setInterval(function() {
          if ($('.leaflet-marker-icon').length) {
             clearInterval(existCondition);
             $('.leaflet-marker-icon').each(function () {
              setTimeout($(this).click(), 5000);
            });
          }
         }, 1000); // check every 1000ms

      }
    };
  })(jQuery);

```

---
Tags: javascript
---


# Question
Title: Attach JavaScript to page with Commerce Events
I'm using `hook_page_attachments_alter` in Drupal 9 to add some JavaScript dataLayer calls to certain routes, but I also need to add some to certain cart events (i.e. add item to cart).

I've written a CartEventSubscriber that listens for cart events and have one responding to the AddToCart event, but the only variable it exposes is `CartEntityAddEvent $event`.

Is there another way to tell from `hook_page_attachments_alter` or some other hook that I'm on a page that resulted from the Add to Cart click so that I can add this JS there?

Thanks!

# Answer
So, I found the GA Push module, but it wasn't sure how fully it was being maintained, but I may revisit it in the future. But for my purposes for now, I just took inspiration from the way they use session objects. So, my AddToCart method ended up looking like ...

```
public function addToCart(CartEntityAddEvent $event) {
  /** @var \Drupal\commerce_product\Entity\ProductVariationInterface $product_variation */
  $product_variation = $event->getEntity();
  $request = $this->requestStack->getCurrentRequest();
  $session = null;
  if($request->hasSession()){
    $session = $request->getSession();
  }
  if(is_null($session)){
    return;
  }
  $session->set('{session_id}}', {js_snippet});
}

```

And in my .module file's hook\_page\_attachments\_alter function, I added ...

```
if(\Drupal::request()->hasSession()){
  $session = \Drupal::request()->getSession();
  attachments[] = $session->get('{session_id}');
  $session->remove('{session_id}');
}

```

And proceeded to attach the snippets as normal.
> 0 votes

---
Tags: commerce, 9
---


# Question
Title: How to find all views that have "broken or missing handler"?
Is there an easy way to get a list of all views that have a "broken or missing handler" ? To make sure it is ok to disable a module that defines views plugins.

I think in D8 we have proper dependency management for this stuff. But in D7?

# Answer
> 2 votes
Yes, there is a debug option within Views's advanced settings that will print out debug statements via the Devel when a handler is broken.

Combined with Devel's **Execute PHP** block/form, you can use the execute the following snippet to enable debugging, evoke execution on all Views, and review the output messages for any broken handler warnings between each execution prompt.

```
// Capture/set debug settings.
$views_debug = variable_get('views_devel_output', FALSE);
$views_region = variable_get('views_devel_region', 'watchdog');
variable_set('views_devel_output', TRUE);
variable_set('views_devel_region', 'message');

// Execute all views/displays
foreach( views_get_all_views() as $view) {
  $displays = array_keys($view->display);
  foreach($displays as $display) {
     dpm("Executing $view->name ($display):");
     $view->execute($display);
     $view = $view->clone_view();
  }
}

// Reset debug settings.
variable_set('views_devel_output', $views_debug);
variable_set('views_devel_region', $views_region);

```

# Answer
> 0 votes
I actually had to do similar in D9 recently (after some core and module updates). Here's the code that I used:

```
use Drupal\views\Views;

// Capture/set debug settings.
$views_debug = \Drupal::state()->get('views_devel_output', FALSE);
$views_region = \Drupal::state()->get('views_devel_region', 'watchdog');
\Drupal::state()->set('views_devel_output', TRUE);
\Drupal::state()->set('views_devel_region', 'message');

// Execute all views/displays
$views = Views::getAllViews();
foreach( $views as $view) {
  dpm("Running view id ".$view->get('id')."...");
  $displays = $view->get('display');
  $view = Views::getView($view->get('id'));
  foreach($displays as $display) {
    dpm("Executing $view->name (".$display['id']."):");
    $view->setDisplay($display);
    $view->preExecute();
    $view->execute();
    $content = $view->buildRenderable($display);
  }
}

// Reset debug settings.
\Drupal::state()->set('views_devel_output', $views_debug);
\Drupal::state()->set('views_devel_region', $views_region);

```

---
Tags: 7, views
---


# Question
Title: Modern File Manager for upload and organize documents?
Being new to Drupal, I still struggle with its File-Management.

I have the following use-case:

* Authenticated Users from group 'comitee' can upload files (jpg, png, pdf and docx) to the Server, rename then and structure them in subdirectories
* Authenticated Users from group 'member' can browse those subdirectories and download the Documents.
* Optional: Editors can reference to those files in CKEdit, be it for embeding images or to download documents.

AFAIK I could create my own Content Type with a File-Field and a Taxanomy simulating a directory-structure, and then browsing those files via a view. But in my eyes (still a rookie), this does not seem right to me. And I do not see another build-in way to do this.

From all the research I did, the only Module I could find covering this use-case and running on modern Drupal was IMCE. But IMCE seems not to be able to rename files, and looks a bit old to my eyes. Writing my own module also seems a bit an overkill for such a simple feature.

Is IMCE still the way to go, or is there some proven, stable module for such a use case I did not find? Or is there a standard way to do it in core?

# Answer
> 1 votes
Drupal has media for this. Core provides some media types and you can add additional ones. You can also add fields to media types for more customization.

However, Drupal is not a file manager in the sense of Explorer on Windows or Finder on Mac. Instead, the optimal way to manage files in Drupal is to think about what data relationships you need to manage and then structure your media types based on that.

Instead of worrying about where the files are on disk, you can use taxonomy for a hierarchy or tags or both. And you can use the Views module to easily create and filter different "lists" of files.

If you insist on trying to manage where the files are stored on disk, you can use modules like Filefield Paths, but this is going to be painful and difficult. I would strongly urge you to consider a structure where users don't need to think about where the data is stored but rather how the data items relate to each other.

# Answer
> 0 votes
Just an update about my final solution. According to Patrick Kenny, I did it with Standard Drupal Media, but this was only the starting point.

* Created a new Role 'Member'
* Created a new Taxonomy 'Download-Sections'
* Created a new Content-Type 'Member-Only-File', with a field of Type 'Entity Reference' to Media-Type File and a field of Type 'Entity Reference' to the Download-Sections-Taxonomy.
* Installed Contrib-Module entity\_bundle\_permissions, granted Access to 'Member-Only-File' to role 'Member', but not to anonymous or authenticated users. (had to explictly grant them access to all other bundles, though)
* Created a View on Content Type=Member-Only-File, grouped by 'Download-Sections' (incl. exposed filter), accessible only to members.

Not exactly the design I had planned, but good enough for my use-case

---
Tags: files, 10
---


# Question
Title: Is there any danger in uninstalling Redirect module?
Drupal 9.5.3 with no core customizations and very few contrib modules:

* Redirect
* Asset Injector
* Token

All nodes in this website have *alternative aliases* such as `example.com/my-first-node` instead of `example.com/node/1`.

When creating the website nearly a year and a half ago I have also installed Redirect. I don't recall why exactly. But I know for certain, that I didn't do anything with it "manually".

When I came to uninstall Redirect I got a message that:

> There is content for the entity type: Redirect | **Remove entities Redirect** (link)

If I click the link to remove the entity type I get a list of **ten nodes**.

Why do I get a list of ten nodes? I don't recall every associate these specific nodes with redirect.

Given these data, at last, is there any danger in uninstalling Redirect module?

# Answer
The Redirect module has this setting

> \[x\] Automatically create redirects when URL aliases are changed.

which is enabled by default.

If you delete the redirects you get a 404 instead of a 301 for the old aliases.

It's not dangerous to uninstall the Redirect module, but you lose the information the old aliases ever existed.

This is not to be confused with route normalization, which the module also provides:

> \[x\] Enforce clean and canonical URLs.
>
> * Enabling this will automatically redirect to the canonical URL of any page. That includes redirecting to an alias if existing, removing trailing slashes, ensure the language prefix is set and similar clean-up.

This automatically redirects the internal path /node/123 to the alias so that the user always sees the alias in the address bar. This functionality doesn't store data and can be re-enabled by installing the module again, without data loss.
> 2 votes

---
Tags: 9, redirection
---


# Question
Title: How to get path/URL without language prefix (for multilingual site)
I have written a code to get the parameters (node\_id, taxonomy\_id) from the URL using the following code.

**Sample URL**: `/foo/bar/[nid]\/[tid]`

```
$path = \Drupal::request()->getpathInfo();
$arg = explode('/', $path);
$node_id = $arg[3]; //gives [nid]
$term_id = $arg[4]; // gives [tid]

```

This works, but when I switch to other language (say spanish), the URL becomes

```
/es/foo/bar/[nid]/[tid]

```

So obviously the code doesn't work in this case. Is there anyway to handle this?

# Answer
I got it. Here's the code to get the URL without language prefix.

```
use Drupal\Core\Url;
$current_url = Url::fromRoute('<current>');
// If we want to get the url without language prefix
$path = $current_url->getInternalPath();
$path_args = explode('/', $path);

```
> 0 votes

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


# Question
Title: How to conclude from Upgrade Status module if my website is ready to be upgraded from 9 to 10 in command line?
How to conclude from Upgrade Status module if my website is ready to be upgraded from 9 to 10 in **command line**?

From the documentation I understand that I should run either of these commands:

* `vendor/bin/drush upgrade_status:analyze (us-a) --all`
* `vendor/bin/drush upgrade_status:checkstyle (us-cs) --all`

Is that correct or at least, Would you use more particular arguments?

My question is general and principal but my personal case is a primarily core 9.5.9 website with Redirect, Token and Asset Injector contrib modules.

# Answer
> 1 votes
From the documentation, `upgrade_status:analyze` produces ASCII style output whereas `upgrade_status:checkstyle` produces XML. That choice is your preference.

You can pass each command a list of projects to analyze, or use any of these options:

```
  --all                Analyze all projects.
  --skip-existing      Return results from a previous scan of a project if available, otherwise start a new one.
  --ignore-uninstalled Ignore uninstalled projects.
  --ignore-contrib     Ignore contributed projects.
  --ignore-custom      Ignore custom projects.

```

As you are using `--all` that should check every project, every time you execute the command.

---
Tags: 9, upgrading
---


# Question
Title: How do I set field mapping in the Feeds module for Drupal 8?
I'm trying to use Feeds 8.x-3.x-dev on Drupal 8.4. I've created a feed type (eg. `News Feed`) and I'm trying to set the field mappings, but I get an empty list with no way to add anything to it:

The target content type is a custom one, that's similar to Articles, but it also contains some extra fields (such as the source of the feed).

If I add a feed URL to this type and try to import it, it obviously fails:

> Test Source has been created.
>
> Warning message
>
> An entity of type "content" failed to validate with the following errors:
>
> Title (title): This value should not be null.
>
> News GUID (field\_news\_guid): This value should not be null.
>
> News Link (field\_news\_link): This value should not be null.
>
> News Source (field\_news\_source): This value should not be null.
>
> Please check your mappings.
>
> Error message
>
> Failed importing 20 News.

Most tutorials and references online talk about the module for Drupal 7, which looks significantly different from what I see.

Is there something I'm missing or is this mapping feature currently broken?

*Edit:* I am aware of the pre-release status of this module, but I'm trying to evaluate it to see what works and what doesn't. Downgrading to Drupal 7 isn't an option, so I have to make do with what I have for 8. If not Feeds, is there any alternative for a simple RSS/Atom feed import? Aggregator would work just fine for my needs, but how do I get it to import the contents as nodes?

*Edit:* I decided to downgrade to Drupal 7.

# Answer
> 1 votes
1. First, select a target to map to.
2. This will result into a list of sources to appear. Select one of these sources.

Notes:

* The UI for CSV parser is still incomplete. See https://www.drupal.org/node/2669974
* If the sources list does not appear after selecting a target, you may be facing javascript issues. In this case, check with a debugger which scripts fails. In D7, the jQuery Update module (or how that modules was configured) sometimes was the culprit.
* If there are no targets appearing, try to rebuild caches.
* Currently there is a bug with updating items if the target 'Feeds item' is not in the list. Be sure to map to that target if you not only want to insert new items, but also update existing ones. See https://www.drupal.org/node/2857692.

# Answer
> 0 votes
I had the exact same issue as what the OP reported but in my case it was due to missing files from the module that somehow didn't transfer in the push to production. Make sure you have the Target directory in the feeds module `feeds/src/Feeds/Target` as well as in `feeds/src/Plugin/type/Target`.

---
Tags: 8, feeds
---


# Question
Title: Migration fails with "missing migrations" errors
I am trying to migrate a Drupal 7 site to Drupal 9 using the Migrate module user interface. I have read through and followed the corresponding tutorials on drupal.org, but the migration still fails.

Given that my original Drupal 7 site is quite complex, for testing purposes, I created a fresh installation of Drupal 7 and created some dummy nodes; then I ran the upgrade from the user interface in Drupal 9.

The *What will be upgraded?* page indicated that 29 modules would be upgraded (including the Node module). After performing the upgrade, I got the following messages:

> Completed 39 upgrade tasks successfully
> 40 upgrades failed
> Upgrade process not completed

The content hasn't been migrated.

When I checked the upgrade log, I found the following error:

> Migration d7\_node:article did not meet the requirements. Missing migrations d7\_node\_type, d7\_user. requirements: d7\_node\_type. requirements: d7\_user.

The *d7\_node\_type.yml* and *d7\_user.yml* migration files are there in the appropriate Drupal 9 folders, so I don't understand what the problem is. What am I missing?

# Answer
I had the same messages in my log when I first tried a migration using the user interface. I also had the following which once sorted out appeared to clear up the other errors.

> General error: 1267 Illegal mix of collations (utf8mb4\_general\_ci,IMPLICIT) \>and (utf8mb4\_0900\_ai\_ci,IMPLICIT)

It seems the collations of the databases need to be the same. My source db from my drupal 7 site is utf8mb4\_general\_ci and the default for my new db is utf8mb4\_0900\_ai\_ci. So I used phpmyadmin to 'convert' the drupal 7 db to utf8mb4\_0900\_ai\_ci which did the trick.

I'm no mysql expert, as demonstrated by my use or phpmyadmin instead of the command line, so you should use a copy of your source db at the very least.
> 0 votes

---
Tags: migrations, 9
---


# Question
Title: Bulk update for unchecked "Generate automatic URL alias"
I have a lot of programmatically generated nodes with the option "**Generate automatic URL alias**" unchecked, so i can't use the **Bulk Update** of the pathauto module.

How can i to bulk generate the pathauto alias for these nodes?

Edit: i use Drupal 7

# Answer
> 6 votes
Have you tried using Views Bulk Operation. All you will need to do is create a view that will list all the nodes that will meet your criteria and then assign an action 'Generate Url alias' (I haven't tried it though.)

# Answer
> 7 votes
VBO doesn't have an option to change the status of 'Generate automatic URL alias'

You could execute the following mysql query:

```
UPDATE `pathauto_state` SET `pathauto`=1 WHERE `entity_type` = 'node'

```

Or if you want to update just exact content type only:

```
UPDATE  `pathauto_state` p, `node` n SET `pathauto` = 1 WHERE
p.entity_id = n.nid and n.type = 'mycustontype'

```

where 'mycustomtype' is a machine name of the content type.

Or if you have drush installed:

```
drush sqlq "UPDATE pathauto_state SET pathauto=1 WHERE entity_type = 'node'"

```

After that you can bulk generate the new paths as you would normaly do on: admin/config/search/path/update\_bulk

# Answer
> 2 votes
In addition to Rick B's answer, you will also need to create entries for the nodes that have never had that checked. That can be accomplished running this query:

```
INSERT INTO pathauto_state
SELECT 'node',n.nid ,1
FROM node n
WHERE n.type = 'api'
AND n.nid NOT IN (SELECT entity_id FROM pathauto_state)

```

which can be run either using drush on directly on the database as Rick described.

For taxonomy terms, determine your term's vocabulary id (`3` in the example below) and do a similar insert:

```
INSERT INTO pathauto_state
SELECT 'taxonomy_term', t.tid, 1
FROM taxonomy_term_data t
WHERE t.vid = 3
AND t.tid NOT IN (SELECT entity_id FROM pathauto_state)

```

# Answer
> 1 votes
I can verify this works with Views Bulk Operations (VBO).

Just tried what Gokul N K mentioned because I ran into the same problem and I can verify it still works with actual module versions.

I had existing taxonomy terms with unchecked “Generate automatic URL alias” and I wanted to update them in bulk.

My setup below: Drupal 7 (7.34) with Views (7.x-3.8), Pathauto (7.x-1.2) & VBO (7.x-3.2). I assume the modules present / installed configured.

1. deleted all taxonomy term aliases /admin/config/search/path/delete\_bulk
2. created a new view under /admin/structure/views and selected (Show) Taxonomy terms (in my case I selected all for all vocabularies, you could choose a certain vocab only)
3. select "fields" under "Display format", make more adjustements if necessary, then "Continue & edit"
4. Under fields, hit "add" and search for "Bulk operations: Taxonomy term", check and apply
5. then check "Update taxonomy term alias" and apply
6. Save your view and head to the views location and bulk update all taxonomy term path aliases

# Answer
> 1 votes
For those of you that need this to be in php form for using in a module/theme/etc really quick:

```
<?php
$update_auto_aliases = db_update('pathauto_state')
  ->fields(array(
    'pathauto' => 1,
  ))
  ->condition('entity_type', 'node', '=')
  ->execute();
?>

```

# Answer
> 1 votes
In my case (for Drupal10 ) bulk update was not generating aliases due to the fact that all the nodes (when you edit a node) had unchecked the checkbox "generate automatic alias". I have found a quick workaround (which I recommend when you have less than a few hundreds nodes). Go to /admin/content and from there select the nodes to be updated and make sure to select "Update Url alias" in the action dropdown (below the filters) and then click "Apply to selected items".

# Answer
> 0 votes
You need to delete the aliases for those previously created nodes before assigning them new aliases. This post explains how to do that.

# Answer
> 0 votes
I think this can be done with Drupal 8 and VBO (at least it worked for me) - using the "*Modify field values*" action - because "*Generate automatic URL alias*" is just a *field* automatically provided for each item of content. The caveat is that you'll have to do it for each *content type*, but this can all be done on the same form as follows :-

1. Select the items in the VBO listing required (or *Select all*)
2. Choose the "Modify field values" *action*
3. Click "Apply to selected items" button
4. Expand each content type you want to apply this to and tick the "*URL Alias*" checkbox. The expanded form should then show a "Generate automatic URL alias" checkbox. This defaults to ticked so you don't have to do/change anything. *Don't* press the *Submit* button yet...
5. After doing step #4 for each *content type* press the submit button.

I didn't get a confirmation message afterwards (which is disconcerting - probably a bug in the excellent VBO module) but it did work for me (presumably in the background batch job).

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


# Question
Title: How to render a custom block in a twig file?
I created a custom block named "Alert Bar" in the "navigation" region and I want to render it in my header file.

My header file currently has code like this to render the blocks -

```
{% if page.navigation or page.navigation_collapsible %}
  {% block navbar %}
    {% if no_head != 'true' %}
      {% include '@eventsns/components/navbar.html.twig' with incs %}
    {% endif %}
  {% endblock %}

```

Can I do something like `{% block alertbar %}` to display the alert bar block? The machine name says it is "alertbar" but I'm not sure if that's the correct variable since it does not render anything.

# Answer
1. block in twig are a "placedholder" to re-use text. They aren't drupal blocks
2. The easiest way as far I know to print a block is to use twig tweak module. The could should be `{{ drupal_entity('block', 'block_id', check_access=false) }}`
> 2 votes

# Answer
If you're rendering a custom block, you might want to use `block_content` instead.

1. Block: `{{ drupal_entity('block', 'block_id', check_access=false) }}`
2. Block Content: `{{ drupal_entity('block_content', 'content_block_id') }}`

Documentation: Rendering Blocks with Twig
> 0 votes

---
Tags: theming, blocks
---