# Question
Title: Send "admin (user awaiting approval)" email programmatically to admin
I want to send the "admin (user awaiting approval)" email after creating an account in the `user_insert hook`

I don't know what function is used. I did find `_user_mail_notify` which works well but only sends emails to registered users (and not to admins). Moreover, we see that `_user_mail_notify` has 8 possible parameters which correspond to messages sent to users and not to admins (in the UI, there are 9 possibles messages).

I'm looking for a function like `_admin_mail_notify` or `_administrator_mail_notify`

I know `_admin_mail_notify` doesn't exist with that name but maybe that helps to be clearer.

Here is somethings that works to send a user an email :

```
function my_module_user_insert(\Drupal\user\UserInterface $user) {
    // send email to new user
    _user_mail_notify('register_pending_approval', $user);
    // want to send user awaiting approval email, pseudo code
    // _admin_mail_notify('lorem', $lorem);
}

```

**EDIT 1**

I had not specified it to simplify my question but I did not activate the option "Visitors, but administrator approval is required" because I have 2 types of registrants.

Users with an “A” role can register without email verification or admin approval. And another “B” role that must be approved by the admins. By default users can all register and in the `hook_user_insert` I block the user with `$user->block();` so I wanted to also send an email to the admins.

I found this code in `user.module` which seems to be part of the solution:

```
if ($op == 'register_pending_approval') {
      // If a user registered requiring admin approval, notify the admin, too.
      // We use the site default language for this.
      \Drupal::service('plugin.manager.mail')->mail('user', 'register_pending_approval_admin', $site_mail, \Drupal::languageManager()->getDefaultLanguage()->getId(), $params);
    }

```

# Answer
After inspecting the code in `/core/modules/user`, I found these lines of code in `/core/modules/user/user.module` :

```
if ($op == 'register_pending_approval') {
      // If a user registered requiring admin approval, notify the admin, too.
      // We use the site default language for this.
      \Drupal::service('plugin.manager.mail')->mail('user', 'register_pending_approval_admin', $site_mail, \Drupal::languageManager()->getDefaultLanguage()->getId(), $params);
}

```

So, I just need to add this in hook\_user\_insert

```
function my_module_user_insert(\Drupal\user\UserInterface $user) {
    $params['account'] = $user;
    $site_mail = \Drupal::config('system.site')->get('mail_notification');
    // If the custom site notification email has not been set, we use the site
    // default for this.
    if (empty($site_mail)) {
        $site_mail = \Drupal::config('system.site')->get('mail');
    }
    // send email
    \Drupal::service('plugin.manager.mail')->mail('user', 'register_pending_approval_admin', $site_mail, \Drupal::languageManager()->getDefaultLanguage()->getId(), $params);
}

```
> 1 votes

---
Tags: users, emails
---


# Question
Title: Convert field from string_long to text_long
I need to convert a field on a paragraph from the `string_long` type to the `text_long` type.

There is data in the field so I can't change it in the UI.

How would I do this programmatically?

# Answer
> 3 votes
Here's the solution I came up with based on the example code provided by https://drupal.stackexchange.com/users/71454/miststudent2011. I had to adapt it a bit for this specific case:

```
/**
 * Convert plain text field to formatted text field.
 */
function mymodule_update_9002() {
  $entity_type = 'paragraph';
  $field = 'field_paragraph_variant';

  // Retrieve existing field data.
  $database = \Drupal::database();
  $tables = [
    "{$entity_type}__$field",
    "{$entity_type}_revision__$field",
  ];
  $existing_data = [];
  foreach ($tables as $table) {
    // Get the old data.
    $existing_data[$table] = $database->select($table)
      ->fields($table)
      ->execute()
      ->fetchAll(PDO::FETCH_ASSOC);
  }

  // Get the field config.
  $field_storage = \Drupal::entityTypeManager()->getStorage('field_storage_config');
  $field_storage_config = $field_storage->loadByProperties(['field_name' => $field]);

  foreach ($field_storage_config as $field_storage) {
    // Save the config as an array and change the type.
    $new_field_storage = $field_storage->toArray();
    $new_field_storage['type'] = 'text_long';

    // Delete the original field, otherwise the new table columns won't get added.
    $field_storage->delete();

    // Re-create the field.
    $new_field_storage = $field_storage->create($new_field_storage);
    $new_field_storage->enforceIsNew(TRUE);
    $new_field_storage->save();
  }

  // Restore the data.
  foreach ($tables as $table) {
    $insert_query = $database
      ->insert($table)
      ->fields([
        'bundle',
        'deleted',
        'entity_id',
        'revision_id',
        'langcode',
        'delta',
        $field . '_value',
        $field . '_format',
      ]);
    foreach ($existing_data[$table] as $row) {
      $row[$field . '_format'] = 'subscriber_text';
      $insert_query->values(array_values($row));
    }
    $insert_query->execute();
  }
}

```

---
Tags: entities, 9
---


# Question
Title: Creating remote video media entity programmatically not generating thumbnail
Using Drupal 9.4.1, I am creating a remote video media entity programmatically and for some reason the title and thumbnail are not being created. They are created when cron runs so in my terminal when I run `drush cron` I get these errors:

```
$ drush cron
  [notice] Starting CPC XML Import
  [warning] Illegal offset type UrlResolver.php:154
  [warning] Illegal offset type in isset or empty UrlResolver.php:155
  [warning] Illegal offset type UrlResolver.php:167
  [warning] Illegal offset type UrlResolver.php:168

```

The file that is producing this error is: /core/modules/media/src/OEmbed/UrlResolver.php

The media entities are created and attached to the node, however, no thumbnail and no title on the media entity.

An example URL I am using to create these entities is: `https://www.youtube.com/watch?v=1r4wuc_oGwY`

If I create the remote video entity through the media library UI, it creates it no problem. Thumbnail is generated and title is imported from YT.

My code is below:

```
    // Add Video Gallery Videos.
    if ($product_data->xpath('./marketing_content/content[@type="gallery-video"]')) {
      foreach ($product_data->xpath('./marketing_content/content[@type="gallery-video"]/content') as $video) {
        $link = $video->media->source; // This is the youtube link.
        $video = self::upsertVideo($link);
        $product->field_videos->appendItem(['target_id' => $video->id()]); // This works, it adds the media entity to the node.
      }
    }

```

and then here is my upsertVideo function:

```
    /**
     * Load or create a media type of remote_video based off of the URL.
     *
     * @param string $link
     *   A link to the video on CPC feed.
     *
     * @return \Drupal\media\Entity\Media
     *   The existing or newly created media entity.
     */
    private static function upsertVideo($link) {
      $query = \Drupal::entityQuery('media')
        ->condition('bundle', 'remote_video')
        ->condition('field_media_oembed_video', $link)
        ->execute();

      // Video found, return it.
      if (count($query) > 0) {
        $video = Media::load(reset($query));
        return $video;
      }

      // Create a new Remote Video media entity.
      $video = Media::create([
        'bundle' => 'remote_video',
        'uid' => \Drupal::currentUser()->id(),
        'field_media_oembed_video' => [
          'value' => $link,
        ],
      ]);

      $video->setPublished(TRUE)->save();

      return $video;
    }

```

# Answer
> 0 votes
`$link` is likely an object. Cast it to a string because it is used to dereference an array.

---
Tags: media, 9
---


# Question
Title: How do I change status from "Pending" to "Completed"?
Ubercart is install without any payment gateway. The workflow is to take user orders via out website and payments are handled offline. Once we received payment and shipped the product, we'd like to mark the order as Completed.

Here is the doc:

> 1. When a customer moves from the checkout form to the review order page, a new order is created with their information in the default status for the in\_checkout state. (By default, this is "In checkout.")
> 2. When a customer completes checkout, the order gets moved from the default in\_checkout status to the default status for the post\_checkout state. (By default, this is "Pending.")
> 3. The rest happens manually by order administrators, but the other two default statuses are "Processing" and "Completed." Processing is actually just another status in the post\_checkout state while Completed is the default status for the completed state.

However, I don't see a status dropdown list or similar UI element for changing an order's status when editing an existing order:

> http://shop.example.com/admin/store/orders/100001/edit

How can I change the status from `Pending` to `Completed`?

# Answer
Under the drupal 7version of Ubercart 3, order status would be changed using the dropdown found under

`http://shop.example.com/admin/store/orders/100001/view`
> 1 votes

# Answer
We update status in

Home » Administration » Store » Orders

or:

admin/store/orders/view

At that interface, we see four icons. If you hover over them you will see:

* View order \<order#\>
* Print order \<order#\>
* Edit order \<order#\>
* Delete order \<order#\>

Click on **View order \<order#\>**

The URL should now read:

admin/store/orders/\<order#\>/view

At the bottom of that screen you should see a drop down labeled:

**Order status**

with **Completed** as the last choice

Select the status you want, indicate whether or not you want a copy (good for troubleshooting and records) and then click on **Update**.
> 0 votes

---
Tags: 6, ubercart
---


title: Proactively rebuild view cache

text:
# Question
Title: Proactively rebuild view cache
I have a view that takes a while to build when the cache is cold (around 11s). When the cache is hot, the view loads quickly, of course (around 100ms). I'm using tag-based caching for this view, so when I add a node, and reload the view, it takes a while to generate, since the cache is being rebuilt during the request.

Is there a way to proactively rebuild the cache? I see two options, neither of which I know how to do:

* Warm up the view's cache on the next cron run, and run cron very often. For this I would need a way to check whether the cache is cold for that specific view. This is not ideal, because unlucky anonymous users could still visit the view before cron and get a bad experience.
* Warm up the view's cache directly after it's invalidated, i.e. during or directly after the POST request that created the new node. In my use case, it's better to let the user that creates nodes wait than to let some random unsuspecting anonymous users wait while they unwittingly hit a cold cache.

Any ideas?

# Answer
> 1 votes
You could render the view isolated from the page content so that the cache data of the view doesn't bubble up.

For example in a block:

```
  public function build() {
    $view = Views::getView('my_view');
    $view_build = $view->buildRenderable('block_1');
    $view_rendered = \Drupal::service('renderer')->renderPlain($view_build);
    $build = [
      '#markup' => $view_rendered,
      '#cache' => [
        'tags' => ['custom_cache_tag'],
      ],
    ];
    return $build;
  }

```

Then the block is served from cache until you invalidate the custom cache tag:

```
Cache::invalidateTags(['custom_cache_tag']);

```

For this you could use a QueueWorker, which you add to the queue when nodes are submitted. This queue worker could then, after invalidating the tag, trigger an anonymous request to rebuild the cached block.

Only one of many possible ideas. A universal solution would be a service which caches the rendered view markup on its own, which gives you more control to serve the invalidated content while the updated view is being rebuilt.

---
Tags: views, caching, 9
---


