# Question
Title: How do I mimic Pathauto transliterated output for an alias in my custom PHP code?
When writing my custom function I need to manually append node name to a taxonomy term link. To get the taxonomy term part done I use:

```
  $link_uri = taxonomy_term_uri($term);
  $path_alias = drupal_get_path_alias($link_uri['path']);

```

This works ok, now - I want to append node name ("/" . $node\_name), but instead of raw string, I want the Pathauto transliterated output, as set in the URL alias configuration, for that node context.

What function should I use to mimic that output? I looked at `hook_pathauto_alias_alter(&$alias, array $context)` but I'm not sure that's what I need.

# Answer
If you want to filter your string the way pathauto does it, you can use `pathauto_cleanstring()`:

```
module_load_include('inc', 'pathauto', 'pathauto');
$node_title .= pathauto_cleanstring($node->title);

```
> 4 votes

# Answer
On Drupal 8/9, you can use the Pathauto Alias Cleaner service :

```
/** @var Drupal\pathauto\AliasCleaner $cleaner */
$cleaner = \Drupal::service('pathauto.alias_cleaner');
$cleaner->cleanString($node->getTitle());

```
> 0 votes

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


# Question
Title: What's the point of using Webform Node instead of directly using a Webform's form?
What's the point of using Webform Node instead of directly using a Webform's form?

I have tried both. I see that submissions on a node are not exactly the same as submissions on the direct form, so there's a potential for submissions to get split. If I want people to use the node, but someone finds the direct form, then that can be confusing for people needing to review all submissions.

Is it ok to just use the direct form? Is there any advantage to using a node instead?

# Answer
This is a high-level answer. The default is to use the form itself. Only use the node if doing so makes it easier for your site's needs.

Why use a node?

Sometimes you want access to node features-- node fields in addition to webform fields (such as media reference fields to insert images), revisioning for the "content" part of the node on the webform page, metatags that follow the node rules on your site (although metatag webform module now addresses this for pure webforms as well), and so on.

But if you don't know that you need nodes for some reason, just keep using the webforms directly.
> 4 votes

# Answer
Under the hood, when you place a webform field under a Node (or any entity really) and make a submission through that entity, the entity is recorded in the submission. If you look at the `webform_submission` table, two columns are used to track this: `entity_type` and `entity_id`. These two columns are available as relationship points in Views, tying `Webform <- Webform Submission -> Node`. The webform field is also a special extension of the entity reference field, allowing an entity to reference a webform - also available as a relationship in Views.

With this setup, you can make complex relationship chains in Views that allow you to list and filter down forms/submissions in various ways:

* Filter submissions by Node.
    + A-B test which page made the form more effective.
* Filter Forms by Node.
    + If a user has "preferred topics", and Form Nodes have said topics, you can create a list of Forms based on those topics.
    + `Webform <- Submission -> Node -> Taxonomy Terms <- User`
* Filter Forms/Submissions by another entity related to a Node.
    + Only allow access to forms that are assigned to a Group.
    + `Webform <- Submission -> Node <- Group Content -> Group`

> If I want people to use the node, but someone finds the direct form, then that can be confusing for people needing to review all submissions.

You can disable direct form access in the webform config. I typically disable direct form access if I place forms on entities.
> 1 votes

---
Tags: webforms
---


# Question
Title: How to add some content every Nth comment?
My use is case is that I wish to show an advert every 3rd comment.

The forum module added the comment field to the forum content type. So the field name is comment\_forum.

I have a block that contains the embed code for the ads. Using twig\_tweak module to render that block in my template using `{{ drupal_entity('block_content', '5') }}`

I then created a template file called field--comment-forum.html.twig.

So far I have this:

```
{%
  set classes = [
    'field',
    'field--name-' ~ field_name|clean_class,
    'field--type-' ~ field_type|clean_class,
    'field--label-' ~ label_display,
    'comment-wrapper',
  ]
%}
{%
  set title_classes = [
    'title',
    'comment-title-main',
    label_display == 'visually_hidden' ? 'visually-hidden',
  ]
%}

{% if comments and not label_hidden %}

  <div class="my-5 col-print-12" id="comment-container">
    <section{{ attributes.addclass(classes) }}>
      {{ title_prefix }}
      <h2{{ title_attributes.addClass(title_classes) }} {{ attributes.setAttribute('id', 'comments') }}>{{ label }}</h2>
      {{ title_suffix }}

          {% set pre_render = comments['#pre_render'] %}
            {% for key, item in comments if key|first != '#'%}
                {% if key != 'pager' %}
                    {% set item = { '#pre_render': pre_render, 0: item } %}
                    {% if loop.index0 is divisible by(3) %}
                        {{ item }}
                        <div class="ads">{{ drupal_entity('block_content', '5') }}</div>
                    {% else %}
                        {{ item }}
                    {% endif %}
                {% else %}
                  <div class="comment-pager">{{ item }}</div>
                {% endif %}
          {% endfor %}
    </section>
  </div>
{% endif %}

{% if comment_form %}
  <div class="container">
  <div class="row justify-content-md-center">
    <div class="col col-md-8 p-2 p-md-4 my-5 bg-light rounded comment-new-container d-print-none">
      <h2 class="title comment-form__title comment-new-title">{{ 'Add new comment'|t }}</h2>
      {{ comment_form }}
    </div>
  </div>
</div>
{% endif %}

```

This works, as in the block with the ads are shown every 3rd comment. However it messes up the markup.

Without the template the markup for a comment with replies is this:

This is the markup for the same comments with the above template:

I also notice the `comments_ajax_pager_wrap` container div is also not included either. That's added by the comments\_ajax\_pager module.

This is my first Drupal 9 website. So I'm new to twig, any ideas? I feel like I may even be in the wrong template?

# Answer
A week later and I changed tact completely. I questioned if it would be possible to work with comment.html.twig instead of the field template.

So in my MY\_THEME.theme file I pass the comments weight to the template, like this:

**Updated thanks to @mrweiner's help in the comments**

```
/**
 * Implements hook_preprocess_comment().
 */
function MY_THEME_preprocess_comment(&$variables) {
    /** @var \Drupal\comment\CommentInterface $comment */
    $comment = $variables['elements']['#comment'];
    $node = $comment->getCommentedEntity();
    $cid = $comment->id();
    $entity_manager = \Drupal::entityTypeManager();
    try {

        // Load comments for the node
        /** @var \Drupal\comment\CommentStorageInterface $storage */
        $storage = $entity_manager->getStorage('comment');
        if ($node->hasField('comment_forum')) {
            /** @var \Drupal\comment\CommentFieldItemList $comment_field */
            $comment_field = $node->get('comment_forum');
        } elseif ($node->hasField('field_comments')) {
            /** @var \Drupal\comment\CommentFieldItemList $comment_field */
            $comment_field = $node->get('field_comments');
        }
        $comments = $storage->loadThread($node, $comment_field->getFieldDefinition()->getName(), \Drupal\comment\CommentManagerInterface::COMMENT_MODE_FLAT);

        // Ensure there are comments
        if (empty($comments)){
          return;
        }

       $comment_index = array_key_first(array_filter(array_values($comments), fn ($this_comment) => $this_comment->id() === $comment->id()));
       $weight = $comment_index + 1;
       $variables['displayAds'] = $weight % 3 === 0;

      } catch (\Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException $e) {
      } catch (\Drupal\Component\Plugin\Exception\PluginNotFoundException $e) {
      }
}

```

After implementing that hook I simply added this to comment.html.twig where I wanted my block to appear:

```
{% if displayAds %}
       <div class="comment-ads">{{ drupal_entity('block_content', '5') }}</div>
{% endif %}

```
> 0 votes

# Answer
Seems like you've already got it working from our comments in your other answer (which you can probably just mark as accepted if you're using the approach), but just for your own reference, here's how you might be able to fix your field template approach.

Per your comment mentioning that your initial implementation in the field template was breaking comment\_reply\_count module, I think it's because of your structure. If you look at https://git.drupalcode.org/project/comment\_reply\_count/-/blob/8.x-1.x/js/comment\_reply\_count.js, it relies on `$(this).parents('article.comment').next().slideToggle();`. This line tries to toggle the element directly after article.comment, which is normally `<div class="indented">`. Since you're rendering your ad div *after* the comment, I'd wager that it's trying to toggle that instead.

To maintain the functionality, I think you'd need to:

1. Determine whether a given comment is a parent comment or a child/indented comment. Comments keep track of this on the `pid` value, which stands for Parent ID. If the PID is empty, it's a parent comment. Comments have a `hasParent()` method that checks this.
2. If it is a parent, then render the ad *before* the comment if it is divisible by 3 (or 4, or whatever).

```
            {% set parent_comment_counter = 0 %}
            {% for key, item in comments if key|first != '#'%}
                {% if key != 'pager' %}

                    {% if not item['#comment'].hasParent() %}
                      {% set parent_comment_counter = top_level_comment_counter + 1 %}
                      {% if top_level_comment_counter is divisible by(3) %}
                        <div class="ads">{{ drupal_entity('block_content', '5') }}</div>
                      {% endif %}
                    {% endif %}

                    {% set item = { '#pre_render': pre_render, 0: item } %}
                    {{ item }}
                {% else %}
                  <div class="comment-pager">{{ item }}</div>
                {% endif %}
          {% endfor %}

```

If you wanted to do this in preprocess instead, you could do something like

```
hook_preprocess_field__comment_forum(&$variables) {
  $parent_comment_counter = 0;

  foreach($variables['comments'] as $k => $comment_item) {
    if(!is_array($comment_item) || !isset($comment['#comment'])) {
      continue;
    }

    $variables[$k]['show_ad'] = false;

    /** @var Drupal\comment\Entity\CommentInterface $comment_entity */
    $comment_entity = $comment['#comment'];
    if($comment_entity->hasParent()) {
      continue;
    }

    $parent_comment_counter += 1;
    $variables[$k]['show_ad'] = $parent_comment_counter % 3 === 0;
  }
}

```

in which case your template could then look like

```
            {% set parent_comment_counter = 0 %}
            {% for key, item in comments if key|first != '#'%}
                {% if key != 'pager' %}

                    {% if item.show_ad %}
                        <div class="ads">{{ drupal_entity('block_content', '5') }}</div>
                    {% endif %}

                    {% set item = { '#pre_render': pre_render, 0: item } %}
                    {{ item }}
                {% else %}
                  <div class="comment-pager">{{ item }}</div>
                {% endif %}
          {% endfor %}

```

That's the gist of it. You'd need to modify it if you wanted to include the ad around indented comments to ensure that you aren't including the ad block above the first indented comment after a parent, as that would break it in the same way as before.

I'm not sure exactly why `<div class="comments_ajax_pager_wrap">` was disappearing, though. That wrapper is added by comment\_ajax\_pager\_entity\_display\_build\_alter(), so maybe you could debug from there.
> 1 votes

# Answer
This is EASY-PEASY!

I already build this in some of my previous projects.

In your template file **field--comment-forum.html.twig**, you can iterate over the comments using a loop and a counter variable that keeps track of the comment number. You can use the **loop.index** variable provided by Twig to get the current iteration index.

```
{% set counter = 0 %}
{% for comment in comments %}
  {% set counter = counter + 1 %}
  {# Display the comment content #}
  {{ comment.content }}
  {# Display the ad after every 3rd comment #}
  {% if counter % 3 == 0 %}
    {{ drupal_entity('block_content', '5') }}
  {% endif %}
{% endfor %}

```

I hope this help!
> 0 votes

---
Tags: theming, 9, comments
---


title: Add a text field value with AJAX

text:
# Question
Title: Add a text field value with AJAX
Problem: After an AJAX callback, the text is not inserted in the body field.

Description: I created a fresh Drupal installation. Added a field 'Type' | field\_type | List (text) to the Article CT. The goal was that a change in that select would add text to the body field. Here's the ajax\_test.module code, inspired by the documentation:

```

use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_form_alter()
 */
function ajax_test_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if ($form_id === 'node_article_form') {

    $form['body']['#prefix'] = '<div id="edit-body-wrapper">';
    $form['body']['#suffix'] = '</div>';

    $form['field_type']['widget']['#ajax'] = [
      'callback' => 'myAjaxCallback',
      'disable-refocus' => FALSE,
      'event' => 'change',
      'wrapper' => 'edit-body-wrapper',
      'progress' => [
          'type' => 'throbber',
          'message' => t('Updating'),
      ],
    ];
  }
  // Outside the AJAX callback, the default_value works
  // $form["body"]["widget"][0]["#default_value"] = 'test';
}

function myAjaxCallback(array &$form, FormStateInterface $form_state) {
  if ($selectedValue = $form_state->getValue('field_type')) {
    $form["body"]["widget"][0]["#default_value"] = 'test';
    // Here it won't
  }
  return $form['body'];
}

```

If I set the default\_value without the AJAX, it appears correctly. Using Xdebug, I can see that the callback is updating the value correctly, but nothing appears in the body on completion.

Any suggestions would be very appreciated.

# Answer
> 0 votes
I finally found out a solution here: AJAX form - replacing #default\_value not working (the '2021 edit...') In this specific case, the callback would work:

```
function myAjaxCallback(array &$form, FormStateInterface $form_state) {
if ($selectedValue = $form_state->getValue('field_type')) {
    $userInput = $form_state->getUserInput();
    unset($userInput["body"]);
    $form_state->setUserInput($userInput);
    $form["body"]["widget"][0]["#default_value"] = 'test';
  }

```

---
Tags: ajax
---


# Question
Title: I've just installed drush and am getting this error. What to do?
So I've just installed drush 11.2.0 with Drupal 9.4.6 and the first time I executed `drush si`, I got this error.

> PHP Fatal error: Declaration of Drush\Application::setLogger(Psr\Log\LoggerInterface $logger) must be compatible with Psr\Log\LoggerAwareInterface::setLogger(Psr\Log\LoggerInterface $logger): void in /app/vendor/drush/drush/src/Application.php on line 22

What can I do to fix this issue?

If it matters, I am using Lando.

# Answer
I faced the issue too.

It seems that it's caused by the difference between the version of the `psr/log` package you have in your project and the one in the global vendor of your computer. I explain.

On Drupal 9.4, the dependency version for `psr/log` is `~1.1.4`. When you install Drush globally on your machine with Composer, it'll install `psr/log` on version `3.0.0`. And if you look at this MR (https://github.com/php-fig/log/pull/77) of `psr/log` package, you'll see that the signature of the function changed on the last version so it throws the exception.

The solution is to use an alias for drush binary directly from the project's dependencies, waiting for Drupal 10 and its updated dependencies.

Hope it answers your issue !
> 2 votes

# Answer
This issue also caught me. But none of the solutions worked for me. I was using global drush for all my projects, I finally uninstalled drush globally and installed it per project. In combination with DirEnv. Now everything is smooth!
> 1 votes

# Answer
You could also pin the Drush version in the composer.json by doing the following,

1. Open your composer.json file.
2. In the required section add or change "drush/drush": "^10.0".
3. From the terminal run "composer update".
> 1 votes

# Answer
The solution is: go to your global composer.json and add

```
"psr/log": "~1.1"

```

then run `composer global update -W`
> 0 votes

---
Tags: drush, 9
---


# Question
Title: Check in buildForm method of custom form class if the form was submitted
I have created a large form with a class extending `FormBase`. Many of the elements rendered within the form are only necessary for the user to see - there are not so many really relevant fields in the form but all this data gathering and rendering takes time.

When a form is submitted the `buildForm()` method is called first and after that the `submitForm()` method. Then the buildForm() method gets called again which then is really used to render the form for the user.

I now wonder if it is possible to check within the `buildForm()` method if it is called during the first run before `submitForm()` or if it is used during the second run to actually render it.

`FormState->isSubmitted()` does not do the trick - this is false on buildForm() on the first run.

# Answer
> 1 votes
The form is submitted when there is user input:

```
public function buildForm(array $form, FormStateInterface $form_state) {
  if ($form_state->getUserInput()) {
    // The form was submitted.
    // Build a minimal $form containing only the necessary form elements
    // to submit the user input.
  }
}

```

BTW, buildForm() can be called again, in the same request, if a submit handler causes a form rebuild or in Ajax forms. The user input is processed, $form\_state-\>getValues() and $form\_state-\>getTriggeringElement() are filled with data and can then be used to build a different version of the form.

If the form is not rebuilding it redirects by default to the same URL and builds a new empty form. If this takes too long and the user probably doesn't want to submit the form again, you can change this default behavior and set a different URL.

For example, redirect to the homepage and set a message:

```
public function submitForm(array &$form, FormStateInterface $form_state) {
  $this->messenger()->addStatus($this->t('The form has been submitted.'));
  $form_state->setRedirect('<front>');
}

```

---
Tags: forms
---


# Question
Title: I need help migrating a mulit-value link field from string w/ 2 delimiters
I'm trying to migrate a node bundle from one drupal 9 application to another.

My source format is an XML document.

I'm stuck migrating a multi-value link field.

Both the source and destination machine names are field\_quicklinks.

The source value is a string with two delimiters like the following.

```
"https://www.somedomain.org/somewhere/something.pdf*Something Document^https://www.someotherdomain.org/somewhere-else/some-other-document.pdf*Some Other Document^https://www.yetsomeotherdomain.org/yet-somewhere-else/yet-another-document.pdf*Yet Another Document"

```

So my intent is to explode this twice to look like:

```
[
  [
    "https://www.somedomain.org/somewhere/something.pdf",
    "Something Document"
  ],
  [
    "https://www.someotherdomain.org/somewhere-else/some-other-document.pdf",
    "Some Other Document"
  ],
  [
    "https://www.yetsomeotherdomain.org/yet-somewhere-else/yet-another-document.pdf",
    "Yet Another Document"
  ]
]

```

The latest iteration of my attmpts looks like:

```
field_quicklinks:
    -
      plugin: skip_on_value
      method: process
      value: FIELD_EMPTY
      source: field_quicklinks
    -
      plugin: explode
      source: field_quicklinks
      delimiter: '^'
    -
      plugin: multiple_values
      source: field_quicklinks
    -
      plugin: explode
      source: field_quicklinks
      delimiter: '*'
    -
      plugin: sub_process
      source: field_quicklinks
        process:
          field_quicklinks/uri:
              plugin: callback
              source: field_quicklinks
              callable: array_shift
    -
      plugin: sub_process
      source: field_quicklinks
      process:
        field_quicklinks/title:
            plugin: callback
            source: field_quicklinks
            callable: array_pop

```

If somebody could get me on track I would of course appreciate it very much.

# Answer
So I'm betting there's an existing way to accomplish this but I was spending way too much time on it and decided to create a custom process plugin.

The relevant part of my migration yaml looks like:

```
field_quicklinks_array:
    -
      plugin: skip_on_value
      method: process
      value: FIELD_EMPTY
      source: field_quicklinks
    -
      plugin: str_with_two_delimiters
field_quicklinks:
    plugin: sub_process
    source: '@field_quicklinks_array'
    process:
      uri: uri
      title: title

```

My custom process plugin which I placed here:

```
web/modules/custom/my_bundle_migration/src/Plugin/migrate/process/ParseStringWithTwoDelimiters.php

```

looks like:

```
<?php

  namespace Drupal\my_bundle_migration\Plugin\migrate\process;

  use Drupal\migrate\ProcessPluginBase;
  use Drupal\migrate\MigrateException;
  use Drupal\migrate\MigrateExecutableInterface;
  use Drupal\migrate\Row;
  /**
   * This plugin converts a string with two delimiters into an array of arrays
   *
   * @MigrateProcessPlugin(
   *   id = "str_with_two_delimiters"
   * )
   */
   class ParseStringWithTwoDelimiters extends ProcessPluginBase {
     /**
      * {@inheritdoc}
      */
      public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
        $prelim_results_array = [];
        $final_results_array = [];
        $array_one = explode("^",$value);
        foreach ($array_one as $element) {
          array_push($prelim_results_array,explode("*",$element));
        }
        foreach($prelim_results_array as $v){
          array_push($final_results_array,['uri' => $v[0], 'title' => $v[1]]);
        }

        return $final_results_array;

      }

   }

```
> 2 votes

---
Tags: 9, migrations
---


# Question
Title: How to skip empty and missing values from a migration
I'm trying to skip fields that are not present in my source file or that are empty, but I keep getting "*Migration failed with source plugin exception: Passed variable is not an array or object*"

This is what I've tried in YML:

```
field_contact:
    -
      plugin: skip_on_empty
      method: process
      source: contact_array
    -
      plugin: sub_process
      source: contact_array
      process:
        target_id:
          plugin: migration_lookup
          migration: import_contact_json
          source: Name

```

and

```
field_point_of_contact:
    plugin: sub_process
    source: contact_array
    process:
      target_id:
        -
          plugin: skip_on_empty
          method: process
          source: name
        -
          plugin: migration_lookup
          migration: registry_import_pocs_json
          source: Name

```

Both of them have the same output (i.e. the error described above).

Can someone point me in the right direction, please?

# Answer
I have currently able resolve the issue with this work around.

**Combination One is source for paragraph value set 1.**

**Combination Two is source for paragraph value set 2.**