# Question
Title: How to prevent Drupal from scrolling to the bottom of ajax-appended content in a form
I have a custom form in Drupal.

When a user first sees this form, the only thing on the page is a select box, along with a few other elements they have to fill out.

When they make a selection from the select box, the #ajax callback regenerates the form, and adds about 50 results to the page.

By default, Drupal is scrolling down to the last result. This is a problem, because the users have to scroll back up to the elements near the top of the page to finish their work.

Is there a way to prevent Drupal from scrolling to the bottom of the newly-added form content?

Here is a snippet that shows how I'm setting up the form:

```
$form = array(
'#tree' => TRUE,
'#prefix' => '<div id="myform">',
'#suffix' => '</div>',
);

```

Here is a snippet from the select box that triggers returning the results.

```
$form['selectbox'] = array(
  '#type' => 'select',
  '#title' => t('Select box'),
  '#options' => $predefined_select_options,
  '#empty_option' => t('Select something!'),
  '#ajax' => array(
    'callback' => 'mymodule_form_ajax',
    'wrapper' => 'myform',
    'effect' => 'fade',
  ),
);

$form['other_stuff'] = array(
  '#type' => 'textfield',
  '#title' => t('Other stuff they need to fill out here'),
);

if (isset($form_state['values']['select box'])) {
  foreach ($lots_of_results as $result) {
    $form[$result] = array(
      '#type' = 'fieldset',
      '#title' = 'Lots of results in their own field sets',
    );
  }
  // It scrolls to the bottom of this huge list after it's rendered.
}

```

Here is the ajax handler for the select box.

```
function mymodule_form_ajax($form, $form_state) {
  return $form;
}

```

# Answer
You could override the Drupal.ajax.prototype.success handler (/misc/ajax.js) in your **theme** to control behavior, maybe commenting out Drupal.unfreezeHeight(); and Drupal.freezeHeight(); could do the job? Just copy the whole function and manipulate it your own way.

```
/**
 * Handler for the form redirection completion.
 */
Drupal.ajax.prototype.success = function (response, status) {
  // Remove the progress element.
  if (this.progress.element) {
    $(this.progress.element).remove();
  }
  if (this.progress.object) {
    this.progress.object.stopMonitoring();
  }
  $(this.element).removeClass('progress-disabled').removeAttr('disabled');

  Drupal.freezeHeight();

  for (var i in response) {
    if (response.hasOwnProperty(i) && response[i]['command'] && this.commands[response[i]['command']]) {
      this.commands[response[i]['command']](this, response[i], status);
    }
  }

  // Reattach behaviors, if they were detached in beforeSerialize(). The
  // attachBehaviors() called on the new content from processing the response
  // commands is not sufficient, because behaviors from the entire form need
  // to be reattached.
  if (this.form) {
    var settings = this.settings || Drupal.settings;
    Drupal.attachBehaviors(this.form, settings);
  }

  Drupal.unfreezeHeight();

  // Remove any response-specific settings so they don't get used on the next
  // call by mistake.
  this.settings = null;
};

```

Another option would be to render the ajax form with ajax\_commands where you could add custom js handlers to your callback.
> 3 votes

# Answer
Ran into this issue, where after ajax replace, it would auto scroll up to the top of the page.

```
 '#ajax' => [
    'callback' => 'mymodule_form_ajax',
    'wrapper' => 'myform',
    'disable-refocus' => true, // <-- The solution
  ],

```

OR

```
  '#type' => 'submit',
  '#value' => $this->t('Submit'),
  '#ajax' => [
    'callback' => '::submitForm',
  ],
  '#attributes' => ['data-disable-refocus' => 'true'], // <-- The solution

```
> 1 votes

---
Tags: forms, ajax, javascript
---