**field\_section\_two** is paragraph entity reference multi value field.

Migration Look Up Will return array in this format \[ 0 =\> , 1 =\> \] this will not considered as empty on skip\_on\_empty plugin , so passing array\_filter plugin to skip the process to avoid exception.

```
combination_1:
    -
      plugin: skip_on_empty
      source: image_1
      method: process
    -
      plugin: migration_lookup
      migration: product_image_inset_one
      no_stub: true
      source:
        - ID
        - image_1
  combination_2:
    -
      plugin: skip_on_empty
      source: image_2
      method: process
    -
      plugin: migration_lookup
      migration: product_image_inset_two
      no_stub: true
      source:
        - ID
        - image_2
  field_section_two:
    -
      plugin: callback
      callable: array_filter
      source:
        - '@combination_1'
        - '@combination_2'
    -
      plugin: skip_on_empty
      method: process
    -
      plugin: sub_process
      source:
        - '@combination_1'
        - '@combination_2'
      process:
          target_id: '0'
          target_revision_id: '1'

```
> 1 votes

# Answer
It is difficult to help without seeing the structure of your source file (at least 1 sample record). But, here are some pointers:

* At first glance, the error message says something about a *source plugin exception*. I believe the error might be stemming from the source plugin configuration.
* The approach you are taking with *skip on empty* seems to be in the correct direction.
* Depending on the data that the field contains, you might have to handle it differently. I usually add the following to debug exactly what is being received by a particular field process. Also, make sure that the value being sent to the `migrate_lookup` plugin is an array.

```
# ...
process:
  field_point_of_contact:
    - plugin: callback
      callable: print_r
      source: name
# ...

```
* Have you tried removing the *skip on empty* part? I don't remember correctly, but migrate lookup might be skipping empty values by itself.
* An array with empty strings is not considered *empty*. If your source provides values like `['']`, you might have to send the array through an `array_filter()` to remove empties.

I hope this helps. If it doesn't, you might want to share one row of fake data.
> 0 votes

# Answer
I've promised I'll come back when this is solved, but it took a while :) Thank you everyone for helping out. It turned out the issue was the fact that "migration\_dependencies" was set to "required", so any missing data in the source file was firing that exception. After hours of pulling my hair out, the fix was to change migration\_dependencies to "optional" And no skip\_on\_empty is needed in this case.
> 0 votes

# Answer
Setting migration\_dependencies to optional resolved this issue for me. I was trying all the skips and custom processes only to realize my very simple error and resolution.
> 0 votes

---
Tags: 8, migrations
---


# Question
Title: Remove the X-generator header from the response
I want to remove the CMS type and version disclosure , which Drupal is returning in the *X-Generator:Drupal 8 (https://www.drupal.org)* header.

I am using the following code, but it removes the x-generator header, but I can still see *X-Generator:Drupal 8 (https://www.drupal.org)* in the browser header response.

```
function xxx_page_attachments_alter(&$data, &$context1 = NULL, &$context2 = NULL) {
    foreach ($data['#attached']['html_head'] as $key => $attachment) {
        if ($attachment[1] == 'system_meta_generator') {
          unset($data['#attached']['html_head'][$key]);
        }
    }
}

```

How can I fix my code?

# Answer
The simplest method is to remove the header in a custom EventSubscriber:

```
$response->headers->remove('X-Generator');

```

See https://drupal.stackexchange.com/a/201297/47547 for an example.
> 5 votes

# Answer
It's not exactly the question you are asking, but...

I wrote a detailed answer to the idea of How can I obscure what I am using to run my site? Adding it as an answer here in case it's useful to you as you consider working on this problem.
> 0 votes

# Answer
Please check below link, Created custom module to do that.

@https://github.com/vikrantrc/Remove-X-Generator
> 0 votes

# Answer
@gaurav should also be working. For me it seems to work

```
function THEMENAME_page_attachments_alter(&$data) {
  foreach ($data['#attached']['html_head'] as $key => $attachment) {
    if ($attachment[1] == 'system_meta_generator') {
      unset($data['#attached']['html_head'][$key]);
    }
  }
}

```
> 0 votes

# Answer
The easiest way to do this is to remove the `response_generator_subscriber` service responsible for adding `X-Generator` in the first place. It's all it does so nothing (other than Core's tests) should depend on it.

Simply drop in a `Drupal\Core\DependencyInjection\ServiceProviderInterface` implementation into your module like this:

`my_module/src/MyModuleServiceProvider.php:`

```
<?php

namespace Drupal\ws_main;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;

/**
 * Remove the service adding the X-Generator header.
 */
class MyModuleServiceProvider extends ServiceProviderBase {

  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container) {
    $container->removeDefinition('response_generator_subscriber');
  }

}

```

Important to note is that the class (and filename) must be a CamelCased version of your module's machine name (First character capitalized, remove any underscore and capitalize the next character) as noted in the documentation on altering services. After clearing the cache - rebuilding the service registry - there should even be a tiny performance gain with this method, compared to adding and then removing the header on every response.
> 0 votes

# Answer
**Without coding**

Remove X-Generator is a common requirement for Drupal sites. The Mix module can deal with this and many other common situations without coding.

By checking the "Remove X-Generator" checkbox in `/admin/config/mix`, the following items can easily be removed:

* The meta tag `<meta name="Generator" content="Drupal 10 (https://www.drupal.org)">` from the page source code.
* The "X-Generator" in the HTTP header.

**Coding**

These only take a few lines of code.

To remove the `<meta name="Generator" content="Drupal 10 (https://www.drupal.org)">`, implement this in `[yourmodule].module` file.

@see https://git.drupalcode.org/project/mix/-/blob/1.x/mix.module#L96

```
/**
 * Implements hook_page_attachments_alter().
 */
function HOOK_page_attachments_alter(array &$attachments) {
  foreach ($attachments['#attached']['html_head'] as $key => $attachment) {
    if ($attachment[1] == 'system_meta_generator') {
      unset($attachments['#attached']['html_head'][$key]);
    }
  }
}

```

To remove the "X-Generator" HTTP header, you can implement an EventSubscriber.

@see https://git.drupalcode.org/project/mix/-/blob/1.x/src/EventSubscriber/MixSubscriber.php#L113

```
  public function onKernelResponse(ResponseEvent $event) {
    $response = $event->getResponse();
    $response->headers->remove('X-Generator');
  }

```
> 0 votes

---
Tags: 8, security
---


# Question
Title: How can I set multi-value datafield on node submit?
I would like to calculate and set the fourth (points) subfield of datafield on form submit. In the for each loop, the second and third subfield are used to calculate $points. How can I set/save the fourth value?

```
function handling_points_settings_submit(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
 $duration = 0.6;
 $node = $form_state->getFormObject()->getEntity()->toArray();
 // dpm($node);
 // dpm($node['field_player_stats']);
  $allPlayers = $node['field_player_stats'];
 foreach ($allPlayers as $player)   {
    //dpm($player["player"]);
    //dpm($player["wins"]);
    if (isset($player["player"])) {
        $points = intval($player["wins"]) * $duration * 2 + intval($player["non_wins"]) * $duration;
        \Drupal::messenger()->addStatus(t(htmlentities('Points' .  $points)));
    }
//something along this:
// $form_state->setValue('field_player_stats',[$player["points"]=>$points]);
 }

```

}

# Answer
```
   function handling_points_settings_submit(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
  $duration = 0.6;
  $node = $form_state->getFormObject()->getEntity()->toArray();
  $allPlayers = $node['field_player_stats'];
  foreach ($allPlayers as &$player) {
    if (isset($player["player"])) {
      $points = intval($player["wins"]) * $duration * 2 + intval($player["non_wins"]) * $duration;
      $player["points"] = $points;
    }
  }
  $node->set('field_player_stats', $allPlayers);
  $node->save();
  \Drupal::messenger()->addStatus(t('Points calculated and saved for all players.'));
}

```

In this example, we first retrieve the value of the my\_datafield element from $form\_state using the getValue() method. We then loop through each item in the datafield using a foreach loop, and calculate the points value using the second and third subfields. Finally, we set the fourth subfield value to the calculated points value, and update the datafield value in $form\_state using the setValue() method.

Note that in the code above, we are using the & reference operator to modify the $item variable directly, rather than creating a copy of it. This allows us to modify the actual value of the datafield subfield instead of just changing the value of the $item variable.
> 1 votes

---
Tags: 9
---


# Question
Title: How to redirect custom ajax form to external url with headers
When setting the form with ajax handler like this

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

    $form['actions']['submit'] = array(
      //...
      '#ajax' => [
        'wrapper' => 'custom_form_wrapper',
        'callback' => '::ajaxCallback',
      ],
    );
  }

function ajaxCallback() {
  $response = new AjaxResponse();
  $url = "www.example.com";
  $response->addCommand(new \Drupal\Core\Ajax\RedirectCommand($url));
}

```

can I set $headers = \['custom' =\> 123\] and pass this header to the redirected url? like we do in RedirectResponse().

So I can see this custom header in www.example.com

# Answer
> 0 votes
No, you cannot set headers in the same way as you do in RedirectResponse() when using RedirectCommand in an AJAX callback. The reason is that RedirectCommand uses JavaScript to redirect the user to the specified URL, and JavaScript does not have the ability to set headers.

If you need to pass headers to the redirected URL, you will need to do so on the server-side. One way to achieve this is to create a custom controller that handles the redirect, and then use RedirectResponse() with the headers you need. Here's an example:

Create a custom controller that handles the redirect and passes the necessary headers:

```
use Symfony\Component\HttpFoundation\RedirectResponse;

class MyController {
  public function redirectWithHeaders() {
    $url = 'http://www.example.com';
    $headers = [
      'custom' => 123,
    ];
    return new RedirectResponse($url, 302, $headers);
  }
}

```

In your AJAX callback, use Url::fromRoute() to generate the URL for your custom controller, and then use RedirectCommand to redirect the user to that URL:

```
use Drupal\Core\Url;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\RedirectCommand;

function ajaxCallback() {
  $response = new AjaxResponse();
  $url = Url::fromRoute('my_module.redirect_with_headers');
  $response->addCommand(new RedirectCommand($url->toString()));
  return $response;
}

```

Note that you will need to define a route for your custom controller in a my\_module.routing.yml file. Here's an example:

```
my_module.redirect_with_headers:
  path: '/redirect-with-headers'
  defaults:
    _controller: '\Drupal\my_module\Controller\MyController::redirectWithHeaders'
  requirements:
    _permission: 'access content'

```

---
Tags: ajax, redirection
---


# Question
Title: How to refresh new migrations in Drupal 8 migration module?
When writing Drupal 8 migrate processes I only can refresh new migration processes if I reinstall the custom migration module. drush cr doesn't work.

**Explanation:**

I have one module, ie: `cm_migrations`, which have 2 migrations:

* `cm_users`
* `cm_tags`

With `drush ms` I see:

```
Group: beer     Status  Total  Imported  Unprocessed  Last imported
 cm_users        Idle    3      3         0            2016-02-09 16:56:25
 cm_tags         Idle    4      0         4

```

I write a new migrate process:

* `cm_beers`

I execute `drush cr; drush ms` and I see the same table as previous.

Only when I uninstall and install `cm_migrations` I can see the three migration processes:

```
Group: beer     Status  Total  Imported  Unprocessed  Last imported
 cm_users        Idle    3      3         0            2016-02-09 16:56:25
 cm_tags         Idle    4      0         4
 cm_beers        Idle    4      0         4

```

Any clue about how can I refresh the migration processes without reinstall the module?

Thanks

# Answer
I found this worked for me

> drush config-import --partial --source=modules/custom/migrate\_module/config/install/
> 27 votes

# Answer
Migrations should be in the `MODULENAME/migrations` subdirectory. After modifying a migration config a simple `drush cr` suffices to apply the changes.

A config deriver will turn a migration config back into a migration plugin.

See this change record: Migrations are plugins instead of configuration entities
> 7 votes

# Answer
There is a module for that. Since normally the yml files are only loaded upon install.

This module lets you can define what module config files are automaticly imported.

https://www.drupal.org/project/config\_devel

Also see this blog post: https://blog.liip.ch/archive/2016/05/04/using-the-new-drupal-8-migration-api-module.html

> Developing your own Drupal 8 migrate modules and fighting caching issues

You have learned, that the whole migration mapping is now done in yaml files. But how about writing your own migration yaml files?

Unfortunately, there are some pitfalls for new Drupal 8 developers. Because of the Configuration Management Interface (https://www.drupal.org/documentation/administer/config) of Drupal 8, all yml files in the “config/install” directory are only imported when installing the module.

This is very impractical if you want to develop new configuration files. To address this, a module “Configuration Development” (https://www.drupal.org/project/config\_devel) which resolves the caching issues can be installed. It is possible to import certain yml files on every request. But unfortunately drush commands are not supported yet. So we need to add all yaml files we want to import into a new section in our module.info.yml.

```
config_devel:
 install:
   - migrate_plus.migration.page_node
   - migrate_plus.migration.menu_item
   - migrate_plus.migration_group.liip

```

Then we can run the following commands after updating the yml file. This will import the new configuration file into Configuration Management Interface.

```
drush cdi <module_name>
drush cr

```
> 6 votes

# Answer
I was struggling with the same issue: how to update migration config during development. Here is what I ended up with:

```
drush cdi1 path-to-config-dir-form-site-root/your-config.yml

```

`config-devel-import-one`, command (`cdi1` for short) is intended to import single config into active configuration. It is the part of config\_devel module mentioned above.
> 3 votes

# Answer
I didn't have success with FLY's solution. Had to uninstall migrate\_tools also, to get yaml's refreshed. And no luck with `devel_config`.

I did find this refreshed configurations:

```
$ drush @site_alias pmu mymodule, migrate_tools, migrate_plus -y
$ drush @site_alias en mymodule, migrate_tools, migrate_plus -y

```
> 2 votes

# Answer
I have found that sometimes none of the above work. Even combining them all. However I could trick migrate\_tools into giving me some insight.

Apparently there is a check if the yml file is valid before it gets listed. Try running the importer (yes, even if it doesn't show up with `$ drush ms` )

My migration was called products, so I did: `$ drush mim products`

`Migration failed with source plugin exception: The "int" plugin does not exist.`

Fixing this fault (changing int to integer in my case) and then following @FLY 's answer above made the migration show up. Shame the error did not show up and it just failed silently, but that's another topic. ;-)

P.S. I would have posted this as a comment, but I don't have enough points yet.
> 0 votes

# Answer
Following up on Peter J Lord's solution, you can also add a config directory (for new or updated ymls) to your settings.php file. e.g.:

```
$config_directories['fresh'] = 'sites/default/fresh';

```

Place new yml files in that directory and then import the fresh configuration settings with drush's config-import command:

```
drush cim fresh --partial

```
> 0 votes

# Answer
Following on from the config\_devel solution explained by FLY.

config\_devel now has a gui at admin/config/development/config\_devel. In 'Auto import' you can list all the ymls you want importing. It doesn't take wildcards so you have to list them individually. When these files change, they will be automatically imported at the beginning of the next browser page request.
> 0 votes

# Answer
In the answer by FLY above, `drush cdi <module_name>` should now be `drush cde <module_name>`.
> -4 votes

---
Tags: migrations
---


# Question
Title: How can I embed a View inside a content of a node?
How can I embed a view inside a content of a node in Drupal 8?

I found something similar, for example in the question about "How do I embed a view inside a node?" or the Viewfield module, but it is all for Drupal 7.

I tried with an Entity reference field pointing to a View but it display only a label and from the Manage Display tab I can choose only from *Label* and *Entity ID*. I need something like the "Rendered entity" option that is present on Entity reference fields pointing to other nodes.

# Answer
### Option 1

You can create a **View Block**. Then the view block will be available in the blocks section `/admin/structure/block`. Assign the view block to a region and show it on specific pages if you need to.

### Option 2

Create a twig template file for your node and use

### Twig Tweak

> Twig Tweak module provides a Twig extension with some useful functions and filters that can improve developer experience.
>
> Ex: `{{ drupal_view('view_name', 'block_1') }}`

### Option 3

If you use Panels or Display Suite, you can embed the view as a field.
> 9 votes

# Answer
I help maintain the D8 branch of EVA, which is functionally similar to Twig Tweak's `drupal_view()` but works as a View display that attaches itself to specified entity bundles as an extra field. This means the View may be reordered within the entity Manage Display UI or e.g., dropped in a field group. Like Twig Tweak's function, it allows contextual filters to be passed as arguments.

The use case for EVA and for the Twig Tweaks solution differs from that for using an entity reference with viewsreference because the latter allows content editors to select different Views on each entity. EVA and `drupal_view()` inject the same View on every entity (although contextual arguments may change the View results).

If you're creating a bespoke theme there may not be any advantage to EVA vs. twig block injection, but if you want to allow sitebuilders to manage a View as if it were an entity field and configure where it appears using the UI, have a look.
> 4 votes

# Answer
There's now also a project called viewsreference, which allows you to embed whole views into nodes via a field (think entity reference, but for complete views): https://www.drupal.org/project/viewsreference
> 3 votes

# Answer
I just used `hook_entity_extra_field_info()` and `views_embed_view()` for the content of the extra field.

```
**
 * Implements hook_entity_extra_field_info().
 */
function MY_MODULE_entity_extra_field_info() {
  $extra['node']['MY_CONTENT_TYPE'] = [
    'display' => [
      'MY_EXTRA_FIELD_NAME' => [
        'label' => 'My Extra Field',
        'description' => '',
        'weight' => 10,
      ],
    ],
  ];

  return $extra;
}

/**
 * Implements hook_ENTITY_TYPE_view() for node.
 */
function MY_MODULE_node_view(array &$build, NodeInterface $node, EntityViewDisplayInterface $display, $view_mode) {
  if ($node->bundle() === 'MY_CONTENT_TYPE') {
    $build['MY_EXTRA_FIELD_NAME'] = [
      '#type' => 'container',
      'label' => ['#markup' => '<div class="label">My Extra Field:</div>'],
      // At the following line embedding the view,
      // and giving it an optional contextual filter $node->id()
      'view' => views_embed_view('VIEW_NAME', 'DISPLAY_ID', $node->id()),
    ];
  }
}

```
> 1 votes

# Answer
You can use https://www.drupal.org/project/views\_entity\_embed. It allows you to embed views in textarea using WYSIWYG editor.
> 0 votes

---
Tags: views, 8, nodes
---


# Question
Title: Stripe doesn't see API key after TrustedRedirectResponse
I have a controller that calls the Stripe API using stripe-php to create a checkout session.

```
  /**
   * Checkout using Stripe.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request object.
   *
   * @return \Symfony\Component\HttpFoundation\Response
   *   The response.
   */
  public function checkout(Request $request): Response {
    $stripe_settings = $this->config('stripe.settings');
    Stripe::setApiKey($stripe_settings->get('apikey.' . $stripe_settings->get('environment') . '.secret'));

    // Create a Stripe checkout session.
    // https://stripe.com/docs/checkout/quickstart
    $checkout_session = Session::create([
      'line_items' => [
        [
          'price_data' => [
            'currency' => 'usd',
            'unit_amount' => 100,
            'product_data' => [
              'name' => 'Product $1',
              'description' => 'Description',
            ],
          ],
          'quantity' => 1,
        ],
      ],
      'mode' => 'payment',
      'success_url' => 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
      'cancel_url' => 'https://example.com/cancel',
    ]);
    $checkout_url = $checkout_session->baseUrl() . $checkout_session->instanceUrl();

    // In order to avoid errors like this:
    // - LogicException: The controller result claims to be providing relevant
    //   cache metadata, but leaked metadata was detected. Please ensure you are
    //   not rendering content too early. ... TrustedRedirectResponse.
    // Every Url::toString needs to have "->toString(TRUE)->getGeneratedUrl();".
    // See https://www.drupal.org/node/2638686
    $url = Url::fromUri($checkout_url, ['absolute' => TRUE, 'https' => TRUE])->toString(TRUE);
    $headers = [
      'Authorization' => 'Bearer ' . Stripe::getApiKey(),
    ];
    $response = new TrustedRedirectResponse($url->getGeneratedUrl(), Response::HTTP_SEE_OTHER, $headers);
    $response->addCacheableDependency((new CacheableMetadata())->setCacheMaxAge(0));

    // Redirect to Stripe checkout URL.
    return $response;
  }

```

So I call `Stripe::setApiKey`, I have my keys correctly set up (the checkout session is created), and the redirect to the external Stripe.com checkout session URL works. But it says the API key is missing from the headers.

I checked using Fiddler, and the header I added is sent correct in the controller's redirect response.

When looking at Stripe's checkout documentation, it doesn't use a controller, and it doesn't seem to need a separate header with the API key. So I'm not really sure what I'm missing. Do I have to do something different to ensure the header stays there after the redirect occurs in the browser or something?

# Answer
> 0 votes
The problem was that I used

```
$checkout_url = $checkout_session->baseUrl() . $checkout_session->instanceUrl();

```

Because that is `https://api.stripe.com/v1/checkout/sessions/cs_test_...`

I needed to use

```
$checkout_url = $checkout_session->url;

```