# Question
Title: How to show terms with a specific depth as exposed filter
I would like, on Drupal 9, to show in a view as exposed filter a taxonomy term with depth 0, one with level one (the children) and one with level 2 (level one's children).

Basically I have a content type that has a taxonomy term reference field to a vocabulary that has up to three levels of depth. I'd like to make 3 exposed select, as in the screen  So, showing the first level as one select, then enable the second select if the term selected first has children and again enable the third select if the second term has children too.

I'm trying to do it with standard view, but I cannot figure how.

How can I accomplish this?

# Answer
Not possible with Drupal core, you'll need to install the Simple Hierarchical Select contrib module.
> 0 votes

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


# Question
Title: Views SQL query not showing in production
I don't see any of my data from my view on my production website. I'd like to compare the data generated in the view compared to my local (which is working fine).

But in my production website, I don't see the executed query  Even if all the config seems to be set the right way (at least, the same as my working local)

Do I have something else to configure ? Maybe inside a settings.php ?

# Answer
Found it ! I had this written in a production config file

```
$config['views.settings']['ui']['show']['sql_query']['enabled'] = FALSE;
$config['views.settings']['ui']['show']['performance_statistics'] = FALSE;

```
> 1 votes

---
Tags: views, 9
---


# Question
Title: Argument 6 passed to Drupal\layout_builder\Plugin\Block\InlineBlock::__construct() must implement interface Drupal\Core\Session\AccountInterface
I was upgrading Drupal 8 to 9. I installed 'Upgrade Status' module and fixed as suggested by it. Now it was time to upgrade to D9. I changed on composer.json.

```
"drupal/core-composer-scaffold": "^8.9.0",
"drupal/core-recommended": "^8.9.0",

```

To

```
"drupal/core-composer-scaffold": "^9.1.0",
"drupal/core-recommended": "^9.1.0",

```

Then ran following command:

```
composer update
drush cr
drush updb -y

```

After running the update, I got the Drupal 9.2.6. When browsing the URL, it showed following error:

> TypeError: Argument 6 passed to Drupal\layout\_builder\Plugin\Block\InlineBlock::\__construct() must implement interface Drupal\Core\Session\AccountInterface, instance of Drupal\Core\Logger\LoggerChannel given, called in /app/web/core/modules/layout\_builder/src/Plugin/Block/InlineBlock.php on line 117 in Drupal\layout\_builder\Plugin\Block\InlineBlock-\>\__construct() (line 95 of core/modules/layout\_builder/src/Plugin/Block/InlineBlock.php).

I googled but could not find out the solution. Any suggestion is really appreciated.

# Answer
Mine was a failed patch for:

web/core/modules/layout\_builder/src/Plugin/Block/InlineBlock.php

Leading to an InlineBlock.php.rej file being created.

Try the following patch if yours was the same: -

```
diff --git a/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php

diff --git a/web/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php b/web/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php
--- a/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php  (date 1656600871622)
+++ b/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php  (date 1656600871622)
@@ -93,11 +93,13 @@
    * @param \Drupal\Core\Session\AccountInterface $current_user
    *   The current user.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository, AccountInterface $current_user) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityDisplayRepositoryInterface $entity_display_repository, TimeInterface $time, AccountInterface $current_user = NULL) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);

     $this->entityTypeManager = $entity_type_manager;
     $this->entityDisplayRepository = $entity_display_repository;
+    $this->time = $time;
+
     $this->currentUser = $current_user;
     if (!empty($this->configuration['block_revision_id']) || !empty($this->configuration['block_serialized'])) {
       $this->isNew = FALSE;

```
> 0 votes

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


# Question
Title: Customer profiles cannot hold more than 1 values, even when allowing multiple profiles per user
I have custom API that creates new `Customer` profiles with different addresses / emails:

```
$profileStorage->create([
        'type' => 'customer',
        'uid' => $this->currentUser->id(),
        'status'=> 1,
        'address' => $addressData
])
$profile->setDefault(true);
$profile->save();

```

It works creating those profiles and attaching them to the current user. However, then after whenever I try to edit the user's account fields or just use `$user->validate()` I get this error:

**"customer\_profiles: Customer profiles: this field cannot hold more than 1 values."**

However Customer Profile Type has both "Allow multiple profiles per user" and "Profiles of this type represent Commerce customer profiles" selected.

This has been the case in Drupal 8 and 9.

UPDATE:

It seems this error actually occurs at `$entity->validate()`, not on `save()`

This is the contents of `core.entity_form_display.profile.customer.default.yml`

```
uuid: xxx7f0e2-d809-4d2b-9388-af399c98xxxx
langcode: en
status: true
dependencies:
  config:
    - field.field.profile.customer.address
    - field.field.profile.customer.field_email
    - profile.type.customer
  module:
    - address
  enforced:
    module:
      - commerce_order
_core:
  default_config_hash: xxxxVkJkUSPhil9xxxxdTivMqxCUloT_71AHWxxxx
id: profile.customer.default
targetEntityType: profile
bundle: customer
mode: default
content:
  address:
    type: address_default
    weight: 0
    region: content
    settings: {  }
    third_party_settings: {  }
  field_email:
    type: email_default
    weight: 1
    region: content
    settings:
      placeholder: ''
      size: 60
    third_party_settings: {  }
hidden: {  }

```

and the contents of `profile.type.customer.yml`

```
uuid: xxxx4f32-xxxx-xxxx-xxxx-bd10470bxxxx
langcode: en
status: true
dependencies:
  enforced:
    module:
      - commerce_order
third_party_settings:
  commerce_order:
    customer_profile_type: true
_core:
  default_config_hash: xxxxAQDUxxxxwavxxxxlcbJx9xxxxFtCq8l73Axxxx
id: customer
label: Customer
display_label: 'Customer information'
multiple: true
registration: false
roles:
  authenticated: authenticated
  verified_email: verified_email
  verified_cc: verified_cc
allow_revisions: false
new_revision: false

```

# Answer
> 1 votes
That setting means the customer may have multiple profiles of that type assigned to their uid, not that every profile reference field can itself be used for multiple value references. That said, I'm not aware of a field in Commerce Core called `customer_profiles`. Is this something custom? You might just need to update its definition to be able to put multiple references in it.

# Answer
> 0 votes
Since this profiles are tied with drupal commerce, we don't have to show this on the user profile edit page. That is actually what is going on. User can have multiple profiles at the checkout stage, but when you going to save user with multiple profiles, it blocks with error 'cannot hold more then 1 values'. All you need to do is in `Configuration > People > Account Settings > Manage Form Display` disable profile field and save. That'll fix the problem

---
Tags: commerce, 9
---


# Question
Title: getStorage() on null when using entityTypeManager in form
I'm trying to use dependency injection correctly in a custom form but I'm getting an error when trying to access entityTypeManager.

```
<?php

namespace Drupal\my_module\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\my_module\Service\AliasCsvParser;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a my_module form.
 */
class myModuleImportForm extends FormBase {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Class constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager
  ) {
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    $form = new static(
      $container->get('entity_type.manager')
    );

    return $form;
  }

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

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

    $form['path_alias_csv'] = [
      '#type' => 'my_module_managed_file',
      '#title' => $this->t('Alias import csv'),
      '#description' => $this->t('upload a csv file containing at least the following 3 columns "id, alias, langcode"'),
      '#upload_location' => 'private://my_module_import',
      '#upload_validators' => [
        'file_validate_extensions' => ['csv'],
        '_validate_alias_csv' => [],
      ],
    ];

    $form['results'] = [
      '#type' => 'container',
      '#attributes' => [
        'class' => [
          'parse-results',
        ],
      ],
    ];

    $form['actions']['#type'] = 'actions';
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Import aliases'),
      '#button_type' => 'primary',
      '#attributes' => ['class' => ['visually-hidden']],
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $csv_field = $form_state->getValue('path_alias_csv');
    $parser = new AliasCsvParser(reset($csv_field));
    $parser->saveAliasFromCsv();
    if (TRUE) {
      $file = $this->entityTypeManager->getStorage('file')->load(reset($csv_field));
      $file->setPermanent();
      $file->save();
    }

  }

}

```

I get the error `Call to a member function getStorage() on null in` on this line `$this->entityTypeManager->getStorage('file')->load(reset($csv_field));` So I think the class isn't being initialised correctly and `$entityTypeManager` is null but I don't know why.

Cheers Dan

# Answer
I was incorrectly trying to chain function calls

This works.

```
$file_storage = $this->entityTypeManager->getStorage('file');
$file = $file_storage->load(reset($csv_field));
$file->setPermanent();
$file->save();

```
> -1 votes

---
Tags: forms, dependency-injection
---


# Question
Title: Migrate nodes with special characters in title
Given a source's title like

```
This "cool" & "neat" article's title has HTML entities

```

, is creating a title of

```
This "cool" & "neat" article's title has
HTML entities

```

Must I create a process plugin to handle this? My migration yml looks somewhat like this:

```
...
source:
...
    -
      name: title
      label: 'Title'
      selector: title
...
process:
  title: title
...

```

# Answer
It looks like you will have to define a custom process plugin to do this - I can't find any plugin for it on this or this page.

There is a PHP function called `htmlspecialchars_decode`, which decodes all HTML special character entities, which you can probably use. It takes in a string and returns the decoded string. We also need to pass it the ENT\_QUOTES flag for it to convert both double and single quotes.

So you could probably do something like:

```
namespace Drupal\YOUR_MODULE\Plugin\migrate\process;

use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;

/**
 * Decode HTML entities.
 *
 * @MigrateProcessPlugin(
 *   id = "decode_html_entities"
 * )
 */
class DecodeHtmlEntityString extends ProcessPluginBase {

  public function transform(string $value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    return htmlspecialchars_decode($value, ENT_QUOTES);
  }

}

```
> 2 votes

# Answer
I solved that with callable plugin:

```
process:
  title:
    source:
      - g_title
      - ENT_QUOTES
    plugin: callback
    callable: htmlspecialchars_decode
    unpack_source: true

```
> 0 votes

---
Tags: 8, nodes, migrations
---


# Question
Title: Is it possible to populate a field entity reference with query parameters?
I created an entity reference field for a node filtered by a view type "entity reference", but I need to pass an argument in the contextual filter of this view, to filter entities on my field.

I tried passing my argument on the URL in a query parameter (e.g. node/add/page\_interieur?dossier=2), but I never get results in my field autocomplete.

Is it possible to do that with this method or another one?

### Settings for the contextual filter with the *Query parameter* option

>

### Settings for the *Entity reference* field

>

# Answer
To programmatically pass argument to my field entity reference with link `node/add/page_interieur?dossier=512` :

```
use Drupal\node\Entity\Node;
use Drupal\Core\Form\FormStateInterface;

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

  if ($form_id == 'node_page_interieur_form') {
    $nid  = \Drupal::request()->query->get('dossier');

    if (is_numeric($nid) && isset($form['field_dossier_reference'])) {
      //autocomplete select field reference
      $form['field_dossier_reference']['widget']['#default_value'] = $nid;
      //disable field
      $form['field_dossier_reference']['#disabled'] = TRUE;
      //pass my ID like argument in my field to filter only pages referenced
      $form['field_liste_ref_dossier']['widget']['target_id']['#selection_settings']['view']['arguments'][] = $nid;
    }

    foreach (array_keys($form['actions']) as $action) {
      if ($action != 'preview' && isset($form['actions'][$action]['#type']) && $form['actions'][$action]['#type'] === 'submit') {
        $form['actions'][$action]['#submit'][] = 'science_po_page_interieur_form_submit';
      }
    }
  }
}

```

My contextual filter configuration in views :
> 1 votes

# Answer
**For** example.com/path?id=55

\[current-page:query:id\]

**For** example.com/path/55

\[current-page:url:args:last\]

**For** example.com/path/alias

\[current-page:url:unaliased:args:last\]
> -1 votes

---
Tags: views, entities
---


# Question
Title: How do I hide the title on a specific node?
How can I hide the title on a specific node?

I have tried the following three modules, but none of them do what I'd like.

1. Page Title
2. Exclude node title
3. Automatic Node titles

I added field\_hide\_title to the page content type, the code in `hook_preprocess_node()` function. It can't work fine.

The value shown from `print_r($vars['node'])` is the following:

```
stdClass Object(
  [vid] => 4
  [uid] => 1
  [title] => search_material
  [log] =>
  [status] => 1
  [comment] => 1
  [promote] => 0
  [sticky] => 0
  [nid] => 4
  [type] => page
  [language] => zh-hant
  [created] => 1339055801
  [changed] => 1339727555
  [tnid] => 0
  [translate] => 0
  [revision_timestamp] => 1339727555
  [revision_uid] => 1
  [body] => Array(
    [und] => Array(
      [0] => Array(
        [value] =>
        [summary] =>
        [format] => php_code
      )
    )
  )
  [field_hide_title] => Array(
    [und] => Array(
      [0] => Array([value] => 1)
    )
  )
  [rdf_mapping] => Array(
    [rdftype] => Array([0] => foaf:Document)
    [title] => Array(
      [predicates] => Array([0] => dc:title)
    )
    [created] => Array(
      [predicates] => Array(
        [0] => dc:date
        [1] => dc:created
      )
      [datatype] => xsd:dateTime
      [callback] => date_iso8601
    )
    [changed] => Array(
      [predicates] => Array([0] => dc:modified)
      [datatype] => xsd:dateTime
      [callback] => date_iso8601
    )
    [body] => Array(
      [predicates] => Array([0] => content:encoded)
    )
    [uid] => Array(
      [predicates] => Array([0] => sioc:has_creator)
      [type] => rel
    )
    [name] => Array(
      [predicates] => Array([0] => foaf:name)
    )
    [comment_count] => Array(
      [predicates] => Array([0] => sioc:num_replies)
      [datatype] => xsd:integer
    )
    [last_activity] => Array(
      [predicates] => Array ([0] => sioc:last_activity_date)
      [datatype] => xsd:dateTime
      [callback] => date_iso8601
    )
  )
  [cid] => 0
  [last_comment_timestamp] => 1339055801
  [last_comment_name] =>
  [last_comment_uid] => 1
  [comment_count] => 0
  [name] => admin
  [picture] => 0
  [data] => b:0;
  [entity_view_prepared] => 1
)

```

============================================================ UPDATE:

# but I found one thing. before I change the title to NULL, the title has been displayed out...

print\_r($vars) in mytheme\_preprocess\_page function:

\[summary\] =\> \[format\] =\> php\_code ) ) ) \[field\_hide\_title\] =\> Array ( \[und\] =\> Array ( \[0\] =\> Array ( \[value\] =\> 1 ) ) ) \[rdf\_mapping\] =\> Array ( \[rdftype\] =\> Array ( \[0\] =\> foaf:Document ) \[title\] =\> Array ( \[predicates\] =\> Array ( \[0\] =\> dc:title ) ) \[created\] =\> Array ( \[predicates\] =\> Array ( \[0\] =\> dc:date  =\> dc:created ) \[datatype\] =\> xsd:dateTime \[callback\] =\> date\_iso8601 ) \[changed\] =\> Array ( \[predicates\] =\> Array ( \[0\] =\> dc:modified ) \[datatype\] =\> xsd:dateTime \[callback\] =\> date\_iso8601 ) \[body\] =\> Array ( \[predicates\] =\> Array ( \[0\] =\> content:encoded ) ) \[uid\] =\> Array ( \[predicates\] =\> Array ( \[0\] =\> sioc:has\_creator ) \[type\] =\> rel ) \[name\] =\> Array ( \[predicates\] =\> Array ( \[0\] =\> foaf:name ) ) \[comment\_count\] =\> Array ( \[predicates\] =\> Array ( \[0\] =\> sioc:num\_replies ) \[datatype\] =\> xsd:integer ) \[last\_activity\] =\> Array ( \[predicates\] =\> Array ( \[0\] =\> sioc:last\_activity\_date ) \[datatype\] =\> xsd:dateTime \[callback\] =\> date\_iso8601 ) ) \[cid\] =\> 0 \[last\_comment\_timestamp\] =\> 1339039221 \[last\_comment\_name\] =\> \[last\_comment\_uid\] =\> 1 \[comment\_count\] =\> 0 \[name\] =\> admin \[picture\] =\> 0 \[data\] =\> b:0; \[entity\_view\_prepared\] =\> 1 ) )

# Answer
> 16 votes
You can create a cck field(checkbox/boolean) for that will act as a flag. So you can have a dynamic option if you want to hide the node or not.

Pseudo code:

In template.php

```
function yourtTheme_process_page(&$variables) {
  if($variables['node']->field_hide_title['und'][0]['value']) {
    $variables['title'] = NULL;
  }
}

```

Haven't try this code but I think this will work.

EDIT: Added screenshot of a new field

This should be the value of your cck

# Answer
> 3 votes
Use CSS.

Each individual node will have a specific class on the `<body>` tag of the page, which will allow you to target your specific node.

For example, say you're trying to hide the title on node 69, it would look like the following:

```
.page-node-69 .page-title {
  display: none;
}

```

for node 150 it would look like this:

```
.page-node-150 .page-title {
  display: none;
}

```

You might have to tweak it depending on your theme, and you might have to more specifically target the page title (i.e. `h1.page-title`) just in case there is more specificity further up the cascade.

# Answer
> 2 votes
I guess you could add something like this into your template.php:

```
function YOURTHEME_preprocess_node(&$node) {
    // check if it's the node of interest
    if($node['title'] == 'your-specific-node-title') {
       // set the title to NULL so nothing is rendered
       $node['title'] = NULL;
    }
}

```

As chapabu suggested it might be a better idea to check the node nid instead of the title:

```
if($node['nid'] == 'your-node-nid') {
   ...
}

```

# Answer
> 0 votes
The CSS on the title is a class of title and ID of page-title, so my CSS needs to be

```
.page-node-69 #page.title {
   display: none;
}

```

for this to work.