Which is `https://checkout.stripe.com/c/pay/cs_test_...`

So now I just have

```
$response = new TrustedRedirectResponse($checkout_session->url, Response::HTTP_SEE_OTHER);
$response->addCacheableDependency((new CacheableMetadata())->setCacheMaxAge(0));

return $response;

```

---
Tags: 9, redirection, payment-gateways, page-controller
---


# Question
Title: How to pass paragraph id from layout builder to view?
I have asked this question before but in a different, more convoluted context. This is a simpler example.

I have a paragraph type which I use Layout Builder to define it's layout. In that layout I have a View (paragraph) used to display content from that paragraph. If I add a contextual filter for Paragraph ID to my View and in Views preview I enter a PID, the View displays the correct results. But there is no way I can see to pass the PID from my layout to the view.

There is a Views option to set Block settings and enable Contextual filter which then shows up when I configure the block in LB. But this will not accept a token like \[paragraph:id\]; although technically it shouldn't need this as the View should know the context of where it is placed.

What am I missing here?

# Answer
> 0 votes
* In this case, don't create a paragraph View

* Instead, create a content View

* Then under Advanced, add relationship to your node's paragraph field.
* In Fields, add your paragraph fields.
* Now you can add context of ID and grab from URL.

# Answer
> 0 votes
I use this method: in the LB I remove all the fields and keep only the "title" field (for example) and I use "view" as a formatter of the field.

Then choose the view you created previously and as "View Arguments" I select "Entity ID".

I use this method when I need to create views that have "logic" behind that I can edit faster than creating a template / twig.

We use a lot of contrib modules and I don't know if this possibility comes from the core or from a module.

I use this method on D9.

---
Tags: views, 9, paragraphs, layout-builder
---


title: How do I migrate Yii2 passwords?

text:
# Question
Title: How do I migrate Yii2 passwords?
I migrated users from Yii2 to Drupal 9, where there are password hashes like *$2y$13$nhBZ37OKp27jJBLgRkFlOuL5ac8Bda5n2XIZTjKON5gKPfIcxh61y* genereated by Yii2 with `\Yii::$app->security->generatePasswordHash("123qweASD"))`.

I migrated them 1:1.

Migrating users - advanced password examples says:

> If the source system was a PHP based application that used crypt() or password\_hash(), these hashes should work as-is and they can be migrated 1:1 like in the Phpass example above .When the user logs in to your Drupal 8 site for the first time, Drupal will re-hash the password.

The password are not correct.

I tried to manually insert various hashes into the database according to this algorithm (crypt() with costFactor 13) generated in Yii2, but this also leads to a login error.

I found the following code in Yii2 (User.php).

```
/**
 * Validates password
 *
 * @param string $password password to validate
 * @return boolean if password provided is valid for current user
 */
public function validatePassword($password)
{
    if(!$password) return false;
    return Yii::$app->security->validatePassword($password, $this->password);
}

```

In Security.php, it uses the following code.

```
/**
 * Verifies a password against a hash.
 * @param string $password The password to verify.
 * @param string $hash The hash to verify the password against.
 * @return boolean whether the password is correct.
 * @throws InvalidParamException on bad password/hash parameters or if crypt() with Blowfish hash is not available.
 * @throws InvalidConfigException when an unsupported password hash strategy is configured.
 * @see generatePasswordHash()
 */
public function validatePassword($password, $hash)
{
    if (!is_string($password) || $password === '') {
        throw new InvalidParamException('Password must be a string and cannot be empty.');
    }

    if (!preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hash, $matches) || $matches[1] < 4 || $matches[1] > 30) {
        throw new InvalidParamException('Hash is invalid.');
    }

    switch ($this->passwordHashStrategy) {
        case 'password_hash':
            if (!function_exists('password_verify')) {
                throw new InvalidConfigException('Password hash key strategy "password_hash" requires PHP >= 5.5.0, either upgrade your environment or use another strategy.');
            }
            return password_verify($password, $hash);
        case 'crypt':
            $test = crypt($password, $hash);
            $n = strlen($test);
            if ($n !== 60) {
                return false;
            }
            return $this->compareString($test, $hash);
        default:
            throw new InvalidConfigException("Unknown password hash strategy '{$this->passwordHashStrategy}'");
    }
}

```

Yii 2.0.6 runs on PHP 5.6, while Drupal 9.4.5 runs on PHP 8.1.4.

How do I migrate password hashes?

# Answer
> 3 votes
That doc page seems to apply to Drupal 10, not Drupal 9. see: https://www.drupal.org/node/3322420

If you need to use Drupal 9 you could backport the code and/or write your own class the implements the same interface as

```
Drupal\Core\Password\PhpassHashedPassword

```

In Drupal 9 core.services.yml you wold need to swap your replacement class for that one in the core service definition.

```
service:
  password:
    class: Drupal\Core\Password\PhpassHashedPassword
    arguments: [16]

```

Altering is covered in the doc below, though there is a simpler way of using a replacement definition in the services file in sites/default/services.yml

https://www.drupal.org/docs/drupal-apis/services-and-dependency-injection/altering-existing-services-providing-dynamic-services

---
Tags: 9, migrations
---


title: Cache two sets of nodes

text:
# Question
Title: Cache two sets of nodes
I have a website where I have some blocks that have one content on all nodes, but different content on nodes with certain NID.

Right now, I have condition in block template based on node ID and blocks have route cache context and node id tags and this works perfectly.

However, this makes a new block cache entry for every NID/route, but in fact, there are only two block variants.

How would one optimize this in the most drupal-ish way so there are only two variants of the block cached?

# Answer
> 0 votes
As suggested in the comment, the solution to this problem is to provide its own cache context that checks if the current node id matches a list of nodes, and returns a different context string if this is true or not.

Then use this cache context on own block.

---
Tags: blocks, caching
---


# Question
Title: How to get the true client IP when a reverse proxy sets the value in a custom header rather than in X-Forwarded-For (HTTP_X_FORWARDED_FOR)
I was working with a Drupal site that sits behind a load balancer and a varnish cache - 2 proxies. The true client IP is not present in the `X-Forwarded-For` header (`$_SERVER['HTTP_X_FORWARDED_FOR'`) but is present in `$_SERVER['HTTP_X_REAL_IP']`

The IP that Drupal detects is interestingly from some hostname lookup and not present in any of the `$_SERVER` variables.

I don't have control over the infrastructure team to fix the `HTTP_X_FORWARDED_FOR` at the network level. I will need to fix it in settings.php. Now that Symfony is handling the IP detection, was wondering what `$_SERVER` variable should be altered in settings.php to get Drupal to detect the actual client IP.

# Answer
> 1 votes
To make Drupal detect the IP of the client correctly you will have to update `$_SERVER['HTTP_X_FORWARDED_FOR']` by prefixing the true client IP to it or setting it to the true client IP itself.

```
$_SERVER['HTTP_X_FORWARDED_FOR'] = $_SERVER['HTTP_X_REAL_IP'] . ', ' . $_SERVER['HTTP_X_FORWARDED_FOR'];

```

or

```
$_SERVER['HTTP_X_FORWARDED_FOR'] = $_SERVER['HTTP_X_REAL_IP'];

```

The challenge is that by the time settings.php is parsed, the Request class has already been instantiated and the server variables have already been processed and loaded into the request object. So doing this in settings.php will not help solve the problem.

In index.php

```
$kernel = new DrupalKernel('prod', $autoloader);

$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();

```

settings.php is processed in `$kernel->handle`.

By then `$request` has already been loaded with values from `$_SERVER`

So to make Drupal detect the correct IP you will have to patch index.php to add the below line before `$request` is initialized.

There is likely a PHP OOPs / Symfony approach by overriding some class / extending some class to fix this more appropriately but this will solve the problem.

---
Tags: 9
---


# Question
Title: How to check if webform has a draft submission?
I'm using hook\_webform\_submission\_form\_alter() to prepopulate some form values. When a user saves a draft of their webform submission and comes back to it later, the code in hook\_webform\_submission\_form\_alter() is wiping out their saved values. How do I first check if there's an existing draft submission? Using Webform 6.1.

# Answer
> 0 votes
Ah found it...

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

  $form_object = $form_state->getFormObject();
  $webform_submission = $form_object->getEntity();

  if ( $webform_submission->isDraft() ) {
    return;
  } else {

    //pre-populate fields...
  }

}

```

# Answer
> 0 votes
```
function MYMODULE_webform_submission_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  // Check if there's an existing draft submission.
  $webform_submission = $form_state->get('webform_submission');
  if ($webform_submission && !$webform_submission->isCompleted()) {
    // Get the saved values from the existing draft submission.
    $values = $webform_submission->getData();
    // Prepopulate the form fields with the saved values.
    $form['elements']['my_field']['#default_value'] = $values['my_field'];
    // Add any additional prepopulation code here.
  }
}