# Answer
> 0 votes
For Drupal 9, the title is a block. You can edit the block to exclude showing it on specific pages. If I recall, that's a core feature and not a plugin we're using. =)

---
Tags: 7, entities, theming
---


# Question
Title: How to create a Solr search with partial matches and autocomplete?
I configured a search box for a drupal site and am a bit confused on how to get a search working with partial matches and a sensible autocomplete.

Some basic details:

* Drupal: 9.3.9
* Modules: Search API, Search API Autocomplete, Search API Solr
* Solr: 8.11.1

The search searches through different fields from several types of content. At first I set the field types to "Fulltext". Then I noticed that only complete words are matched. So searching for "idea" would not find pages containing "ideas". That worked when I changed all field types to "Fulltext ngram". But: Now the autocomplete suggests all the partials as well. So entering "super" would suggest "superh", "superhe" and "superhero". That's not really useful for the site's visitors.

What I already tried: The autocomplete uses the suggester "Retrieve from server". I tried to enable the additional module "search\_api\_solr\_autocomplete". That adds three more suggesters, "Solr Spellcheck", "Solr Suggester" and "Solr Terms". The spellcheck suggester did not yield any autocomplete suggestions. Neither did the Solr Suggester. Solr Terms does the same as "Retrieve from server", it suggests all intermediate steps between the search word and the finished term, letter for letter.

What I am looking for is a clue how to configure this so that the search matches tokens with partial searches, but that only complete tokens are used for the autocomplete feature. Maybe a configuration step is missing?

# Answer
> 4 votes
I couldn't get this to work previously, but after upgrading to Drupal 9.4 it now works. What I did was this:

* I added a new field "autocomplete\_tokens" as an "aggregated\_field". I put all the text fields in there that were part of the search, especially the rendered HTML and the file contents.
* As a field type I chose "Fulltext Tokens", which is defined as "Full text field without any processing like stemming or stop word filters, just unmodified tokens from the text separated by white spaces". This way, all the words in the input stay exactly as they are. No stemming, no breaking up ito ngrams.
* In the "autocomplete" tab of my index, I clicked on "Edit" and chose the suggester "Retrieve from server". Under "Configure suggester Retrieve from server \> Override used fields" I chose the new field "autocomplete\_tokens". This way, the autocomplete feature got its suggestions only from my new field, not from all the other stemmed and ngrammed fields.

And that's it, this time it worked like a charm. Reindex all contents (since a new field was added and needs to be present in the index), and the autocomplete now behaves as expected. I can only guess that I did something stupidly wrong or that something changed with Drupal 9.4.

This solution has some caveats, of course. First, when I add a new field to be part of the search (e.g. for a new content type), I have to remember to add it to the autocomplete token concatenation field as well. This can easily be forgotten. On the other hand, I also have to add the new field to the view and maybe other places, so this needs to be tested anyway.

I also found that this datatype does not remove punctuation from the tokens. So if my content contains e.g. "unbowed, unbent, unbroken", the autocomplete suggestion for "unb" is "unbowed," and "unbent," along with "unbroken" (or "unbroken.", if it ends as a sentence). This can maybe dealed with using a different field type or adding a special field type to the schema.xml. Since I wanted to close this issue fast, I added a filter instead to my local search module:

```
function my_module_search_api_autocomplete_suggestions_alter(array &$suggestions, array $alter_params) {
  $allNewSuggestions = [];
  foreach ($suggestions as $index => $suggestion) {
    // Remove punctuation from the end of autocomplete suggestions.
    $newSuggestionSuffix = rtrim($suggestion->getSuggestionSuffix(), ".!?,-'\"");
    $suggestion->setSuggestionSuffix($newSuggestionSuffix);

    // Now remove duplicates that occur if two different input suggestions are
    // reduced to the same token when removing the punctuation.
    $newSuggestion = $suggestion->getSuggestionPrefix() . $newSuggestionSuffix;
    if (in_array($newSuggestion, $allNewSuggestions)) {
      unset($suggestions[$index]);
      continue;
    }
    $allNewSuggestions[] = $newSuggestion;
  }
}

```

This removes all punctuation from the end of the suggestions and removes duplicates (if a word was suggested one with a trailing comma and once with a trailing full stop, for example). Now we might have fewer than the configured number of sugestions, but I can live with that.

I also notice that all the suggestions are in lower-case, which looks a bit strange for German nouns. But for now I can also live with that.

---
Tags: search
---


# Question
Title: Anonymous User name is changed to a strange name in watchdog logs
Our D9 site's dblog is showing the anonymous user name as a very stange name instead of anonymous. All anonymous users are shown as "closhewupheheh…" even though the anonymous user name is set to "Anonymous" in the account settings.

I suspect this may be related to the "realname" module but there is nothing in the issue queues related to the anonymous user name.

Is this anything to be concerned about?

Is there a way to get it to display "Anonymous" again?

# Answer
Not sure what the root cause was but I ended up updating the user account's DB entry to change it back to Anonymous. Resolved.
> 0 votes

---
Tags: users
---


# Question
Title: Webform 4 passing in email token into the redirect url confirmation page
This is for Drupal 7 and webform 4. I'm trying to pass in an email token value submitted from the previous webform page into the confirmation url. But it shows up blank. And the token browser dialog isn't working so I can't see how it should be formatted.

How do I reference the email field value token in the webform?

# Answer
> 0 votes
The token value is this:

`[submission:values:email]`

You can see all of it using this:

`[submission:values]`

---
Tags: 7, webforms, tokens
---


# Question
Title: How to call a token directly from the WYSIWYG editor?
I wish to call a token directly from the WYSIWYG text editor of a node of a certain content type.

For example, I wish to call the token `[current-page:title]` (node `H1` tag) from the edit page.

So, for example for a node named "Tulip (Tulipus)":

## Input

> `The term [current-page:title] [plural: Tulipa] is used to describe a flower of the family Liliaceae.`

## Output

> The term Tulip (Tulipus) \[plural: Tulipa\] is used to describe a flower of the family Liliaceae.

How can this be done?

# Answer
You'll want the Token Filter module.

As the module's page says, you need to make sure you have the right context for the tokens you want to use; if the context isn't available, token replacement will fail silently.

Also note that it's not yet ready for CKEditor 5.
> 2 votes

---
Tags: nodes, tokens
---


# Question
Title: Payment method that can only be selected in admin UI
How can I make a payment method only available to select when an admin is manually entering an order in the admin UI, and not visible to customers when checking out normally?

Restricting the payment method to the customer role of admin does not work, presumably because the logged in admin is not seen as the actual customer.

# Answer
I solved this by creating a custom condition plugin, as described here: https://docs.drupalcommerce.org/commerce2/developer-guide/core/conditions
> 1 votes

---
Tags: commerce
---


# Question
Title: How to restrict access to a specific node to to an individual user
I am trying to see if I can put together a D9 site for this person how designs custom 3D images and animations. I'm working on a way to have him sell the files once completed, but first I need a way for him to preview the file for the client while he's working on it. For this to work, I need a way to restrict viewing of the node/image so only the logged in client can see it.I looked at the modules that I thought might work, and so far only Taxonomy Access Control comes close, but I'm not sure if it does what I need. Does anybody have any ideas what might be what I'm looking for?

# Answer
Here is a relatively easy way to do this without writing code.

Assumptions

* There is one designer who has multiple clients.
* The designer should have access to everything, while each client should only have access to that client's designs from the designer.

How to implement

* Give the designer all content administrator permissions. This will let the designer create, update, and delete content as needed.
* Create a custom content type and name it however you like (for this example, we'll call it **Designs**).
* Set up accounts for clients with the authenticated role.
* Give the authenticated role permission to "view own content" for the **Designs** content type. Do not give authenticated users the permission to edit or delete **Designs** content (or, more broadly, all of their own content).
* When the designer creates a **Design** node for a client, in the admin UI, assign the client as the author of the node.

Because the client is the node author, they will be able to view the content (since it is their own content, because they are assigned as the author) but nothing else (based on the permissions configured above).
> 1 votes

---
Tags: nodes
---


# Question
Title: Can you use Google Analytics module with UA-xxx-xx along with GTM tracking code?
If we have Google Analytics module set up with a UA id and also wish to do some custom click tracking set up with GTM.

For one, is using both codes allowed or should be done? (UA-xxxx via Google Analytics module and GTM code in html.twig template).

Secondly, if I only create a specific click event tracking on a button in GTM (no page views tracking). Would this still cause any duplication issues. Logic says no, but not sure about the basic level of tracking simply by adding the tag scripts.

Any clarity would be great.

Thanks in advance guys.

# Answer
Do not mix the Google Analytics module's javascript with the GTM javascript on the same site. This will create a mess and you'll probably get duplicate tracking, plus you'll bloat your pages.

Instead, use GTM for everything. One of the "tags" that Google Tag Manager "manages" is Google Analytics, so this is the best approach.

Uninstall the Google Analytics module from your site and use the GoogleTagManager module instead.

You can set up UA inside GTM from within the GTM admin UI.

Also, if this is a new site, consider upgrading to GA4 instead of UA because UA has been sunset.
> 1 votes

---
Tags: google-analytics
---


# Question
Title: Embedding a text chunk in the text-area of two or more nodes
I wish to embed the same text chunk inside the **text-area** of two or more nodes.

One possible way is to call a node of content type B **inside** the relevant nodes of content type A by HTML `iframe` but iframes have their problems and aren't ideal.

How would you suggest to do that?

# Answer
"How to add a chunk of text in multiple nodes?"

1. Create a custom module and add a custom token to the module that contains the chunk of text.
2. Install the Token Filter module and enable it for the input filter that you use in your text area.
3. Add the custom token to the text area on the relevant nodes.
> 0 votes

# Answer
This is an answer to the original question of "**How to put a node of content type B inside a node of content type A?**"

There are a lot of ways to do this, but the most common is probably an entity reference.

This answer assumes you are using Drupal 9, but roughly the same approach can be followed for Drupal 7.

Add an entity reference field on content type A.

Next, edit each node of content type A that should include content type B, and set the appropriate content type B in the entity reference field.

This establishes a connection between a specific node of content type A and content type B.

To change how content type B is displayed on content type A, you can use view modes.

Create a view mode called something like "entity reference" on content type B, and then configure the display as you wish it to appear on content type A.

Then, on content type A, go to "Manage display" and set "Rendered entity" as the format for the entity reference field. Click the little gear to the right, and choose the view mode for content type B that you created as an entity reference.

For more complex layouts, you can use Layout Builder to create the view mode, but that's outside the scope of this answer.
> 2 votes

---
Tags: nodes, 9
---


# Question
Title: Make views output more dynamic with knockout.js or other similar framework?
I am currently experimenting with knockout.js so i can make views output more dynamic.

I know React and angular among other newer frameworks are recommended but i do not want to create single page apps or have a separate built app with a fully headless Drupal.

Currently i am constructing my views as normal so the user doesn't have to do anything new. I then rewrite the results so i can add the required knockout.js functionality. For example I can add local filtering options, local cached data, dynamically update portions of the page all without ever making additional requests to the server. Most of the functionality works 100% in the users browser unless i request more data.

I am currently looking at it to make a POS "point of sale" built on top of Drupal commerce module. The idea behind this is to make it almost 100% offline first and fully dynamic.

My question is, generally does anyone have experience with augmenting views like thiss and if so what frameworks did you use ?

# Answer
> 1 votes
React is reasonably easy to get started with. It's easy to add pieces of React onto an existing site; you definitely don't need to make a completely decoupled app.

I've built a few React frontends for views and it was pretty easy once I learned the basics of React.

For an easy way to get started, see this tutorial on how to integrate React into an existing app.

For more information, see this curated list on getting started with React and Drupal.

For an example of a module that integrates React, see React Comments, which adds a React UI to standard Drupal comments.

# Answer
> 0 votes
The quickest way to do this is take your view and create a new display type of "REST export" if you don't see this option you will need to enable the core "RESTful Web Services" module.

this gives you a new toy as you can then deliver the data via rest endpoint to any "front-end" page using whatever js library you want.

all you need to know how todo is create a custom module, with a custom controller (to make the page) and provide a template for that page and add js to that page

(see https://www.drupal.org/docs/drupal-apis/routing-system/introductory-drupal-routes-and-controllers-example to do that ^^^)

---
Tags: views, commerce, javascript
---


# Question
Title: How do I add a variable for menu.html.twig?
I want a variable in menu.html.twig file. I tried adding the following hook in the theme's .theme file, but the template file doesn't print anything.

```
function my_theme_name_preprocess_menu(&$variables) {
  $account = \Drupal::currentUser();
  $variables['current_username'] = $account->getDisplayName();
}

```

The menu.html.twig template file contains the following markup.

```
<div class="title-container">
   <span class="item-title">{{ current_username }}</span>
</div>

```

# Answer
Two issues. For preprocessing in general, a variable depending on the current user needs also cache metadata:

```
$variables['current_username'] = [
  '#markup' => \Drupal::currentUser()->getDisplayName(),
  '#cache' => [
    'contexts' => [
      'user',
    ],
    'tags' => [
      'user:' . \Drupal::currentUser()->id(),
    ],
  ],
];

```

Specific to menu templates. They are not normal template files, they contain a macro which is run for each menu item, where only the variables are available which are passed in the argument list:

```
{% macro menu_links(items, attributes, menu_level) %}

```

So you need to add the variable in the `items` menu tree so that it is available for the menu item you want to target.
> 1 votes

---
Tags: 8, hooks
---


# Question
Title: Exception: In BootstrapHook.php line 32, how can I consistently resolve this?
My build process is (mostly working), but sometimes when I swap out to a new project, I am winding up with an error which looks like the output below. I have found this error message extremely unhelpful in sorting out what my underlying issue might be. And having resolved this issue in the past, and folded it into my build process, does not seem to have resolved it for all future builds of similar projects. I am seeking advice on how to proceed here, would appreciate any help I can get, please. Thanks.

**UPDATE #01**:

leymanxx:

Switching out to use the local drush ( `sudo -u jenkins vendor/drush/drush/drush site-install . . .` ) does not appear to have changed the outcome.

*Is your site managed with Composer?* Yes. *What template?* no site template, just a composer.json file derived originally from `drupal-composer/drupal-project`. *What version of Drush?* `Drush Commandline Tool 9.7.2` *What version of Drupal?* composer.json specifies: `"drupal/core": "~8.8.5",`.

-- Hugh Esco

```
# sudo -u jenkins /usr/local/drush/drush site-install \
    -y -vvv \
    --db-url='mysql://my_project_code_db_user_dev:a_somewhat_secret_db_password@localhost/my_project_code_db_dev' \
    --db-su=root --db-su-pw='my_very_secret_root_password' \
    --account-mail=site-admin@example.org \
    --account-name=admin \
    --account-pass=reallysecret \
    --site-name=efc9c26-00497.dev.my_project_code.example.org

 [preflight] Config paths: /opt/local/my_project_code/drupal/vendor/drush/drush/drush.yml,/opt/local/my_project_code/drupal/drush/drush.yml
 [preflight] Alias paths: /opt/local/my_project_code/drupal/web/drush/sites,/opt/local/my_project_code/drupal/drush/sites
 [preflight] Commandfile search paths: /opt/local/my_project_code/drupal/vendor/drush/drush/src,/opt/local/my_project_code/drupal/drush
 [bootstrap] Starting bootstrap to root [0.12 sec, 8.69 MB]

In BootstrapHook.php line 32:

  [Exception]
  Bootstrap failed. Run your command with -vvv for more information.

Exception trace:
  at /opt/local/my_project_code/drupal/vendor/drush/drush/src/Boot/BootstrapHook.php:32

 Drush\Boot\BootstrapHook->initialize() at /opt/local/my_project_code/drupal/vendor/consolidation/annotated-command/src/Hooks/Dispatchers/InitializeHookDispatcher.php:34

 Consolidation\AnnotatedCommand\Hooks\Dispatchers\InitializeHookDispatcher->callInitializeHook() at /opt/local/my_project_code/drupal/vendor/consolidation/annotated-command/src/Hooks/Dispatchers/InitializeHookDispatcher.php:27

 Consolidation\AnnotatedCommand\Hooks\Dispatchers\InitializeHookDispatcher->initialize() at /opt/local/my_project_code/drupal/vendor/consolidation/annotated-command/src/CommandProcessor.php:145

 Consolidation\AnnotatedCommand\CommandProcessor->initializeHook() at /opt/local/my_project_code/drupal/vendor/consolidation/annotated-command/src/AnnotatedCommand.php:289

 Consolidation\AnnotatedCommand\AnnotatedCommand->initialize() at /opt/local/my_project_code/drupal/vendor/symfony/console/Command/Command.php:221

 Symfony\Component\Console\Command\Command->run() at /opt/local/my_project_code/drupal/vendor/symfony/console/Application.php:1005

 Symfony\Component\Console\Application->doRunCommand() at /opt/local/my_project_code/drupal/vendor/symfony/console/Application.php:255

 Symfony\Component\Console\Application->doRun() at /opt/local/my_project_code/drupal/vendor/symfony/console/Application.php:148

 Symfony\Component\Console\Application->run() at /opt/local/my_project_code/drupal/vendor/drush/drush/src/Runtime/Runtime.php:118

 Drush\Runtime\Runtime->doRun() at /opt/local/my_project_code/drupal/vendor/drush/drush/src/Runtime/Runtime.php:49

 Drush\Runtime\Runtime->run() at /opt/local/my_project_code/drupal/vendor/drush/drush/drush.php:72

 require() at /opt/local/my_project_code/drupal/vendor/drush/drush/drush:4

site:install [--db-url DB-URL] [--db-prefix DB-PREFIX]
[--db-su DB-SU] [--db-su-pw DB-SU-PW]
[--account-name [ACCOUNT-NAME]] [--account-mail [ACCOUNT-MAIL]]
[--site-mail [SITE-MAIL]] [--account-pass ACCOUNT-PASS]
[--locale [LOCALE]] [--site-name [SITE-NAME]]
[--site-pass SITE-PASS] [--sites-subdir SITES-SUBDIR]
[--config-dir CONFIG-DIR] [--existing-config] [-h|--help]
[-q|--quiet] [-v|vv|vvv|--verbose] [-V|--version] [--ansi]
[--no-ansi] [-n|--no-interaction] [-d|--debug]
[-y|--yes] [--no]
[--remote-host REMOTE-HOST] [--remote-user REMOTE-USER]
[-r|--root ROOT] [-l|--uri URI] [--simulate] [--pipe]
[-D|--define DEFINE] [--notify] [--xh-link XH-LINK]
[--druplicon] [--] <command> [<profile>]...

```

# Answer
To people who end up here from July 2022

Composer changed its default behaviour when running in non-interactive mode and that will result in plugins not being installed.

That will result in the error on line 32 of bootstrap.php

To resolve this quickly you can manually run a composer install and approve all of the plugins.

To fix the build process you will need to do this and commit the `composer.json` with the approved plugins in.

This is a BC-breaking change (albeit an advertised one), currently, composer will not treat this as an error but this is being looked at
> 2 votes

# Answer
leymanxx:

Thank you friend for your questions. They led me to update the version spec for drupal/core (and drupal/core-dev) in my composer.json to read `"^8.8"` instead. After that I was able to run:

```
# rm -rf vendor/ web/

# composer update

# sudo -u jenkins /usr/local/drush/drush site-install \
    -y -vvv \
    --db-url='mysql://my_project_code_db_user_dev:a_somewhat_secret_db_password@localhost/my_project_code_db_dev' \
    --db-su=root --db-su-pw='my_very_secret_root_password' \
    --account-mail=site-admin@example.org \
    --account-name=admin \
    --account-pass=reallysecret \
    --site-name=efc9c26-00497.dev.my_project_code.example.org

# drush status
 Drupal version   : 8.9.2

<snip>

 Database         : Connected
 Drupal bootstrap : Successful

```

and to produce a working base installation of drupal! Updating that in my code and running this again through my build process to see if it flies. Thanks for prodding me with that question.
> 1 votes

---
Tags: drush, composer
---


title: How to properly log custom exceptions?

text:
# Question
Title: How to properly log custom exceptions?
I'm trying to improve the code quality of my custom module by adding custom exceptions. Before, I was lazy and throwing `\Exception` everywhere, but I recently refactored all my code to use custom exceptions.

In `mymodule/src/Exception`, I created MyModuleException:

```
class MyModuleException extends \Exception {
}

```

And then several additional exceptions such as MyModuleLogicException and MyModuleOutOfBoundsException, which extend MyModuleException.

Then I made an EventSubscriber to log the exceptions:

```
<?php

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\Http\Exception\CacheableAccessDeniedHttpException;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Webmozart\Assert\InvalidArgumentException;

/**
 * Event subscriber MyModuleExceptionSubscriber.
 */
class MyModuleExceptionSubscriber implements EventSubscriberInterface {

  /**
   * Implement with a priority higher than 50.
   *
   * Must run before Drupal\Core\EventSubscriber\ExceptionLoggingSubscriber.
   */
  const PRIORITY_HIGHER_THAN_50 = 60;

  /**
   * Logger factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected LoggerChannelFactoryInterface $logger;

  /**
   * MyModuleExceptionSubscriber constructor.
   *
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger
   *   The logger factory interface.
   */
  public function __construct(LoggerChannelFactoryInterface $logger) {
    $this->logger = $logger;
  }

  /**
   * Log my custom exceptions.
   *
   * @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
   *   The event to process.
   */
  public function onException(ExceptionEvent $event): void {
    $exception = $event
      ->getThrowable();

    if ($exception instanceof MyModuleException) {
      $this->logger->get('mymodule_exception')->error($this->getErrorMessage($exception));
      $response = new Response("Something bad happened!", 500);
      $event->setResponse($response);
    }
  }

  /**
   * {@inheritDoc}
   */
  public static function getSubscribedEvents(): array {
    $events = [];
    $events[KernelEvents::EXCEPTION][] = [
      'onException',
      self::PRIORITY_HIGHER_THAN_50,
    ];
    return $events;
  }

  /**
   * Generate a useful error message to log an exception.
   *
   * @param \Exception $exception
   *   The exception to generate an error message for.
   *
   * @return string
   *   The generated error message.
   */
  private function getErrorMessage(\Exception $exception): string {
    $exception_class = get_class($exception);
    return "Class: $exception_class <br>Message: " .
      $exception->getMessage() .
      "<br>File: " .
      $exception->getFile() .
      "<br>Line number: " .
      $exception->getLine() .
      "<br>Stack trace:<br>" .
      $exception->getTraceAsString();
  }

}

```

Then I ran some behat tests and triggered all the different types of exceptions.

What I found was that in most cases, the custom exceptions were logged correctly by my exception event subscriber.

However, for exceptions thrown from code running in a `hook_node_presave()` or `hook_node_insert()`, the logs show the exception as a standard **php** exception, so they are not getting picked up by my event subscriber:

> Drupal\Core\Entity\EntityStorageException: My custom exception message Drupal\Core\Entity\Sql\SqlContentEntityStorage-\>save() (line 811 of /app/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).

I think the problem is that the event subscriber is only seeing uncaught exceptions, and so my custom exceptions are getting caught in Drupal's entity saving logic and then getting rethrown as a generic PHP exception.

I implemented the exception event subscriber because I thought that would be a lot less code (put the logging logic in one place and handle all exceptions as they come in), since all my exceptions are fatal and don't need to be caught.

But, because of this, Drupal is catching the exceptions for me and replacing my custom exception messages with generic Drupal ones.

So the question is: **what's the best practice to ensure that I get a custom log message whenever one of my exceptions is thrown?** I could write a try/catch block for every exception and then put the logging logic in the catch block, but that seems like a lot of extra code. Is there a more elegant way to handle this?

# Answer
> 4 votes
If a try/catch block is implemented correctly and preserves the original exception like in the mentioned example of the entity save operation:

*SqlContentEntityStorage::save()*

```
  public function save(EntityInterface $entity) {
    $transaction = $this->database->startTransaction();
    try {
      ...
    }
    catch (\Exception $e) {
      $transaction->rollBack();
      ...
      throw new EntityStorageException($e->getMessage(), $e->getCode(), $e);
    }
  }

```

the originally thrown exception is stored as third parameter in the newly thrown exception.

Then your EventSubscriber can get the original exception by running getPrevious() recursively (in case the exception you've raised is nested in multiple try/catch blocks):

```
public function onException(ExceptionEvent $event) {
  $exception = $event->getThrowable();
  $original_exception = $exception;
  while ($original_exception->getPrevious()) {
    $original_exception = $original_exception->getPrevious();
  }
  if ($original_exception instanceof MyModuleException) {
    // your code logging the exception
  }
}

```

---
Tags: 9, log-messages
---


# Question
Title: Does deleting a content type also delete all nodes of that type?
I know I can delete all nodes of a content type, keeping the content type, through bulk operations or such. If I'm not interested in keeping the content type, can I just delete the content type itself and all nodes will be gone with it?

This is the message I see when hitting the delete link for a content type, on Drupal 7.58.

>

Translated from French, that is:

> \[Content type name\] is used by 3 pieces of content on your site. It could be impossible to display them or to modify them correctly if you delete the content type.

The displayed message does not lead me to think outright that the nodes will be deleted, just that I might not be able view or edit them.

# Answer
> 3 votes
The confirmation message that Drupal 7.58 shows in English is the following one, where *%type* is the content type name and *@count* the number of nodes.

> %type is used by @count pieces of content on your site. If you remove %type, you will not be able to edit the %type content and it may not display correctly.

Drupal 7.58 shows that warning, but it lets you delete the content type. What that warning says it's correct: Once the content type used by existing nodes is deleted, those nodes cannot be anymore deleted; they also won't display correctly, since the function that deletes a content type (`node_type_delete()`) deletes also the fields added to those nodes (with `field_attach_delete_bundle()`).

In Drupal 7.90, the latest Drupal 7 release available now, if you try to delete a content type for which there are nodes, Drupal won't allow you to delete it. It will tell you you need to first delete all the nodes of that content type.

For example, if I try to delete the *Basic Page* content type after I created a *Basic Page* node, instead of the confirmation form, Drupal will show me the following message (although the page title will be *Are you sure you want to delete the content type Basic page?*).

> Basic page is used by 1 piece of content on your site. You cannot remove this content type until you have removed all of the Basic page content.

>

Although Drupal 7.58 allows you to delete a content type for which there are nodes, it's preferable to first delete the existing nodes of the content type that is going to be deleted, following these steps.

* On admin/content, select the content type you want to delete in *type*
* Click on *Filter*
* The list at the bottom of the page will show only the nodes of that content type

>
* Click on the checkbox shown on the right of *Title*, in the header
* Select *Delete selected content* from *Update options* (from the list that shows *Publish selected content*)
* Click on the *Update button*

>

As side note, Drupal 7.58 isn't anymore secure. The following security issues has been fixed, in releases created after Drupal 7.58. (These are the last five fixed security issues.)

---
Tags: 7
---


# Question
Title: I cannot send HTML mail using "{{ node.body.value }}"
I use Drupal 9 and the Rules module to send emails when an *Article* node is updated.
I installed the *Mimemail* module and set the formatter to *mimemail*; all the field are correctly rendered. Only `{{ node.body.value }}` displays the HTML markup in the mail directly.

The rule settings are the following.

```
Hello, {{node.field_unit}} ！<br>
New Message Alert!<br>
<br>
id：{{ node.field_id }}<br>
mail：{{ node.field_mail }}<br>
type：{{ node.field_type }}<br>
time：{{ node.created }}<br>
subject：{{ node.title }}<br>
content：<br>
{{ node.body.value }}<br>

```

The received email is rendered like in this screenshot.

>

These are the value stored in the database.

>

I'm not sure how to solve this.

Could anyone help me?

# Answer
> 0 votes
Instead of `.value` use `.processed` to get the formatted output:

```
{{ node.body.processed }}

```

---
Tags: rules, 9, mimemail
---


# Question
Title: Correctly cache route by dynamic parameter
I have a route with an optional parameter like:

`/foo/bar/{baz}`

`{baz}` is optional.

When accessing that route by a value for baz, the page contents are correct, but the breadcrumb is incorrect and caches the first one that you visit. This makes the breadcrumb incorrect. These are paths that are accessible in the admin area only.

Is there a way to make the breadcrumb correct?

Edit: is the route cache wrong or the menu cache?

# Answer
In this case, you need to implement a custom breadcrumb, then add a cache context for the URL.

How to create a custom breadcrumb: https://www.drupal.org/node/2876622

Cache contexts: https://www.drupal.org/docs/drupal-apis/cache-api/cache-contexts

Or, you may be able to work something out with the Custom Menu Breadcrumbs module.
> 0 votes

---
Tags: routes, 9
---


# Question
Title: How to programmatically edit field settings of a content type
My ultimate goal is to use a drush command to change the allowed paragraphs in a paragraph entity reference field for various content types. I'm able to load the field entity and see the settings I need to change.

```
$field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('node', 'my_custom_content_type');
$field_definitions['two_column_accordion']['enabled'] = TRUE;

```

However I'm not sure how to actually change the settings and save it for the content type. getFieldDefinitions returns an array containing the information I need to change but what it returns isn't by reference so I'm not sure how I can save anything.

How can I edit the settings of an entity reference field programmatically?

# Answer
> 2 votes
I was able to perform the edit like so

```
$field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('node', 'custom_content_type');
      if(isset($field_definitions['field_content'])){
          $current_settings = $field_definitions['field_content']->get('settings');
          $current_settings['handler_settings']['target_bundles_drag_drop']['two_column_accordion']['enabled'] = TRUE;
          $field_definitions['field_content']->set('settings', $current_settings);
          $field_definitions['field_content']->save();
      }

```

Once I realized that $field\_definitions\['field\_name'\] was a FieldConfig object I was able to see that the 'get', 'set', and 'save' methods were what I needed.

---
Tags: entities, 9
---


# Question
Title: How to create a module which installs entity types from /config/install/….yml files?
I created lots of paragraphs which go with a theme. Everything works fine, and now I want to deploy this theme and the related paragraphs to several more sites. I exported the entity-types (node,paragraphs and fields) using the config manager UI. I then stripped the UUID from the .yml files and put them into modules/custom/MY\_MODULE/config/install. I then created the MY\_MODULE.info file.

```
name: fTheme
description: paragraph types for f theme
type: module
core_version_requirement: ^9
package: Custom
dependencies:
  - paragraphs:paragraphs

```

Now I'm stuck. I simply have no clue as what to put into MY\_MODULE.module to trigger the entity-type creation at install. Searching the web and reading three books didn't help. I'm using Drupal 9.4 and it seems there were lots of changes since 8.0 (which all my books are based on). Thanks in advance to point me to the proper spot (for dummies).

# Answer
> 1 votes
To let Drupal use the files in the config/install directory to create entities or configuration objects, you don't need any code in the module file, or even have a module file. You just need to have a .info.yml file (not a .info file); that is all Drupal needs to know that a directory contains a module and use those files to create entities / configuration objects.

That is true in Drupal 8, as well as Drupal 9.

As example of what a Drupal core module does, see the *Forum* module, which uses the content of its *config/optional* directory to create entities. Its `forum_install()` hook just creates the taxonomy term it used.

```
function forum_install($is_syncing) {
  // Set the weight of the forum.module to 1 so it is loaded after the taxonomy.module.
  module_set_weight('forum', 1);

  // Do not allow to delete the forum's node type machine name.
  $locked = \Drupal::state()
    ->get('node.type.locked');
  $locked['forum'] = 'forum';
  \Drupal::state()
    ->set('node.type.locked', $locked);
  if (!$is_syncing) {
    // Create a default forum so forum posts can be created.
    $term = Term::create([
      'name' => t('General discussion'),
      'description' => '',
      'parent' => [
        0,
      ],
      'vid' => 'forums',
      'forum_container' => 0,
    ]);
    $term->save();
  }
}

```

The difference between the *config/install* and the *config/optional* directories is explained in Optional configuration provided by modules and themes is now stored in config/optional.

---
Tags: paragraphs
---


title: Clone a node programmatically

text:
# Question
Title: Clone a node programmatically
I am modifying the node content on `hook_form_alter()` as follows.

```
  $node = \Drupal\node\Entity\Node::load($nid);
  if ($node) {
    $node->field_p_frontip = $availableip[0];
    $node->save();
  }

```

I need to clone the node and save it in the `hook_form_alter()` submission. How could I do this?

**UPDATE**

---

In **D6** the node was cloned using the function clone\_node\_save which uses the node id to clone as **`clone_node_save($nid,false);`**, what is the corresponding function in **D8** ??

# Answer
> 18 votes
In Drupal 8, any entity can be cloned using `EntityInterface::createDuplicate()`. So in the case of your node object: `$cloned_node = $node->createDuplicate()`. Calling `$cloned_node->save()` will save a new node with a different ID.

# Answer
> 3 votes
```
<!-- The below solution works for me. (Drupal - 9.4.1)
1. It perfectly clones all paragraphs.
2. It does not clone files.
3. It does not clone terms. -->

$nid = 17; // Example node id
$node = Node::load($nid);

if (is_object($node)) {
  $clonednode = $node->createDuplicate();
  // Loop over entity fields and duplicate nested paragraphs.
  foreach ($clonednode->getFields() as $field) {
    if ($field->getFieldDefinition()->getType() == 'entity_reference_revisions') {
      if ($field->getFieldDefinition()->getFieldStorageDefinition()->getSetting('target_type') == "paragraph") {
        $paragraphs = [];
        foreach ($field as $item) {
          $paragraphs[] = $item->entity->createDuplicate();
        }
        $fieldname = $field->getFieldDefinition()->getName();
        $clonednode->$fieldname =  $paragraphs;
      }
    }
  }

  $clonednode->changed->value = time();

  // Append cloned in the title.
  $clonednode->set('title', 'Cloned - ' . $node->getTitle());

  // Cloned node should be unpublished.
  $clonednode->set('status', 0);

  $clonednode->save();
}

```

---
Tags: nodes, 8
---


# Question
Title: How to change a text with one dynamic term in all nodes?
I have a core website, no contrib modules or themes are installed.

All my nodes, from several content types, start with the following text, which is written in WYSIWYG CKeditor.

> The term X is used to describe

I wish to change this everywhere to:

> X I describe as

How to change a text with one dynamic term in all nodes?

# Answer
> 1 votes
DOMDocument is not going to help here because ultimately this data lives within I assume a formatted text field (WYSIWYG). The best that will do is 'change' the sentence when rendering it, but not actually fix the problem underneath.

Unfortunately this requires one of two paths:

* You manually edit all the content to what you want.
* You run a MySQL Find and Replace query.

The latter is a destructive operation so make a backup before trying anything.

https://stackoverflow.com/questions/11839060/find-and-replace-text-in-the-entire-table-using-a-mysql-query

You are looking for the database table of the field in question (and its revision table too), which is what you will run the query against. Another problem that makes this really difficult is you want to replace a pattern, which requires regular expressions:

https://dev.mysql.com/doc/refman/8.0/en/regexp.html#function\_regexp-replace

This is still doable, if not a challenge. You'd need 3 capture groups (regex):

https://stackoverflow.com/questions/28592180/regexp-replace-capturing-groups

The regex may look something like this:

```
(?<subject>The term)\ (?<term>[A-Z0-9]+)\ (?<predicate>is used to describe)

```

Which the replace part *may be*

```
$term I describe as

```

None of this is strictly Drupal related.

In hindsight, this would probably be best solved as a migration plugin against that field where manipulation is a bit easier, safer and iterative than raw SQL queries.

---
Tags: database, 9
---


title: Alternative to field group module

text:
# Question
Title: Alternative to field group module
The field group module is currently not ready for Drupal 9. I would like to implement the same functionality for my forms. What other alternative module can I use that is compatible with Drupal 9, PHP 7.4, and MySQL 8?

# Answer
Field Group ***does*** work with Drupal 9. There is no alternative.
> 4 votes

---
Tags: 9
---


# Question
Title: Get proper ID from media entity for file loading purposes
I'm attempting to load the file attached to a media entity used in a field attached to a paragraph in order to create a url to the file.

```
    $vid = $paragraph->get($field_name)[0]?->entity?->toArray()['vid'][0]['value'];
    $media['desktop_mp4'] = File::load($vid)?->createFileUrl();

```

$paragraph-\>get($field\_name)\[0\]?-\>entity does give me a proper Media object, which does have properties like 'vid' and 'mid' but I'm not sure what to use when loading the file attached to it.

In an example case I know that the ID is supposed to be 18 but sometimes that comes from the vid and sometimes that comes from the mid. Even when using the same media in the same field type there doesn't seem to be any consistency as to where the proper fid can be found in the array returned by $paragraph-\>get($field\_name)\[0\]?-\>entity?-\>toArray();

What should I be using to the fid from a media entity?

# Answer
The issue was I wasn't thinking about using the actual field from the media object that contained the file. The IDs on the media object lining up with the files I needed might have been coincidences.

In order to get what I needed I used this

```
$video_file_url = $paragraph->get('field_video')[0]?->entity->field_media_video_file->entity->createFileUrl();

```
> 1 votes

---
Tags: media, 9
---


# Question
Title: Toggle (show or hide) visibility of content type field in view depending on relationship with other content type
I have a member content type that displays info about a company's member. One of the fields is named **member publications**, and it's a link to a blog view where the publications of the member (another content type) are displayed.

I want to show or hide the **member publications** field depending if the member has any publications.

I tried this using the **hook\_page\_attachments** using this snippet

```
function MYMODULE_page_attachments(array &$page) {
  //This line works the first time i open the node page, but not after is cached
  $entity = \Drupal::routeMatch()->getParameter('node');

  if( $entity !== null && $entity->bundle() == 'member'){

    $publications = Drupal::entityQuery('node')
      ->condition('type','publication')->condition('field_publication_author',$entity->id(),'IN')->execute();

    $numberOfPublications = sizeof($publications);

    if($numberOfPublications !== null){
      $page['#attached']['drupalSettings']['MYMODULE'] = [
        'memberPublications' => $numberOfPublications
      ];
    }
  }
}

```

And then i just show the field or not in js depending on the value attached

```
let memberPublications = settings.MYMODULE.memberPublications;

        if(memberPublications == 0){
          $('.field--name-field-member-publications').css('display','none');
        }

```

This works fine the first time i open the member node page, but when i remove all the members publications, the button still shows, the page gets cached and the value doesn't change, when i remove all cache if works again.

Is there a way to have a dynamic field inside a node, that appears or dissapears based in a condition that involves a relationship with another content type? And can it be done without having to reload the cache every time for it to work?

# Answer
The hook you are using is only for global attachments. If you have an attachment specific to nodes attach it to nodes:

```
/**
 * Implements hook_ENTITY_TYPE_view_alter() for node entities.
 */
function mymodule_node_view_alter(array &$build, EntityInterface $node, EntityViewDisplayInterface $display) {
  if ($build['#view_mode'] == 'full' && $node->bundle() == 'member') {
    ...
    $build['#attached']['drupalSettings']['MYMODULE'] = [
      'memberPublications' => $numberOfPublications,
    ];
    // add list tag for the content type publication
    $build['#cache']['tags'][] = 'node_list:publication';
  }
}

```

This solves most caching issues because nodes are already setup to be cached properly. In this case you need to add a cache tag for the other content type, though, to recalculate the entity query in case a publication is added or deleted.

There are of course other solutions without javascript, but this would be a too broad for an answer. So I'm focusing on why the solution you've found so far doesn't work.
> 0 votes

---
Tags: nodes, javascript, hooks, caching
---


# Question
Title: Is there a way to populate a form with dynamic values?
I might be missing the point of the form api, but I was wondering if I can somehow create a form and initialize it with dynamic values?

Here is what I'm trying to do:

**my\_module.module**

```
function my_module_preprocess_user(&$vars) {

     $sponsorshipsEligibleForPackagereceiving = SponsorshipUtils::getPackageSendEligableSponsorships((int) $vars['user']->get('uid')->getString());

     // this will call ConfirmDeliveryForm::buildForm straight - how can I pass sponsorshipsEligibleForPackagereceiving to it?
     $formRenderElements = Drupal::formBuilder()->getForm(ConfirmDeliveryForm::class, $state);

     $vars['handle_block'] = $formRenderElements;
}

```

Is there a way to initialise the ConfirmDeliveryForm with $sponsorshipsEligibleForPackagereceiving before the buildForm is used?

The form itself would then allow the user to modify stuff via the ajax callbacks.

Alternatively I could probably just initialize $sponsorshipsEligibleForPackagereceiving inside of ConfirmDeliveryForm::buildForm function with the currently logged in user?

Thx a lot for your help!

# Answer
A variable passed in formBuilder::getForm()

```
$form = Drupal::formBuilder()->getForm(ConfirmDeliveryForm::class, $extra);

```

is available in buildForm() as extra argument:

```
buildForm(array $form, FormStateInterface $form_state, $extra = NULL)

```

You need to set a default value for the extra argument, see How do I pass parameters to the form builder?
> 1 votes

---
Tags: forms, 9
---


title: Cache Form table size is enormous

text:
# Question
Title: Cache Form table size is enormous
Cache table's size had increased to 10+ GB last month, and I had fixed it temporarily by truncating it. Last time I checked it was around 1GB. So in couple of months it will hit 10GB again. How should this be dealt with ?

Note that I have disabled all cron jobs on this site. If this is the reason, which cron should be enabled ?

# Answer
> 24 votes
The `{cache_form}` table is a little funny, and behaves in a slightly different manner than other cache tables.

If you take a look at `drupal_flush_all_caches()` you will see that `{cache_form}` isn't cleared. This is to protect in-progress forms from being nuked.

The `system_cron()` function does take care of pruning out old data from `{cache_form}` along with the other cache tables.

You really should run cron on all Drupal sites. If you `{cache_form}` table is ginourmous, then I bet your `{watchdog}` and `{session}` tables are, too. Many other modules run housekeeping activity as part of their own `hook_cron()` functions.

You may also want to poke around the issue queue. There have been some bugs with `{cache_form}`, and you may be running into one.

# Answer
> 6 votes
> Thumb Rule: Cron should be run regularly for the housekeeping of your website.

You mentioned in your comment to MPD that in-spite of setting up the cron and running them regularly your cache\_form table is growing up quickly.

**One solution to that is to run your cron more frequently.** Say every six hours or lesser? If you cannot afford to do it read further.

**Alternate Solution :**

```
mymodule_cron() {
    cache_clear_all(NULL, 'cache_form');
}

```

Install Elysia Cron and now you can run the cron function of your module separately. You can keep the frequency of the Elysia cron for you module to run every six hours. So that your `cache_form` table is pruned every six hours.

During this pruning process the entries which are not older than 6 hours will not be deleted. The reason being, if all the entries are deleted then any forms which are being submitted at the time of deleting the entries can behave weirdly.

Look at the code in https://api.drupal.org/api/drupal/includes!form.inc/function/form\_set\_cache/7

```
function form_set_cache($form_build_id, $form, $form_state) {
  // 6 hours cache life time for forms should be plenty.
  $expire = 21600;

```

As the comment reads they are assuming it should be plenty and in your case it is becoming too plenty for you. So the trick is to either clear the cache\_form table more frequently and reduce the value of $expire to a lower value, if you want to clear the cache\_form entries more frequently than the default value of 6 six hours then you need to alter the TTL of the cache\_form entries.

You can do that by installing cacheboject and then implementing the `hook_cacheobject_presave` within which you can alter the TTL to may be 2 or 3 hours.

```
mymodule_cacheobject_presave()($object, $cid, $bin) {
  // Extend the expiry period for prototype forms used in ajax enabled forms.
  $cache_ttl = 1 ; // Change it to any number of hours
  if ($bin == 'cache_form') {
    $object->expire = REQUEST_TIME + $cache_ttl * 3600;
  }
}

```

One downside of this approach is if the forms are not submitted within 2 hours(the RTL value you set) the the form data can be lost and you might get some form expired issues.

# Answer
> 1 votes
As a workaround on this problem, I have created module https://www.drupal.org/project/session\_cache\_form

# Answer
> 1 votes
When I was having performance issues on a site I was working, I ran into this after I fixed caching. You can read the article here: https://thinktandem.io/blog/2017/11/22/debugging-with-new-relic-blazemeter-strace-more/

From my blog post, you can add a queue and cron setup, then use something like Elysia Cron to make it all work together well:

```
/**
 * Implements hook_cron_queue_info()
 */
function THE MODULE_cron_queue_info() {
  // Set up the worker queue.
  $queues['THE MODULE_queue'] = array(
    'worker callback' => 'THE MODULE_queue_process',
    'time' => 600,
  );
  return $queues;
}

/**
 * Implements hook_cron()
 */
function THE MODULE_cron() {
  // Load up our worker queue.
  $queue = DrupalQueue::get('THE MODULE_queue');

  // Set up the query for expired results.
  $sql = "SELECT cid FROM {cache_form} WHERE expire < :time";
  $query = db_query($sql, array(':time' => REQUEST_TIME));
  $results = $query->fetchAll(PDO::FETCH_ASSOC);

  // Split this into chunks for safety and speed.
  $chunks = array_chunk($results, 5000);
  foreach ($chunks as $chunk) {
    // Add the chunk to the queue worker.
    $queue->createItem($chunk);
  }
}

/**
 * Worker callback defined in hook_cron_queue_info().
 *
 * @param array $data
 *   The array of cids we want to delete.
 */
function THE MODULE_queue_process($data) {
  db_delete('cache_form')
    ->condition('cid', $data, 'IN')
    ->execute();
}

```

# Answer
> 1 votes
## Use the Safe cache\_form Clear module.

It will let you prune the table to a reasonable size first, then maintain it.

Excerpted summary from the project page:

> Safely remove a limited number of items from the cache\_form table.

Once the module is installed, first prune cache\_form: run `drush safe-cache-form-clear` until the table size stays consistent, indicating you've removed all records older than 6 hrs.

It will then continue running on cron.

This is the module documented for this purpose by Acquia for their subscribers. The Acquia documentation page provides good additional information.

# Answer
> 0 votes
the `cache_form` is configurable now in `settings.php`

You can add the following line to your settings.php file:

```
$conf['form_cache_expiration'] = 21600;

```

where the "21600" is the expiration time by minutes.

You can refer to the documentation at: https://www.drupal.org/node/2857751

---
Tags: database, caching
---


# Question
Title: Request does not reach controller after a few requests
I have a custom module for an online shop. Module's controller gets a product id which is sent by the user through a query string and puts it into the session. That is crucial for the shopping cart functionality.

Things are that, after clearing the cache, everything is ok, but after a few minutes/requests, the requests stop entering the controller. It seems like the response has been cached, even if:

* I have disabled the caches at admin/config/development/performance,
* I return '#cache' =\> \['max-age =\> 0\] within the render array returned by the controller and
* all responses come with the header "x-drupal-cache-max-age: 0 (Uncacheable)".

I also noticed that these errors usually come with the following apache error:

```
AH01070: Error parsing script headers

```

# Answer
If you want to disable the caching of a controller, use this method in your controller class:

```
  /**
   * @return int
   */
  public function getCacheMaxAge(): int {
    return 0;
  }

```
> 0 votes

---
Tags: caching, 9
---


# Question
Title: Can't uninstall fields that depend on a module incompatible with current version
I'm upgrading a site from Drupal 8 to 9. In its Drupal 8 version it used the field\_collection module. There are some fields that still exist in some ghostly manner, that depend on the field\_collection module. How can I get rid of these fields? The usual advice is to reinstall the missing module but I cannot reinstall field\_collection as it is not compatible with Drupal 9.

Here's what I see on the status page:

```
Mismatched entity and/or field definitions
The following changes were detected in the entity type and field definitions.
Content
The node.field_committee_with_position field needs to be uninstalled.
The node.field_councillor_with_pos field needs to be uninstalled.
The node.field_meeting_timetable field needs to be uninstalled.

```

What I've tried:

1. Running cron (has no effect)
2. Trying to delete the fields using drush

```
drush config:delete field.field.node.field_committee_with_position
 [error]  Config field.field.node.field_committee_with_position does not exist

```

(This was confirmed by doing an config export and seeing that no yaml files were created for those fields)

3. Installing the devel\_entity\_updates module and then running `dentup`:

```
$ drush dentup
The following updates are pending:

node entity type :
The node.field_committee_with_position field needs to be uninstalled.
The node.field_councillor_with_pos field needs to be uninstalled.
The node.field_meeting_timetable field needs to be uninstalled.

 Do you wish to run all pending updates? (yes/no) [yes]:
 > yes

```

But after pressing Enter I get an error message which begins:

```
The "field_item:field_collection" plugin does not exist.

```

This is a dev site and I'm confident with running SQL commands so if there's a way I can just blitz these fields out of the database please let me know.

# Answer
> 0 votes
I had a similar issue where we removed a module, yet fields remained. The only solution that I found was to do the following:

1. Open the DB in a DB management tool (I preferred a tool with GUI)
2. Delete the node.field\_name table
3. Delete the node.revision\_field\_name table
4. Go to the config table, find the row related to field\_name and delete it
5. Delete all cache related tables
6. Clear the cache again, just in case (I guess you can do only one of the two steps - 5 or 6)

* Make a backup of your DB before attempting
* Change field\_name with the field that you want to remove

Hope it helps. Best of luck!

---
Tags: entities, 9, upgrading
---


# Question
Title: How should I remove nodes from database for which the content type was deleted on Drupal 7.58?
On Drupal 7.58, I deleted a content type for which thousands of nodes existed. On this version of Drupal, deleting the content type is allowed even if nodes still exist (see Does deleting a content type also delete all nodes of that type?)

How should I proceed to clean my database and remove any nodes of that content type?

Would it be safe to do something along the lines of:

```
SELECT * from node WHERE type = "content_type_name"

```

and use all the node ids (nid) from that query to delete rows from `node_counter`, `node_comment_statistics`, `node_access` and `node_revision`? And then delete the rows from `node`?

# Answer
The easiest thing to do would probably be:

1. Create the content type you deleted, the important part here is to give it same machine name as before, this will make the old nodes that exist in the database be picked up as this new node type.
2. Clear cache (to ensure that everything gets reset)
3. Delete the nodes, depending on your system, you might want to use a batch job, or the content list to simply delete them, by code you can:

```
$nids = db_query("SELECT nid form {node} where type = 'the-type';")
  ->fetchAllKeyed(0, 0);
if ($nids) {
  node_delete_multiple($nids);
}

```
4. Delete the node type after clean up is done.

Your idea is basically what needs to be done, but you will be missing related data, like taxonomy\_index storing all tags for a node and potential other modules storing data for nodes.

Please note, the idea is not battle tested, but I believe I have done something like this before once or twice in the past.
> 2 votes

---
Tags: 7
---


# Question
Title: How do I fix the Drush error "SQLSTATE[HY000] [2002] No such file or directory"?
I just updated my macos' php version using homebrew. This worked, the php version I'm currently running is 8.0.2

But doing this my Drush stopped working. When running `drush cr` I get the following error:

```
In Connection.php line 189:
SQLSTATE[HY000] [2002] No such file or directory

```

I tried several suggestions mentioned here: I've got \`PDOException: SQLSTATE\[HY000\] \[2002\] No such file or directory\` when using drush

The highest voted answer:

```
sudo mkdir /var/mysql
sudo ln -s /Applications/MAMP/tmp/mysql/mysql.sock /var/mysql/mysql.sock

```

Gives me the following feedback:

```
mkdir: /var/mysql: File exists
ln: /var/mysql/mysql.sock: File exists

```

When I then run `mysql_config --socket` I get `/Applications/MAMP/tmp/mysql/mysql.sock`  as return.

I also tried changing the `.zprofile` on my computer. I added:

```
export PATH=/Applications/MAMP/bin/php/php8.0.2/bin:$PATH

```

and

```
export DRUSH_PHP="/Applications/MAMP/bin/php/php8.0.2/bin/php"

```

But, as you might see, I don't really know what I'm doing and why. Can someone help me get Drush working again? I'm working on Drupal 9 websites using Drush 11 (drush -v is working).

# Answer
Use `127.0.0.1` instead of `localhost` in the database connection configuration.
> 5 votes

---
Tags: drush, 9
---


# Question
Title: How to add a top-level link to the Admin menu via the links.menu and routing yaml's
Let's say I want to add an additional link to the admin toolbar after Reports such as Groups does.

In my\_module.routing.yml I have:

```
my_module.admin:
  path: '/admin/my_module'
  defaults:
    _controller: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage'
    _title: 'My Module Stuff'
  requirements:
    _permission: 'access administration pages'

```

In my\_module.links.menu.yml I have:

```
my_module.admin:
  title: My Link
  route_name: 'my_module.admin'
  parent: 'system.admin'
  description: 'Stuff my link does'
  weight: 8

```

I took these from the corresponding Groups module. When I clear cache, nothing new shows up in the admin toolbar or the admin menu UI settings.

# Answer
This does actually work. I created a brand new module and copied your code into those files and it worked - I got the My Link menu appearing in the admin toolbar. I can only think that you don't have the correct permissions for the user you were testing with or that you didn't do a full cache clear (`drush cr`).
> 1 votes

---
Tags: routes, navigation, 9
---