```

---
Tags: 8, webforms
---


title: Add column to custom field schema

text:
# Question
Title: Add column to custom field schema
I have created a D8 custom field that extends `FieldBaseItem`. It is already in use storing data.

How do I get the schema updated in the database, for an existing field?

What I've done:

I have added a new column by adding to `propertyDefinitions` and `schema()` accordingly.

Here's an example schema. Let's say I just added the `admin` column.

```
  /**
   * {@inheritdoc}
   */
  public static function schema(FieldStorageDefinitionInterface $field_definition) {
    $schema = [
      'columns' => [
        'state' => [
          'type' => 'varchar',
          'length' => 2
        ],
        'admin' => [
          'type' => 'int',
          'size' => 'tiny'
        ],
        ...

```

I've found posts on how to do this in `hook_update_N` in D7, but it's unclear how to do this in D8.

# Answer
> 3 votes
In fact, like it's a custom field type, your change in the schema can be detected and applied if you launch the drush command `drush entity-updates` (or `drush entup`).

All tables which implement this field (like `node__field_my_field_type` or `paragraph__field_my_field_type`) will be updated. So you don't need to use an hook\_update to update the schema of all these tables.

The big problem with this command is many errors are silent and sometimes, the command don't return errors but the schema hasn't been updated and still proposed by the command to be updated.

# Answer
> 9 votes
Since `entup` is no longer available in Drupal 8 (or 9 or 10), many people have struggled with this, and many modules contain copious amounts of code in their update hooks to deal with this. If you know exactly which field instances need to be updated, you can update their tables directly, but this is not an option if you have a module that provides a `FieldType`, and you are writing an update hook for that module. You want all instances of your field type to be detected and updated.

This Drupal core issue has some code examples for adding and removing properties from existing field types while updating all instances of that field type: https://www.drupal.org/project/drupal/issues/937442#comment-13760432 . Credit goes to https://www.drupal.org/u/robbinzhao . I just cleaned up the code and made it into a utility class:

```
<?php

namespace Drupal\my_utilities;

use Drupal\Core\Entity\Sql\SqlContentEntityStorage;

/**
 * Utilities for updating field type definitions.
 *
 * Based on https://www.drupal.org/project/drupal/issues/937442#comment-12586376
 */
class FieldTypeUpdateUtil {

  /**
   * Add a new column for fieldType.
   *
   * @param string $field_type
   *   The ID of the field type definition.
   * @param string $property
   *   The name of the property whose column is to add.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Database\SchemaObjectDoesNotExistException
   * @throws \Drupal\Core\Database\SchemaObjectExistsException
   */
  public static function addProperty($field_type, $property) {
    $database_schema = \Drupal::database()->schema();

    $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();

    // First, get all fields of the provided field type.
    $field_map = \Drupal::service('entity_field.manager')->getFieldMapByFieldType($field_type);

    // Process per entity type (i.e., node, paragraph) all fields.
    foreach ($field_map as $entity_type_id => $fields) {
      $entity_type_storage = \Drupal::entityTypeManager()->getStorage($entity_type_id);

      // Database schema can only be updated, if the values are stored in the
      // database, of course.
      if ($entity_type_storage instanceof SqlContentEntityStorage) {
        foreach (array_keys($fields) as $field_name) {
          $field_storage_definition = $entity_definition_update_manager->getFieldStorageDefinition($field_name, $entity_type_id);

          // Database column definition, according to each field property.
          $field_columns = $field_storage_definition->getColumns();

          // Get the table and column names, according to the field definition.
          $table_mapping = $entity_type_storage->getTableMapping([
            $field_name => $field_storage_definition,
          ]);
          $table_names = $table_mapping->getDedicatedTableNames();
          $table_columns = $table_mapping->getColumnNames($field_name);

          // Check if, for the property, the corresponding table exists in the
          // database. If not, create the table column (according to the schema
          // provided by the field definition).
          foreach ($table_names as $table_name) {
            $table_exists = $database_schema->tableExists($table_name);
            $field_exists = $database_schema->fieldExists($table_name, $table_columns[$property]);

            if ($table_exists && !$field_exists) {
              $database_schema->addField($table_name, $table_columns[$property], $field_columns[$property]);
            }
          }

          // Reflect any changes made to the field storage definition.
          $entity_definition_update_manager->updateFieldStorageDefinition($field_storage_definition);
        }
      }
    }
  }

  /**
   * Remove a property and column from field_type.
   *
   * @param string $field_type
   *   The ID of the field type definition.
   * @param string $property
   *   The name of the property whose column to remove.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\Sql\SqlContentEntityStorageException
   */
  public static function removeProperty($field_type, $property) {
    $field_map = \Drupal::service('entity_field.manager')
      ->getFieldMapByFieldType($field_type);
    foreach ($field_map as $entity_type_id => $fields) {
      foreach (array_keys($fields) as $field_name) {
        self::removePropertyFromEntityType($entity_type_id, $field_name, $property);
      }
    }
  }

  /**
   * Inner function, called by removeProperty.
   *
   * @param string $entity_type_id
   *   The ID of the entity type.
   * @param string $field_name
   *   The ID of the field type definition.
   * @param string $property
   *   The name of the property whose column to remove.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Core\Entity\Sql\SqlContentEntityStorageException
   */
  private static function removePropertyFromEntityType($entity_type_id, $field_name, $property) {
    $entity_type_manager = \Drupal::entityTypeManager();
    $entity_update_manager = \Drupal::entityDefinitionUpdateManager();
    $entity_storage_schema_sql = \Drupal::keyValue('entity.storage_schema.sql');

    $entity_type = $entity_type_manager->getDefinition($entity_type_id);
    $field_storage_definition = $entity_update_manager->getFieldStorageDefinition($field_name, $entity_type_id);
    $entity_storage = \Drupal::entityTypeManager()->getStorage($entity_type_id);
    /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
    $table_mapping = $entity_storage->getTableMapping([
      $field_name => $field_storage_definition,
    ]);

    // Load the installed field schema so that it can be updated.
    $schema_key = "$entity_type_id.field_schema_data.$field_name";
    $field_schema_data = $entity_storage_schema_sql->get($schema_key);

    // Get table name and revision table name, getFieldTableName NOT WORK,
    // so use getDedicatedDataTableName.
    $table = $table_mapping->getDedicatedDataTableName($field_storage_definition);
    // try/catch.
    $revision_table = NULL;
    if ($entity_type->isRevisionable() && $field_storage_definition->isRevisionable()) {
      if ($table_mapping->requiresDedicatedTableStorage($field_storage_definition)) {
        $revision_table = $table_mapping->getDedicatedRevisionTableName($field_storage_definition);
      }
      elseif ($table_mapping->allowsSharedTableStorage($field_storage_definition)) {
        $revision_table = $entity_type->getRevisionDataTable() ?: $entity_type->getRevisionTable();
      }
    }

    // Save changes to the installed field schema.
    if ($field_schema_data) {
      $_column = $table_mapping->getFieldColumnName($field_storage_definition, $property);
      // Update schema definition in the database.
      unset($field_schema_data[$table]['fields'][$_column]);
      if ($revision_table) {
        unset($field_schema_data[$revision_table]['fields'][$_column]);
      }
      $entity_storage_schema_sql->set($schema_key, $field_schema_data);
      // Try to drop field data.
      \Drupal::database()->schema()->dropField($table, $_column);
    }
  }

}

```

# Answer
> 4 votes
The update hooks are essentially the same as Drupal 7, but it's recommended to use the DB Connection object with the addField() method.

The update hook to add a column might look like this:

```
$spec = array(
 'type' => 'varchar',
 'description' => "New Col",
 'length' => 20,
 'not null' => FALSE,
);
$schema = Database::getConnection()->schema();
$schema->addField('mytable1', 'newcol', $spec);

```

Full documentation can be found here: https://www.drupal.org/docs/8/api/update-api/updating-database-schema-andor-data-in-drupal-8

# Answer
> 0 votes
This is a function I wrote to add new field(s) to existing field tables.

```
/**
 * Add a new column for fieldType.
 *
 * @param string   $field_type  ID of the field type.
 * @param string[] $new_fields  Field key(s) that is new to your schema.
 *
 * @return void
 */
function field_type_add_property(string $field_type, array $new_fields) {

  if (!$field_storage_configs = \Drupal::entityTypeManager()
    ->getStorage('field_storage_config')
    ->loadByProperties(array('type' => $field_type))
  ) {
    throw new \Exception('Unable to find field type ' . $field_type);
  }

  // Get schema handler to alter table with.
  $schema_handler = Database::getConnection()->schema();

  // Loop through all configs.
  foreach ($field_storage_configs as $field_storage) {

    // Just to play safe
    if (!($field_storage instanceof FieldStorageDefinitionInterface)) {
      throw new \Exception('Unexpected entity type loaded: ' .
        (is_object($field_storage) ? get_class($field_storage) : var_export($field_storage, true)));
    }

    // get the most updated schema from field stroage
    $schema = $field_storage->getSchema();
    $table_name = str_replace('.', '__', $field_storage->id());
    $revision_table_name = str_replace('.', '_revision__', $field_storage->id());

    // loop through the fields to alter the schema of table.
    foreach ($new_fields as $new_field) {
      $column_name = "{$field_storage->getName()}_{$new_field}";
      if (!$schema_handler->fieldExists($table_name, $column_name)) {
        $schema_handler->addField(
          $table_name,
          $column_name,
          $schema['columns'][$new_field]
        );
      } else {
        // Show some warning message or error
        throw new \Exception(sprintf('Field %s already exists in table %s',
          $column_name, $table_name));
      }
      if (!$schema_handler->fieldExists($revision_table_name, $column_name)) {
        $schema_handler->addField(
          $revision_table_name,
          $column_name,
          $schema['columns'][$new_field]
        );
      } else {
        // Show some warning message or error
        throw new \Exception(sprintf('Field %s already exists in table %s',
          $column_name, $revision_table_name));
      }
    }
  }
}

```

---
Tags: 8
---


# Question
Title: How can I render a responsive image style from an image in the theme directory?
I am working on template `views-view-fields--myview.html.twig`. But I do not think it matters what template you are working with for this to work.

I found this Twig that can add Drupal responsive images to an image that is not in a field. In this case this image is in the files directory. My question is that I want to place this image in my themes directory in: `/themes/custom/mytheme/img/mygraphic.png`. What URI can I use to make that work in this example?

Second question is: The image alt tag is empty even though I provided one. How can I display an alt tag?

```
{% set responsiveimagestyle = {
    '#theme': 'responsive_image',
    '#responsive_image_style_id': 'my_custom_responsive_style',
    '#uri': 'public://mygraphic.png',
    '#alt': 'my alt text',
    '#attributes': { class: 'img-responsive' },
} %}

```

In the views-view-fields--myview.html.twig template I now can use the following variable.

```
{{ responsiveimagestyle }}

```

The image is wrapped in the picture tag and is using the Drupal Responsive Images style.

# Answer
> 2 votes
> This is the same when using the image filters from the Twig Tweak module: You can't render responsive images from a random URI, it has to be an URI that is stored in the file\_managed DB table. **But with Twig tweak you can render normal image styles from random URIs**, and manually create a responsive image tag by rendering multiple normal image styles. – Hudri

Great, so there is a workaround one can do, manually create one:

```
{% set imagePath = '/themes/custom/mytheme/img/mygraphic.png' %}
<img srcset="{{ imagePath|image_style('thumbnail') }} 300w, {{ imagePath|image_style('medium') }} 800w" src="{{ file_url(imagePath) }}" alt="some graphic image" typeof="foaf:Image"/>

```

# Answer
> 1 votes
I'm pretty sure (though not a 100%) that rendering a responsive image where the original image comes from a theme asset won't work that way. To have a responsive image rendered you need multiple different image derivatives in different sizes. These normally get created automatically during image upload via an image field. I can't imagine that this happens on the fly from an unmanaged image.

Your best bet I guess is to provide a managed image from a theme settings or system settings form. This gets uploaded to the files directory as usual. Maybe all images sizes then get created automatically. Maybe you still need to programmatically ensure the image derivatives get created.

Alternatively you could simply require to upload all necessary image sizes, to then build your own `srcset` from them, see No Sssweat's answer.

The alt tag in your question needs to be added from the `#attributes` array.

# Answer
> 1 votes
Might be an old post but you can also do this with the following module https://www.drupal.org/project/system\_stream\_wrapper

Pass the uri `theme://mytheme/img/mygraphic.png` and the responsive\_image theme function should pick up the new theme stream wrapper.

Hope that helps

# Answer
> 0 votes
I am able to render the alt text using the following code.

```
{% set card_img = {
   '#theme': 'responsive_image',
   '#responsive_image_style_id': 'concentration_card',
   '#uri':        item.entity.field_ccard_img.entity.field_media_image.entity.fileuri,
   '#attributes': { class: 'card-img', alt: item.entity.field_ccard_img.entity.field_media_image.alt },
                }
%}

```

---
Tags: 8, theming, media
---


title: Orders view personalization

text:
# Question
Title: Orders view personalization
Apache 2.4.29 + php8.1 + mySQL 5.7.41 Drupal 9.5.3 Commerce 8.x-2.33

Hi all folks ! I'm trying to personalize the orders view with custumer's name, adress, ... To do that i add the "commande" field in the view with "rendered entity" form, but with that i see all the command's history, commentaries ... despite the fact that i create un special "listing" display format for commands and i hide every fields. The "listing" selection appears good in the field format in the view. Need some help, please.

# Answer
> 0 votes
The question seems rather unclear and could do with screenshots and more of an explanation of what the end result should be.

However, if you are trying to attach a different entity to a view to display its fields it sounds like you would be better off adding a relationship to the view of this "Commande" entity. This can be found under the Advanced section on the right side of the Views edit screen. Once you have the correct relationship, you will find additional fields can be added. Without knowing more about your site I can't tell you more than that, but that should be a good starting point for you.

If you still can't find a solution via views, you may need to look at creating a custom module and creating your own controller to display the table you need.

---
Tags: views, commerce
---


# Question
Title: Storing temporary data in a form AJAX callback
I have a form submit button that when clicked fires an AJAX callback.

```
$form['actions']['submit'] = [
  '#type' => 'submit',
  '#value' => $this->t('Title...'),
  '#ajax' => [
    'callback' => '::getResponse',
    'wrapper' => 'wrapper',
  ],
];

```

In the AJAX callback, I would like to save what the user entered, plus what the API responded with. I have tried using form state storage and $form\_state-\>set, but in both cases the values are lost.

Form AJAX callback:

```
  public function getResponse(array &$form, FormStateInterface $form_state) {
    // API call here...

    $form['response']['#value'] = trim($result["answer"]) ?? $this->t('No answer was provided.');
    return $form['response'];
  }

```

Is there a way to update the UI and the form state?

# Answer
> 1 votes
Data can be stored in the form submission using `$form_state->set('[ARBITRARY KEY]', $value)`, then retrieved when the form is rebuilt with `$value = $form_state->get('[ARBITRARY KEY]')`. On the first form build, `$value` will be null, as the form has not gone through the ajax yet. On further #ajax rebuilds, `$value` will contain the value you set in the submit handler. Note that you will have to store the value on the form state in the submit handler, NOT the #ajax callback.

---
Tags: forms, 9
---


# Question
Title: Block Configuration Form Returning Unexpected Value
I'm trying to build a block configuration form. Here's my blockForm code:

```
  public function blockForm($form, FormStateInterface $form_state) {
    $form['resolve_ip_addresses'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Resolve IP Addresses'),
      '#default_value' => $this->configuration['resolve_ip_addresses'],
      '#description' => $this->t('Resolve IP addresses to return host names for log file entries.'),
    ];

    $form['log_file_path'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Log File Path'),
      '#default_value' => $this->configuration['log_file_path'],
      '#description' => $this->t('The full file system path to the log file to be parsed.'),
    ];

    $form['log_file_format'] = [
      '#type' => 'radios',
      '#title' => $this->t('Log Format'),
      '#default_value' => $this->configuration['log_file_format'],
      '#options' => [
        0 => $this->t('Common Log Format (Apache)'),
        1 => $this->t('Combined Log Format (Nginx)'),
        2 => $this->t('Other'),
      ],
      '#attributes' => [
        'name' => 'field_log_file_format',
      ],
    ];
    $form['custom_log_format'] = [
      '#type' => 'textfield',
      '#size' => '60',
      '#placeholder' => $this->t('Enter log format'),
      '#default_value' => $this->configuration['custom_log_format'],
      '#attributes' => [
        'id' => 'custom-log-format',
      ],
      '#states' => [
        'visible' => [
          ':input[name="field_log_file_format"]' => ['value' => 2],
        ],
      ],
    ];

    return $form;
  }

```

The form seems to be displayed properly. I'm having an issue getting the value for the "log\_file\_format" field. Here's my blockSubmit code:

```
  public function blockSubmit($form, FormStateInterface $form_state) {
    $this->configuration['resolve_ip_addresses'] = $form_state->getValue('resolve_ip_addresses');
    $this->configuration['log_file_path'] = $form_state->getValue('log_file_path');
    $this->configuration['log_file_format'] = $form_state->getValue('log_file_format');
    $this->configuration['custom_log_format'] = $form_state->getValue('custom_log_format');
  }

```

The problem is that the value returned from $form\_state-\>getValue('log\_file\_format') is always 0 (zero), no matter what value I select on the form and save the block. All of the other values are correct. Interestingly, the "custom\_log\_format" field correctly switches visibility on the form when the "Other" option (value 2) is selected. What am I doing wrong here?

# Answer
> 0 votes
The fix suggested by @unusedspoon took care of the radio element value problem. The form element value was properly set after removing the `'name' => 'field_log_file_format'` attribute from the `'log_file_format'` form element - but that broke the visibility toggle for the `'custom_log_format'`. The fix for that was to change `':input[name="field_log_file_format"]'` to `':input[name="settings[log_file_format]"]'`.

---
Tags: forms, blocks, configuration
---


# Question
Title: How to validate numbers in a webform custom composite element
I have a Webform with a custom composite, and there I have a element which type is Number and i want to validate this element.

If I check required when the field is empty it show a message that the field is required, but if I put letters in the field show the same message when it should be that the field is not valid because it has letters.

I know how to do this with a textfield element but this element is not inside the custom composite with a regular expression . And even if i change the custom composite element from Number to Textfield I can not do it this, can not be validated individually.

# Answer
> 0 votes
You can add regular expressions for elements in a custom composite by going to the *General* tab of the custom composite, then adding your regular expression in the custom properties field for an element within the *Custom composite settings* section.

This link may be of use:

https://www.drupal.org/project/webform/issues/3162515

# Answer
> -1 votes
Instead of putting validations just create a number type field. And inside the number field of the custom composite element, `you can not enter the letters`, only numbers can be entered so no concept/need for validating against letters.

---
Tags: webforms
---


title: Colorbox and complex modals

text:
# Question
Title: Colorbox and complex modals
Is it possible to make the colorbox popup take more complex content than just an image and a caption?

On a drupal 9 site I have been asked to modify a simple colorbox gallery to include a long/formatted Caption/story and a title in a responsive two-panel pop-up.

Is such a thing even possible or am I better of building something like this from scratch or with something else?

to expand on the format:

1. View showing a custom media type with several fields
2. Each popup should contain 3 fields - A Title, A Story and an Image
3. Should be a responsive two-column (Image + Story) at desktop to Image on top of story on mobile

What I really want is colorbox to act as a formatter for an entire entity and then be able to template the content it injects into the pop-up

# Answer
> 1 votes
After a few days of pain I think I have a solution. In case it is of use to anyone else.

Firstly: Colorbox 2.0 (Drupal 9/10 version) cannot load entities. By default, it is only an image formatter. From the project site:

> Colorbox for Drupal 8 is an image field formatter and nothing more, or less.

**Solution 1: HTML Formatted Media type Caption**

It is possible to have colorbox load a Media entity image field and pass another custom field as the caption. With some tweaking, you can get html working as well. This can be setup on the entity display settings or in a view (as a formatter for the image field). It is not very flexible. The caption will, by default, also be the image title which can cause issues if you are loading html. You will probably also need to fiddle with the allowed html tags in the colorbox module's settings.

If that is what you need, that is doable. If you need anything more complex read on.

**Solution 2: Adding full entities**

There is a mobule that extends colorbox to allow the loading of entities it is called Colorbox Entity Display

It doesn't completely integrate with colorbox. In order to have the entity load you need to add a class to a link.

It DOES NOT work for media entities; at least I couldn't get it to work. You will need to make a normal content type and configure it to look how you want it to appear in the modal.

Colorbox will attempt to load the node portion of the content so you can just override the node template with whatever format you want.

The process for getting entities into a view based photo gallery is:

1. Create view with at least - Image field, Link to content (as text and hidden), field for link title (hidden)
2. Re-write the output of the image field as a link and pass the two other fields as well as the custom colorbox-entity class to the link.

After that, you should have a colorbox gallery with the ability to load entities into the modal.

---
Tags: views, 9
---


# Question
Title: Programatically render a node in a specific language
I want to render a node display programmatically for sending it to a search engine. It works ok but is ignoring the language and renders the field labels in the source language (which is English).

I use the following code for creating the teaser markup.

```
 $render_array_teaser = $view_builder->view($entity, 'compact_teaser', 'de');
 $rendered_teaser = $renderer->renderPlain($render_array_teaser);

```

The result gives me a teaser that includes a field named "field\_sku" that has the label "SKU number". If I output the teaser in the browser the label gets correctly translated to German = "Artikelnummer" if the current language is "German".

If I render the teaser with the above code the label stays English even if I set the langcode parameter to 'de'.

How to get the teaser with German lables?

# Answer
The field labels are used from the config translation system. You also need to set the config override language. See `user_mail()` in core.

```
  // Temporarily alter the language manager.
  $language_manager = \Drupal::languageManager();
  $langcode = $message['langcode'];
  $variables = array('user' => $params['account']);

  $language = \Drupal::languageManager()->getLanguage($params['account']->getPreferredLangcode());
  $original_language = $language_manager->getConfigOverrideLanguage();
  $language_manager->setConfigOverrideLanguage($language);
  $mail_config = \Drupal::config('user.mail');

  // Restore the language manager.
  $language_manager->setConfigOverrideLanguage($original_language);

```
> 9 votes

# Answer
Seems like this do not works anymore - see https://www.drupal.org/project/drupal/issues/3061599 :-(
> 0 votes

---
Tags: 8, i18n-l10n
---


# Question
Title: Why are terabytes of memory suddenly requested?
A couple of days ago I configured my server to use PHP-FPM to use different versions of PHP for different sites. After that they worked fine. Two Drupal 9 sites are using PHP 8.1, other Drupal 7 sites are using PHP 7.4.

Without any changes I am aware of, the sites stopped working. The server log file contains a warning regarding memory usage:

> PHP Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 7002662505284858752 bytes) in Unknown on line 0

I had already raised the memory\_limit from 512mb to 1gb. Before, the error message reflected the other setting:

> PHP Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 7002662505284858752 bytes) in Unknown on line 0

I even tried to set it to -1:

> PHP Fatal error: Out of memory (allocated 2097152) (tried to allocate 7002662505284858752 bytes) in Unknown on line 0

How on earth could Drupal suddenly use 7.002.662.505.284.858.752 bytes of memory? That's 7.002.662.505 gb or 7.002.662 tb.

At the same time I got errors regarding SSL certificates. All sites use certificates from Let's Encrypt and worked without a problem. Running checks on https://www.ssllabs.com, no problem appears. I configured the sites to run without https, but the memory error remains.

I can't even log into my sites, but using Drush, the watchdog log doesn't show anything important.

On some pages or sites, using Chrome, I get the error ERR\_EMPTY\_RESPONSE.

I am kind of lost after some hours of searching. Does anybody have an idea what could be causing this?

**Update:** I created an issue on drupal.org: Auto-generated .htaccess in files directory breaks sites

# Answer
> 1 votes
I investigated a lot and it seems the problem was that after installing PHP-FPM, I didn't disable mod\_php. Now I ran

```
sudo a2dismod php7.4

```

and rebuilt all caches. The error does not appear anymore, at least by now.

Before, I found that this part in `sites/default/files/.htaccess` of Drupal 8 and 9 sites caused SSL errors that lead to the problems described above:

```
<IfModule mod_php7.c>
  php_flag engine off
</IfModule>
<IfModule mod_php.c>
  php_flag engine off
</IfModule>

```

Commenting them out (adding # in every line) made the sites work properly and apparently also makes the memory error disappear. After disabeling mod\_php, the sites ran with the original `.htaccess` created by Drupal.

### Maintaining security features with PHP-FPM

In my understanding, using PHP-FPM means that the security features in `.htaccess` won't work. One workaround I found was adding this before `<IfModule mod_php7.c>` in `sites/default/files/.htaccess`:

```
<Files "*.php">
  SetHandler none
  SetHandler default-handler
  Options -ExecCGI
  RemoveHandler .php
</Files>

```

This will lead to security warnings by the Security Review in Drupal, though, because the `.htaccess` file has been altered. Another way is to change the configuration directly in the Apache conf file as decribed here (I adapted it a little):

```
# Security setting for files folder in Drupal.
<DirectoryMatch "^/var/www/.*/sites/.*/(files|tmp)">
    # Turn off all options we don't need.
    Options -Indexes -ExecCGI -Includes -MultiViews

    # Set the catch-all handler to prevent scripts from being executed.
    SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
    <Files *>
        # Override the handler again if we're run later in the evaluation list.
        SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
    </Files>

    # If we know how to do it safely, disable the PHP engine entirely.
    <IfModule mod_php7.c>
        php_flag engine off
    </IfModule>
    <IfModule mod_php.c>
        php_flag engine off
    </IfModule>
</DirectoryMatch>

# Security setting for config folder in Drupal.
<DirectoryMatch "^/var/www/.*/sites/.*/(private|config|sync|translations|twig)">
    <IfModule mod_authz_core.c>
        Require all denied
    </IfModule>

    # Deny all requests from Apache 2.0-2.2.
    <IfModule !mod_authz_core.c>
        Deny from all
    </IfModule>
    # Turn off all options we don't need.
    Options -Indexes -ExecCGI -Includes -MultiViews

    # Set the catch-all handler to prevent scripts from being executed.
    SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
    <Files *>
        # Override the handler again if we're run later in the evaluation list.
        SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
    </Files>

    # If we know how to do it safely, disable the PHP engine entirely.
    <IfModule mod_php7.c>
        php_flag engine off
    </IfModule>
    <IfModule mod_php.c>
        php_flag engine off
    </IfModule>
</DirectoryMatch>

```

---
Tags: 9
---


# Question
Title: How do I check if TwigTweak is enabled before declaring a function in a template?
I am cretaing a theme which uses the twigtweak module to display some views/blocks in some of the templates.

If a person enables the theme before enabling twigtweak module they get an error. For example if I put the following in a template, the site gets a php error 'drupal\_entity is an unknown function'

```
{{ drupal_entity('block_content', 1) }}

```

So I try

```
{% if drupal_entity ?? false %}
    {{ drupal_entity('block_content', 1) }}
{% else %}
    <p>You should enable Twig Tweak module for this functionality</p>
{% endif %}

```

But I am still getting similar errors. How can I check if Twig Tweak is enabled or if the Twig Tweak function is valid/exists?

Thanks

# Answer
> 1 votes
On Drupal 8.9.x and successive Drupal versions, a theme can define its dependencies from modules. When that theme is installed, Drupal core will require that module to be installed, before allowing the theme installation. This means that when a theme template file is used, the require to use it.

Themes can declare dependencies on modules gives more details, but essentially that is done as it is done with modules. In the .info.yml file for the theme, it is sufficient to add lines like the following ones. (Replace `<module>` with the module name, name-spaced, for example `drupal:user` for the User module that is part of Drupal core, or `twig_tweak:twig_tweak` for the Twig Tweak module.)

```
dependencies:
  - <module>

```

If instead you want the theme to optionally depend on that module, you need to implement a preprocess function that is used for that template file. Since the question does not make clear which template file is used, I will make an example that is valid for the *user.html.twig* template file, but that can be adapted to other template files. (Replace `<theme_name>` with the theme machine name.)

```
function <theme_name>_preprocess_user(&$variables) {
  $variables['twig_tweak'] = \Drupal::moduleHandler()->moduleExists('twig_tweak');
}

```

Then, the template file should check the value of that variable.

```
{% if twig_tweak %}
  {{ drupal_entity('block_content', 1) }}
{% else %}
  { # Show the content in a different way #}
{% endif %}

```

Since that module is an optional dependency, users should not see a message telling them to install a module when the module is not installed, which would probably be seen even from users who cannot install new modules on that site. Instead, the template file should shown alternative content, or show the same content in a different way.

If the same variable is required from more template files, instead of a preprocess function that is called for a single template file, I would implement `<theme_name>_preprocess()`, which is called for every template file.

# Answer
> 0 votes
If your theme depends on a module to function you should add the module as a dependancy in your themes .info.yml file. e.g.:

```
dependencies:
  - drupal:twig_tweak

```

Then people won't be able to install your theme without it

---
Tags: theming
---


# Question
Title: KernelEvents::REQUEST is not fired on cached pages
I need to implement an event subscriber to perform some actions when the page is loaded. The event should be fired whether the requested page exists in the Drupal cache or not. It seems that the `KernelEvents::REQUEST` event doesn't fire when Drupal serves something from the cache.

Is there an event I can use to achieve this, or should I implement some form of middleware?

# Answer
The dynamic cache subscribes an event with priority 27. If you want that your code runs before that you have to use a priority \>27:

```
  public static function getSubscribedEvents() {
    $events = [];

    // Run after AuthenticationSubscriber (necessary for the 'user' cache
    // context; priority 300) and MaintenanceModeSubscriber (Dynamic Page Cache
    // should not be polluted by maintenance mode-specific behavior; priority
    // 30), but before ContentControllerSubscriber (updates _controller, but
    // that is a no-op when Dynamic Page Cache runs; priority 25).
    $events[KernelEvents::REQUEST][] = ['onRequest', 27];

```

Which runs DynamicPageCacheSubscriber::onRequest..
> 17 votes

# Answer
Drupal 8 has two level cache, page cache and dynamic page cache.

Yes you can intercept the dynamic page cache as what @4k4 mentioned. The issue you are having is more likely to intercept the page cache. The key is in here.

There are a few solutions for this:

1. Add new class which implements 'HttpKernelInterface' and register 'http\_middleware' with higher priority than 200 (280 will do). See 'PageCache' class and implementations for references.
2. Create new class to alter the existing 'PageCache' by extending from 'ServiceProviderBase'. Check this out for references here. Then, create new class to extends the 'PageCache'.

Here is code references:

This is StaticCacheServiceProvider.php:

```
/**
 * Modifies the language manager service.
 */
class StaticCacheServiceProvider extends ServiceProviderBase
{
  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container)
  {
    // Overrides language_manager class to test domain language negotiation.
    $definition = $container->getDefinition('http_middleware.page_cache');
    $definition->setClass('Drupal\your_module\StackMiddleware\StaticCache');
  }
}

```

This is StaticCache.php:

```
/**
 * Executes the page caching before the main kernel takes over the request.
 */
class StaticCache extends PageCache
{
  /**
   * {@inheritdoc}
   */
  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)
  {
    // do special logic here.

    $response = parent::handle($request, $type, $catch);

    return $response;
  }
}

```

Hope helps.
> 9 votes

# Answer
In addition to the 2 methods mentioned by @kororo, you can also try to solve it in the following way.

Since the PageCache uses requestPolicy to determine whether to return the page cache or not

```
Drupal\page_cache\StackMiddleware\PageCache::handle()

$this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW

```

So, you can also solve this by implementing a RequestCheckPolicy, which can be found at
> 0 votes

---
Tags: 8, caching, event-subscribers
---


# Question
Title: Adding custom operations with hook_entity_operation()
I'm trying to add a custom entity operation to taxonomy terms of a specific vocabulary.

I've found documentation on using hook\_entity\_operation() to add the operation, and that works, but I'm not sure what to do from there.

Here's the hook implementation:

```
function nm_target_entity_operation(\Drupal\Core\Entity\EntityInterface $entity) {
  $operations = [];
  if ($entity->getEntityTypeId() == 'taxonomy_term' && $entity->vid->getString() == 'data-source') {
    $operations['import'] = [
      'title' => t('Re-import'),
      'url' => // what goes here?
      'weight' => 50,
    ];
  }
  return $operations;
}

```

If I want to have a confirmation page at /taxonomy/term/{taxonomy\_term}/import, what do I put in the URL property and what kind of class should that route point at?

I took a look at Entity Clone module as that's the only contribute module we use that implements that hook, but that does complicated things with link templates that I don't understand.

# Answer
The explanation of what the array returned by `hook_entity_operation()` contains is explained in the documentation for `EntityListBuilderInterface::getOperations()`.

> * title: The localized title of the operation.
> * url: An instance of \Drupal\Core\Url for the operation URL.
> * weight: The weight of this operation.

`'url'` is simply the URL for the page executing that operation.

There are 5 implementations of that hook done in Drupal core, for example `config_translation_entity_operation()`, `content_translation_entity_operation()`, or `field_ui_entity_operation()`.
The code they use to get the URL vary from one implementation to the other. The simpler way to get a URL for a page created from a module you wrote, for which you know the page route, is calling `Url::fromRoute()`.
> 1 votes

---
Tags: entities, 9
---