# Question
Title: Issues with beans in the migration (some nodes don't migrate, some migrate old revisions)
I am trying to do a migration from Drupal 7 to Drupal 9. Most seems to migrate okay but I noticed the following problems:

* I am missing some nodes
* Some nodes migrated only old revisions of the node (IE: In the live site a node has 8 revisions, and the migration only migrated the first 2, leaving the most recent of the 2 as the live content, which is a review from 2015. The most recent review in the site is from 2021)

The issue probably comes from one of those notices, I am just not too sure how to fix it or debug them:

```
The "bean" entity type does not exist. (/app/web/core/lib/Drupal/Core/Entity/EntityTypeManager.php:143)
[notice] Cannot change the field type for an existing field storage. The field storage node.field_thumbnail has the type entity_reference. (/app/web/core/modules/field/src/Entity/FieldStorageConfig.php:375)
[notice] Cannot change the field type for an existing field storage. The field storage node.field_event_date has the type daterange. (/app/web/core/modules/field/src/Entity/FieldStorageConfig.php:375)
[notice] The "bean" entity type does not exist. (/app/web/core/lib/Drupal/Core/Entity/EntityTypeManager.php:143)
 [notice] Attempt to create a field field_bean_text that does not exist on entity type bean. (/app/web/core/modules/field/src/Entity/FieldConfig.php:315)
 [notice] Attempt to create a field field_link_to that does not exist on entity type bean. (/app/web/core/modules/field/src/Entity/FieldConfig.php:315)
 [notice] The configuration property settings.required_summary.0 doesn't exist. (/app/web/core/lib/Drupal/Core/Config/Schema/ArrayElement.php:76)
 [notice] The configuration property settings.required_summary.0 doesn't exist. (/app/web/core/lib/Drupal/Core/Config/Schema/ArrayElement.php:76)

```

Any tips to migrate beans? I tried using the module "bean migrate" but then those notices turn in to:

```
 [notice] Upgrading bean:homepage_information_block_base
 [error]  Drupal\Core\Database\IntegrityConstraintViolationException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'uuid' cannot be null: INSERT INTO "block_content" ("revision_id", "type", "uuid", "langcode") VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3); Array
(
    [:db_insert_placeholder_0] =>
    [:db_insert_placeholder_1] => homepage_information_block_base
    [:db_insert_placeholder_2] =>
    [:db_insert_placeholder_3] => und
)
 in Drupal\Core\Database\Driver\mysql\ExceptionHandler->handleExecutionException() (line 50 of /app/web/core/lib/Drupal/Core/Database/Driver/mysql/ExceptionHandler.php).
 [notice] SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'uuid' cannot be null: INSERT INTO "block_content" ("revision_id", "type", "uuid", "langcode") VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3); Array
(
    [:db_insert_placeholder_0] =>
    [:db_insert_placeholder_1] => homepage_information_block_base
    [:db_insert_placeholder_2] =>
    [:db_insert_placeholder_3] => und
)

```

I am fairly familiar with Drupal, just not so much with Migrations, so any general tips to help me debug/fix would be appreciated

# Answer
Okay so I eventually figured this out. I am not sure why I was not getting the error, but somewhere in the migration process I eventually found out my docker container did not have enough memory assigned for the process. The migration seemed to finish, but parts of it crashed/timed out and didnt migrate.

All I did was increase the memory and timeout time and it worked. The other errors were probably result of that and/or irrelevant.
> 0 votes

---
Tags: migrations, 9
---


# Question
Title: Can I use theme hook to display some extra fields in block?
Let's say I have 'opigno\_documents\_last\_group\_block' hook:

```
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'opigno_documents_last_group_block' -->
<!-- BEGIN OUTPUT from 'modules/contrib/opigno_learning_path/templates/opigno-documents-latest-group-block.html.twig' -->
<div class="content-box">
...

```

How can I enter it to pass some more variables to template?

I tried:

```
THEME_NAME_opigno_documents_last_group_block
THEME_NAME_opigno_documents_last_group_block_preprocess
or
THEME_NAME_preprocess_block

```

hooks and some others, but nothing seems to trigger this block, but it seems to dissapear (with plenty other blocks) when I unset npx\_main\_content\_block.

The block opigno\_documents\_last\_group\_block is located in opigno\_learning\_path/src/Plugin/Block/DocumentsLastGroupBlock.php, which looks like this:

```
<?php

namespace Drupal\opigno_learning_path\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Url;

/**
 * Provides a documentslastgroupblock block.
 *
 * @Block(
 *   id = "opigno_documents_last_group_block",
 *   admin_label = @Translation("DocumentsLastGroupBlock"),
 *   category = @Translation("Custom")
 * )
 */
class DocumentsLastGroupBlock extends BlockBase {

  /**
   * @var \Drupal\Component\Plugin\Context\ContextInterface[]|mixed
   */
  protected $groupId;

  /**
   * {@inheritdoc}
   */
  public function build() {
    $this->groupId = $gid = $this->configuration["group"];
    $tid = _tft_get_group_tid($gid);
    $content = _tft_folder_content($tid, FALSE, $gid);
    $content = array_slice($content ?: [], 0, 4);
    foreach ($content as $index => $item) {
      $content[$index] = [
        '#theme' => 'opigno_documents_last_group_item',
        '#type' => $item["type"] == 'file' ? 'file' : 'folder',
        '#item' => $item,
        '#label' => $item["name"],
        '#link' => $this->itemLink($item),
      ];
    }
    $build['content'] = [
      '#theme' => 'opigno_documents_last_group_block',
      'content' => $content,
    ];
    return $build;
  }
(...)

```

and is attached in LearningPathController in this module:

```
 /**
  * Training document block.
  */
  public function trainingContentDocuments(&$content, $group) {

    // $TFTController = new TFTController();
    // $listGroup = $TFTController->listGroup($group->id());
    $tft_url = Url::fromRoute('tft.group', ['group' =>    $group->id()])->toString();

    $content['tabs'][] = $tft_url = [
     '#markup' => '<div class="see-all see-all-files"><a href="' . $tft_url . '">' . $this->t('See all') . '</a></div>',
    ];

    $block_render =    $this->attachBlock('opigno_documents_last_group_block', ['group' => $group->id()]);
   $block_render["content"]['link'] = $tft_url;
    $content['tab_content']['documents'] = (isset($block_render["content"]["content"]) && !empty($block_render["content"]["content"])) ? [
      '#type' => 'container',
      '#attributes' => [
        'id' => 'documents',
      ],
      'block' => [
        'content' => $block_render["content"],
      ],
    ] : [];

  }

```

# Answer
The correct name for the preprocess function is `THEME_NAME_preprocess_opigno_documents_last_group_block()`.
> 1 votes

# Answer
I managed to understand how to solve my problem and pass extra fields using this hook:

```
function npx_main_theme() {
  return [
    'opigno_documents_last_group_block' => [
      'variables' => [
        'param1' => 'texttest'
      ]
    ]
  ];
}

```
> 0 votes

---
Tags: hooks, 9
---


title: Ajax only binding once

text:
# Question
Title: Ajax only binding once
It looks like Drupal changed to a different, non jQuery version of once, and now all of our code that updates the DOM and needs to reattach the events for AJAX elements no longer reattaches them; `Drupal.attachBehaviors()` no longer works.

# Answer
I have to assume that the changes to core/once library in 9.2 described here - https://www.drupal.org/node/3158256 , then also being used in core Ajax, changed the behavior. Though since we have a more global "once" class, if I understand correctly, we gain the ability to add and remove "once".

So this is what ended up working, but I'm hesitant.

```
(function (Drupal, once) {
...

/* After js (vue in this case) renders & kills event binding */

once.remove('drupal-ajax', '[data-once=drupal-ajax]');
Drupal.attachBehaviors();

...
})(Drupal, once);

```
> 1 votes

---
Tags: ajax, 9
---


# Question
Title: Overwrite twig (template) files from a contrib module in my custom subtheme?
I need to overwrite and adjust the twig (template) files from the Facet module in my custom subtheme? Is that possible? I need to change below markup and CSS classes (to debug faster, I also added my template suggestion here):

```
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'item_list' -->
<!-- BEGIN OUTPUT from 'themes/custom/my_theme/templates/dataset/item-list.html.twig' -->
<div class="item-list">
    <ul data-drupal-facet-id="contactvoorkeur" class="js-facets-checkbox-links">
        <li class="facet-item">
            <input type="checkbox" class="facets-checkbox" id="contactvoorkeur-email" data-facetsredir="/search-person/cards?f[0]=contactvoorkeur%3Aemail">
            <label for="contactvoorkeur-email">

                <!-- THEME DEBUG -->
                <!-- THEME HOOK: 'facets_result_item' -->
                <!-- BEGIN OUTPUT from 'modules/contrib/facets/templates/facets-result-item.html.twig' -->
                E-mail <span class="facet-count">(4)</span>
                <!-- END OUTPUT from 'modules/contrib/facets/templates/facets-result-item.html.twig' -->

            </label>

            <a href="/search-person/cards?f[0]=contactvoorkeur%3Aemail" rel="nofollow" data-drupal-facet-item-id="contactvoorkeur-email" style="display: none;">
                <!-- THEME DEBUG -->
                <!-- THEME HOOK: 'facets_result_item' -->
                <!-- BEGIN OUTPUT from 'modules/contrib/facets/templates/facets-result-item.html.twig' -->
                E-mail <span class="facet-count">(4)</span>
                <!-- END OUTPUT from 'modules/contrib/facets/templates/facets-result-item.html.twig' -->

            </a>
        </li>
        <li class="facet-item">
            <input type="checkbox" class="facets-checkbox" id="contactvoorkeur-post" data-facetsredir="/search-person/cards?f[0]=contactvoorkeur%3Apost">
            <label for="contactvoorkeur-post">

            <!-- THEME DEBUG -->
            <!-- THEME HOOK: 'facets_result_item' -->
            <!-- BEGIN OUTPUT from 'modules/contrib/facets/templates/facets-result-item.html.twig' -->
            Post <span class="facet-count">(2)</span>
            <!-- END OUTPUT from 'modules/contrib/facets/templates/facets-result-item.html.twig' -->

            </label>

            <a href="/search-person/cards?f[0]=contactvoorkeur%3Apost" rel="nofollow" data-drupal-facet-item-id="contactvoorkeur-post" style="display: none;">

                <!-- THEME DEBUG -->
                <!-- THEME HOOK: 'facets_result_item' -->
                <!-- BEGIN OUTPUT from 'modules/contrib/facets/templates/facets-result-item.html.twig' -->
                Post <span class="facet-count">(2)</span>
                <!-- END OUTPUT from 'modules/contrib/facets/templates/facets-result-item.html.twig' -->

            </a>
        </li>
    </ul>
</div>

```

My main goal is to:

**1)** How do I *add* a bootstrap css-class `list-group` to the existing facet class `js-facets-checkbox-links`. So I get:

```
<ul data-drupal-facet-id="contactvoorkeur" class="list-group js-facets-checkbox-links">

```

**2)** And how do I *replace* an existing facet class `facet-item` with `list-group-item`:

```
<li class="list-group-item">

```

# Answer
Facets doesn't define a template, it uses an existing generic template from core. So technically, your question title is not reflecting what you are actually asking/need to do.

That means there isn't a specific template that you can just override and you need a slightly different approach.

It is good practice to allow for a more specific template by using something like `'#theme' => 'item_list__facets'` or so, then you could at least provide a template for all facets block, although it possibly would need to be even more specific/flexible.

That said, using preprocess/template\_suggestions\_alter() hooks, you should be able to add that class or provide a custom template for it, with some assumptions.

Basically, you define a function \`yourtheme\_preprocess\_item\_list($variables). In $variables, you should fine the data you need to identify the block you want to change, for examples based on the data attributes or classes that should be somewhere in there. You can try dpm() or so but I'd recommend setting up an IDE with a real debugger which offers way better experience in looking at complex data structures.

And then you can alter it based on whatever you want, e.g. to add some more classes to it.
> 1 votes

# Answer
Since you didn't clarify any specific module, i'll explain it with Paragraphs.

In the Paragraphs folder there is a folder called "templates", this will be the default template used by all fields that use paragraphs.

If you copy these templates and paste them into your own custom theme you can edit them as much as you like, using twig debug you can specify it per field.

Don't forget to clear your cache when editing!
> 1 votes

# Answer
In my case I am working with Drupal 9 and I wanted to change a twig template from Better Exposed Filter module. As Kimimaruu suggested I did not need a theme suggestion to create my own template. In most cases (most contrib modules and themes should support this) I just copied the template from the contributed module and placed it in my custom theme folder theme/custom/mytheme/templates/form.
> 0 votes

---
Tags: 8, theming
---


# Question
Title: How can I list only modules which need an update?
Drush 8.1.9 & Drupal 7.53. What I'm looking for is a command like `drush ups` but without all the modules that are `[OK]` – so when used with an alias of several sites I don't have to scroll through loads. So all I get is:

```
aliasname
Name                               Installed Version  Proposed version  Message
     Metatag (metatag)                  7.x-1.19           7.x-1.20          Update available
     Views Slideshow (views_slideshow)  7.x-3.4            7.x-3.5           Update available

```

I found `drush vset update_check_disabled 1 -y && drush -n -p up` – it works but here's a sample output, which is not what I want.

```
media_ckeditormedia_ckeditormedia_ckeditor
views_slideshowmedia_ckeditor

```

I also want the version info. Is there anything I can do to get a list of all modules which need an update including the version info?

# Answer
> 11 votes
Drush puts that \[ok\] information out on stderr. So you can actually just dump that by using:

```
drush ups 2>/dev/null

```

which for me gave:

```
 $ drush ups 2>/dev/null
 Name    Installed Version  Proposed version  Message
 Drupal  8.2.5              8.2.6             Update available

```

# Answer
> 7 votes
Consider using '**grep**'. It's not exactly a drush-specific command but will get the job done.

```
drush ups | grep 'Update available'

```

This command will return all lines that contain the phrase 'Update available'.

# Answer
> 7 votes
In a Drupal 8 project it's better to list updates using `composer`:

```
composer outdated 'drupal/*'

```

# Answer
> 6 votes
If your site is built with Composer you can use `drush pm:security`.

> Check Drupal Composer packages for pending security updates.
>
> This uses the Drupal security advisories package to determine if updates are available.

This will give you the following sample output:

> ```
> +-------------+-------------------+-------------------+
> | Name        | Installed Version | Suggested version |
> +-------------+-------------------+-------------------+
> | drupal/core | 8.6.7             | 8.6.10            |
> +-------------+-------------------+-------------------+
>
> ```

# Answer
> -1 votes
Using `drush pm:security`, you can automatically update your website using the BASH code:

```
SECURITY_UPDATES=$(drush pm:security --field=name | tr '\n' ' ')
SECURITY_UPDATES=${SECURITY_UPDATES//drupal\/core/drupal\/core-recommended}

composer update $SECURITY_UPDATES --with-dependencies

```

---
Tags: drush
---


# Question
Title: How would I disallow special characters in usernames?
By default, Drupal 9 allows usernames to have spaces, periods(.), hyphens(-), apostrophes('), underscores(\_) and @ symbols.

How would I **disallow** spaces, periods, apostrophes and @ symbols?

# Answer
> 2 votes
I used the Username Validation module suggested by Patrick Kenny in his comment. The *Blacklist characters* field shown by the module on /admin/config/people/user-name-validation did the trick.

---
Tags: forms, users
---


# Question
Title: How to attach a library to a specific block
I wonder how to attach a library to a specific block. I do this:

in mytheme.libraries.yml

```
   lib-name-script:
      js:
        header: true
        js/masonry.pkgd.min.js: {}
        js/main.js: {}
      dependencies:
        - core/jquery

```

in main.js

```
jQuery(document).ready(function() {

    $('.grid').masonry({
        itemSelector: '.grid-item',
        columnWidth: 220,
        horizontalOrder: true
    });
});

```

and in views-view--block-some.html.twig

```
{{ attach_library('theme_name/lib-name-script') }}

<div class="grid">
    {{ rows }}
</div>

```

But from some reason this dont works. :S

On the and of file I have:

```
<script src="/themes/theme_name/js/masonry.pkgd.min.js?oxcmsf"></script>
<script src="/themes/theme_name/js/main.js?oxcmsf"></script>

```

Was I corect load js, or mistake is on some other place?

# Answer
Using the **hook\_preprocess\_block()** we can attach the library in the specific block.

```
function hook_preprocess_block(&$variables) {
  if ($variables['elements']['#id'] == 'YOURBLOCKID') {
    $variables['#attached']['library'][] = 'custom/global-styling';
  }
}

```

Add it in your custom module.

YOURBLOCKID - block id. get it form var\_dump($variables\['elements'\]\['#id'\]);

custom/global-styling - Your custom library
> 2 votes

# Answer
It sure looks like you are on the right track to me. I've used the same approach myself. See: https://github.com/vegantriathlete/presentation/blob/master/templates/node--slide--full.html.twig

Have you cleared the cache? Maybe the theme registry needs to be updated to reflect the template you are using.

Have you viewed the page source of the page when that block is visible to see if the javascript is being included? Maybe the javascript is being attached and you've got a bug in your main.js. You aren't following the pattern of how to attach javascript. see: https://www.drupal.org/docs/8/api/javascript-api/javascript-api-overview
> 1 votes

# Answer
The problem was in main.js This solve my problem. Thank you vegantriathlete for help.

```
(function ($) {

    $('.grid').masonry({
        itemSelector: '.grid-item',
        columnWidth: 220,
        horizontalOrder: true
    });

})(jQuery);

```
> 0 votes

---
Tags: 8, theming
---


# Question
Title: Multiple aliases per node (and active trail)
Our site is split down the middle for tenants and landlords. But we have content the is the same for both such as "how to report antisocial behaviour".

User would normally navigate something like "Home \> Tenant \> ASB" or "Home \> Landlord \> ASB".

Duplicating content obviously isn't good, but we aren't worried about SEO, we are worried about maintainablity and context for the user.

So, I looking for a way to provide 2 aliases for a piece of content, and have the active trail show accordingly.

I found this, which suggest that symfony should be able to handle it, but I can't find how I would make it work in Drupal.

I can add a second alias, but I always get forwarded to the last one entered.

# Answer
> 0 votes
A simple solution is to create Content Type, say 'delegated', with a single node reference field. Then, configure the reference field to point nodes of the content you want to be duplicated. Configure this field to show the referenced node as full node view (or whatever View mode you prefer).

This way:

* You can create independent pages with their own title, breadcrumb, alias, metadata, etc, but same content (if they reference the same node).
* Editors are able to update/create those 'delegated' node easily (they are just a node).
* As reference field can be limited by a View, you can narrow the contents available to be referenced in a powerful way.

As all are nodes, you can even create admin views to see with contents are related, or any other node available operation.

The main drawback is if you have configurations in referenced nodes that you want to be in the referencer node (say metatags). This could be solved using a custom module (updating referencer metatags when referenced node is updated) or manual copy-paste (ugly).

# Answer
> 0 votes
If you are not worried about SEO (as you wrote), you can just create a duplicate of the page.

The other way is to use the Redirect module. With this module, you'll be able to add many redirects to the same page (but they'll direct a user to the main page URL).

---
Tags: 8, routes, path-aliases, navigation
---


# Question
Title: What does "The provided host name is not valid for this server" mean?
I am running a Drupal 8 website, and when I browse to any page, I get a plain white page with just the following error message on it.

> The provided host name is not valid for this server.

What does this mean? How do I fix this?

# Answer
This error message is coming from a feature that was added to Drupal 8 to protect against HTTP Host header attacks. The feature is also described in the change record that was generated for the patch.

Essentially, it was possible to spoof the HTTP Host header for nefarious purposes, and trick Drupal into using a different domain name in several subsystems (particularly link generation). In other words, the HTTP Host header needs to be considered user input, and not trusted.

To combat this, a new setting, `$settings['trusted_host_patterns']`, was added to Drupal 8 to configure a list of "trusted" hostnames that the site can run from. The setting needs to be an array of regular expression patterns, without delimiters, representing the hostnames you would like to allow to run from.

For example, if you are running your site from a single hostname "www.example.com", then you should add this to your settings (usually found at `./sites/default/settings.php`):

```
$settings['trusted_host_patterns'] = array(
  '^www\.example\.com$',
);

```

Note the `^`, `\.`, and `$`. These are PCRE Syntax. These just mean that you want to match "www.example.com" precisely, with nothing extra at the beginning and end, and that the dots should be treated as dots and not wildcard characters.

If you are running from "example.com", then just use:

```
$settings['trusted_host_patterns'] = array(
  '^example\.com$',
);

```

If you need to run a site of multiple domains and/or subdomains, and are not doing canonical URL redirection, then your setting would look something like this:

```
$settings['trusted_host_patterns'] = array(
  '^example\.com$',
  '^.+\.example\.com$',
  '^example\.org',
  '^.+\.example\.org',
);

```

This allows the site to run off of all variants of example.com and example.org, with all subdomains included.

Once you adjust `$settings['trusted_host_patterns']` to the proper value, you should be able to browse to your site again.

You can also check on the status of your trusted host settings from the status report page, which is at admin/reports/status

If you remove the setting altogether, the trusted host mechanism will not be used, and you will see an error on the status report page. In addition, your site may also be vulnerable HTTP Host header attacks.

If you have this setting configured and are seeing this message, then it probably means you have messed up the regular expression syntax. In this case, take the first example, and copy/paste into your settings, and then edit it to reflect the hostname your site runs from.
> 113 votes

# Answer
This happens because `trusted_host_patterns` variable in your settings file. If you're working on the local environment and you want to override this, define the following section in your `settings.local.php` file:

```
/*
 * Drupal Trusted Host Patterns
 */
$settings['trusted_host_patterns'] = [];

```

Or more generic pattern:

```
$settings['trusted_host_patterns'] = [ '.*' ];

```

Or more specific for the local environments:

```
$settings['trusted_host_patterns'] = array(
  '^172\.20.\0.\3$',
  '^localhost$',
);

```

It's the simplest solution, but not recommended as you should set the proper values to avoid spoofing the HTTP Host header for nefarious purposes. If your website is running only on your local, then you should be fine.

See: New setting for trusted hostname configuration.
> 12 votes

# Answer
For a multisite installation please make sure you have the file /sites/sites.php , or you keep getting this error even if all the config is set up properly.
> 1 votes

# Answer
I encountered this problem on a Debian Apache2 host after installing Drupal 9 with composer. Adding the trusted host line did not resolve the issue.

Instead, what I had to do was add a ServerAlias directive in my Apache2 config. Adding a site alias was mentioned in the comments of the accepted answer, but since that is a little buried, I wanted to post this answer here for anybody who was coming to this issue who still had problems.

```
$ head /etc/apache2/sites-enabled/unleashed.conf
<VirtualHost *:80>
    ServerName unleashed.local
    ServerAlias unleashed.local
    ServerAdmin webmaster@host
    ...

```
> 0 votes

---
Tags: 8, configuration
---


# Question
Title: "Access denied" Error on clicking user/reset link
I am a Drupal newbie, so pardon any errors in my question. In my D9 site I am using password policy module to set password policy rules. When I hit "Reset password" I get a one-time link to my email. Upon clicking the link, it shows "Access Denied"-You are not authorized to access this page error. The log shows below error message:

```
"Path: /user/reset/10. Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException: in Drupal\user\Controller\UserController->getResetPassForm() (line 186 of /var/www/html/web/core/modules/user/src/Controller/UserController.php)."

```

Reset password link is as below:

```
https://mysitedomain/user/reset/10/1644339844/Xglx63gun5qPwmUzv2BEBZPLBUmH-eW0ekVEndy4_1M

```

Any help on how this can be fixed? The user I'm trying to reset the password is active.

# Answer
> 1 votes
I fixed this issue by removing samesite attribute from php.ini. I had it set as "Strict" to comply with OWASP requirements. But Strict means that if you click on a link on foo.org that goes to drupal.org, then you would *not* send the session cookie and you would not be logged in. Which is why I was getting to see "Access Denied" errors constantly.

---
Tags: users, 9
---


# Question
Title: Create configuration storage programmattically for list_string
On a paragraph type, I have a field I want to migrate to a new field of type "list\_string". To do that in the deployment and like our automatic deployment begin by an update of the database follow by importation of configurations, I want to create the new field programmatically before to do the migration in another hook\_update.

I'm using the example of this article https://www.metaltoad.com/blog/programmatically-importing-drupal-8-field-configurations which is perfect except I have a problem because my new field is of type list\_string. My configuration for field.storage is:

```
langcode: fr
status: true
dependencies:
  module:
    - options
    - paragraphs
id: paragraph.field_types_link
field_name: field_types_link
entity_type: paragraph
type: list_string
settings:
  allowed_values:
    -
      value: anchor
      label: Ancre
    -
      value: internal
      label: Interne
    -
      value: external
      label: Externe
  allowed_values_function: ''
module: options
locked: false
cardinality: 1
translatable: true
indexes: {  }
persist_with_no_fields: false
custom_storage: false

```

When I create my new field based on my configuration file like that:

```
$field_storage_link = \Drupal::service('config.storage.sync')->read('field.storage.paragraph.field_types_link');

\Drupal::entityTypeManager()->getStorage('field_storage_config')
  ->create($field_storage_link)
  ->save();

```

I have this error.

> \[error\] The configuration property settings.allowed\_values.0.label.0 doesn't exist.

If I remove the list of allowed\_values, it works and I can add my field to paragraphes bundles but in this case, I'm not able to do my migration properly because the allowed\_values of my field are empty and I don't know how to update it programmatically. Someone can explain what's is the problem in my code and how to fix it?

# Answer
> 2 votes
I finish by find what was the problem. When I read the config file, my allowed value are of format:

```
[
  [
    'value' => 'anchor',
    'label' => 'Anchor'
  ],
  [
    'value' => 'internal',
    'label' => 'Internal'
  ],
  [
    'value' => 'external',
    'label' => 'External'
  ]
]

```

But the FieldStorageConfig wait a format:

```
[
  'anchor' => 'Anchor',
  'internal' => 'Internal',
  'external' => 'External'
]

```

So I add a transformation before to save my new field:

```
$field_storage_link = \Drupal::service('config.storage.sync')->read('field.storage.paragraph.field_types_link');

$allowed_values_link = [];

foreach($field_storage_link['settings']['allowed_values'] as $value) {
  $allowed_values_link[$value['value']] = $value['label'];
}

$field_storage_link['settings']['allowed_values'] = $allowed_values_link;

\Drupal::entityTypeManager()->getStorage('field_storage_config')
      ->create($field_storage_link)
      ->save();

$field_type_link = \Drupal::service('config.storage.sync')->read('field.field.paragraph.link_tdm.field_types_link');

\Drupal::entityTypeManager()->getStorage('field_config')->create($field_type_link)->save();

```

It works properly.

# Answer
> 0 votes
For others with the same issue, see this important comment by Berdir at https://www.drupal.org/project/drupal/issues/2944144#comment-12481021 saying:

> That's not the correct way to create a config entity from config. Here's a snippet based on what I did just today:

```
  $module_handler = \Drupal::moduleHandler();
  $config_storage = new FileStorage($module_handler->getModule('yourmodule')->getPath() . '/config/install');

  foreach (['field.storage.user.field_name', 'field.field.user.user.field_name'] as $config_name) {
    $config_record = $config_storage->read($config_name);

    $entity_type = \Drupal::service('config.manager')->getEntityTypeIdByName($config_name);
    /** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $storage */
    $storage = \Drupal::entityTypeManager()->getStorage($entity_type);
    $entity = $storage->createFromStorageRecord($config_record);
    $entity->save();
  }

```

> The important part is "$entity = $storage-\>createFromStorageRecord($config\_record);", the config structure and config entity structure doesn't always match 1:1.

I can confirm this solved the problem for me with the same error.

---
Tags: 8, entities, configuration, deployment
---


# Question
Title: How can I migrate the values from a multi-value D7 taxonomy term reference field into a D9 field?
I have a node migration using the *d7\_node* source plugin.

I'm trying to migrate the values of a multi-value taxonomy term reference field into a multi-value taxonomy reference field in D9. There is a separate migration to import the taxonomy terms that works great.

In my node migration, I have something like:

```
field_my_tax_field:
  plugin: migration_lookup
  migration: my_taxonomy_migration_id
  source: field_my_d7_tax_field

```

However, this throws an exception and the migration fails. When I throw a breakpoint in *Drupal\migrate\Plugin\migrate\process\MigrationLookup::transform()* (where the exception is thrown), I can see that the value being passed is an array, but the lookup plugin wants a scalar value. The array passed is something like:

```
['target_id' => 123]

```

With this info, I can make this work by updating my migration config with something like:

```
field_my_tax_field:
  - plugin: callback
    callable: reset
    source: field_my_d7_tax_field
  - plugin: migration_lookup
    migration: my_taxonomy_migration_id

```

Using `reset()` like this feels loose. And it seems weird that this extra step is necessary, this seems like use-case #1 for the migration\_lookup function.

What am I missing? How can I do this in a better way?

# Answer
One option is to use the *Drupal\migrate\Plugin\migrate\process\SubProcess* (sub\_process) plugin:

> Runs an array of arrays through its own process pipeline.
>
> The sub\_process plugin accepts an array of associative arrays and runs each one through its own process pipeline, producing a newly keyed associative array of transformed values.

```
field_my_tax_field:
  plugin: sub_process
  source: field_my_d7_tax_field
  process:
    target_id:
      plugin: migration_lookup
      migration: my_taxonomy_migration_id
      source: target_id

```
> 1 votes

---
Tags: migrations
---


# Question
Title: Bibcite: How to sort publications by last name of first author?
Bibcite module: I have a view which shows all publications and I'm using the citation field. But every publication is shown as many time as many authors it has. When I'm using aggregation (count distinct) on one of the sorting items only one publication per year is shown. Also sorting the list by "Contributor: Last name" doesn't work. What is the "official" way to sort publications by the last name of the first author? I have tried so many things now, but I'm not able to get the desired result.

# Answer
The contributor field doesn't provide delta for sorting and filtering, so you have to apply a view hook to access the first last name: https://www.drupal.org/project/bibcite/issues/3182978
> 0 votes

---
Tags: views, 8
---


# Question
Title: FormAPI - Values of AJAX added fields missing from values array on submission
I'm using the Form API to create a form where I have multiple instances of a fieldset. Each fieldset contains the same fields, one for storing an email address and another for another bit of information. But essentially they're both textfields that use autocomplete which works fine. But I'm having an issue in the submission handler, described underneath my code below.

```
$form['authors_container']['authors_fieldset'][$i] = [
    '#type' => 'fieldset',
    '#attributes' => [
      'class' => ['author-fieldset']
    ],
    'email' => [
      '#type' => 'textfield',
      '#title' => 'Author email',
      '#value' => $emailValue,
      '#autocomplete_route_name' => 'discussion_papers.contact_email_lookup',
      '#attributes' => [
        'class' => ['author-email']
      ]
    ],
    'affiliation' => [
      '#type' => 'textfield',
      '#title' => 'Affiliation',
      '#value' => $affiliationValue,
      '#attributes' => [
        'class' => ['author-affiliation']
      ]
    ]
  ];

```

I then have an AJAX button for adding more instances of the above fieldset with its corresponding handler:

```
$form['authors_container']['add_author'] = [
  '#type' => 'submit',
  '#value' => 'Add another author',
  '#submit' => ['::AddAuthor'],
  '#limit_validation_errors' => [],
  '#ajax' => [
    'callback' => '::getAuthorsFields',
    'wrapper' => 'authors-container',
    'method' => 'replace',
    'disable-refocus' => true,
  ]
];

public function addAuthor($form, FormStateInterface &$form_state) {

    $storage = $form_state->getStorage();

    if (empty($storage['numOfAuthors']))
        $storage['numOfAuthors'] = 1;

    $storage['numOfAuthors']++;
    $form_state->setStorage($storage);

    $form_state->setLimitValidationErrors([]);
    $form_state->setRebuild();
}

```

All this works fine, I can add as many instance of the fieldset as I need. My issue is that when I submit the form, the values of only the very last fieldset are always empty in the `$form_state['values']` array, yet I can see the values in the `$form_state['input']` array. I understand that the input array is raw, unvalidated input and that the values array is validated, so my question is why are only the last set of textfields not validated? My validation handler doesn't remove any values.

# Answer
> 0 votes
Two possibilities:

1. You have added the additional fields in the #ajax callback function. As you didn't show which function your fields were defined in, this cannot be seen from your code. Drupal caches the form when building it, then when the form is submitted, it will strip any values not part of the original form definition for security purposes. The problem with adding fields in an #ajax callback function is that the form is cached previous to the callback function, and therefore Drupal discards the submitted values of the fields.
2. If the form element declarations are in fact within the form builder function and not part of an #ajax callback function, you probably need to add `#tree` to the fieldset, so as to create an array of values:

```
$form['authors_container']['authors_fieldset'][$i] = [
  '#tree' => TRUE,
  '#type' => 'fieldset',
  ...

```

This will save each of the submitted values to a separate element of the values array.

---
Tags: forms
---


# Question
Title: How to load content depending on screen size without hiding using CSS?
I have a responsive site. Lots of content is hidden depending on screen size.

This slows down page speed. And on slow devices has a lot of content shifting whilst content is hidden/shown.

In drupal 7 I used browser cap, to detect whether the browser was mobile or desktop and was able to not show blocks/content without having to hide them via CSS.

Is there a way in Drupal 9 to only have content loaded for certain devices, rather than use breakpoints and css to hide content?

Thanks

# Answer
https://github.com/serbanghita/Mobile-Detect/ lists a few Drupal modules in its README, one of the being Drupal 8/9 ready: Mobile Detect. Nice sets of features and even cacheability been taken care of.

> ### PHP
>
> ```
> $md = \Drupal::service('mobile_detect');
> $is_mobile = $md->isMobile();
> $is_tablet = $md->isTablet();
>
> ```
>
> ### Twig Extensions
>
> ```
> {% if is_mobile() %}
> {% if is_tablet() %}
> {% if is_device('iPhone') %}
> {% if is_ios() %}
> {% if is_android_os() %}
>
> ```
>
> ### About the cache contexts:
>
> By design, the "Internal Page Cache" core module assumes that all pages served to anonymous users will be identical, regardless of the implementation of cache contexts.
>
> If you want to use the mobile\_detect cache contexts to vary the content served to **anonymous** users, "Internal Page Cache" must be disabled, and the performance impact that entails incurred.
>
> More info: https://www.drupal.org/docs/drupal-apis/cache-api/cache-contexts
> 1 votes

---
Tags: theming, 9
---


# Question
Title: Set entity field to read-only after user input
I am using hook\_entity\_presave() to check some conditions and set field value. I would like to set the field to read-only after all conditions pass and the value is saved to database. Is it possible to achieve this or must I use another hook for this?

# Answer
I was able to achieve my result by using the following hook:

```
function check_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if ($form_id == "form_id") {
    $form['field_example']["#disabled"] = TRUE;
  }
}

```
> 0 votes

# Answer
Disable Field module is what you're looking for.

> Disable Field module help(s) you to disable the field of any content type ... based on Role selected By Admin.
> 0 votes

---
Tags: entities, hooks
---


title: Uploading a user picture with json:api

text:
# Question
Title: Uploading a user picture with json:api
I'm trying to craft a curl request to upload an image to the user\_picture field on a user entity using json:api.

The documentation is, umm, minimal, but I've used it as a starting point and I have this:

```
curl -s -X POST -b cookie.txt \
    --header "Accept: application/vnd.api+json" \
    --header "Content-type: application/octet-stream" \
    --header "X-CSRF-Token: $TOKEN" \
    --header "Content-Disposition: file: filename=test.jpg" \
    --data-binary "@test.jpg" \
    http://localhost/jsonapi/user/user/$UUID/user_picture

```

The response for this is "`No route found that matches \"Content-Type: application/x-www-form-urlencoded\"`".

What am I doing wrong?

# Answer
> 1 votes
As soon as I posted this I realised my issue, `Content-type` instead of `Content-Type`, duh!

---
Tags: 9
---


# Question
Title: Get field (list type) label in a twig template
I have a content type (*appel\_offre*) with a *field\_categorie\_avis* field, which is a list type with these values.

* ouvert | Ouvert toute l'année
* restreint | Restreint 24h
* concurrence | Appel public à concurrence

In the node--appel-offre.html.twig template, I want to print this field but I only get the key, not the value. For example, for *Appel public à concurrence*, I always get *concurrence*.

I am using `node.field_categorie_avis.value`. Is there another way to get the same value?

# Answer
You can use

```
{{ content.field_categorie_avis[0]['#markup'] }}

```

to display label.

Dont miss the `[0]` because drupal always store items in array in case of field size limit change.
> 10 votes

# Answer
Came across this same issue, none of the proposed solutions worked... in a node template what worked was:

```
node.field_myselect_list.fieldDefinition.itemDefinition.settings.allowed_values[node.field_myselect_list.value]

```
> 0 votes

---
Tags: theming, entities
---


title: How can I programmatically add users?

text:
# Question
Title: How can I programmatically add users?
How can I programmatically add users to an organic group?

# Answer
Something like the following should work; replace `$userId` & `$groupId` with approriate values

```
// Get a User entity via ID
$user = \Drupal\user\Entity\User::load($userId);

// Get a Group entity via ID
$group = \Drupal\group\Entity\Group::load($groupId);

// Add member and save
$group->addMember($user);
$group->save();

```

You can use the following to get the currently logged in userID

```
$userId = \Drupal::currentUser()->id()

```
> 1 votes

---
Tags: 9, organic-groups
---


# Question
Title: How to translate front but keep admin in FR
I have a website with translation by domain, ex :

* monsite.fr
* fr.monsite.ca
* en.moniste.ca ...

But in admin i'd like to stay on monsite.fr/admin whatever content that i translate, is it possible ?

Regards

# Answer
You need to make sure you have the following core multilingual modules enable

* Interface Translation (`locale`)
* Language (`language`)

I'll assume you have also added your desired languages on `/admin/config/regional/language`

On the `/admin/config/regional/language/detection` page you can set the language preference used by your site.

You will want to enable:

* Account administration pages \[X\]
* User \[X\]

Then under the admin account edit page, you can find `LANGUAGE SETTINGS | Administration pages language`. You will want to set this to your preference.
> 1 votes

# Answer
@tyler36 : thanks for your answer, i've done all this config but when i' m on admin content page when i click on translate i'm redirected to an other domain. Below my config detection url by domain (/admin/config/regional/language/detection/url) :

* FR : site.fr
* IT : site.it
* CA-EN : en.site.ca
* CA-FR : fr.site.ca.... when i want to translate a french page to italian when i click on the language i'm redirected to this edit page on dedicated domain BUT i want to stay on french admin BO whatever translation, is it clear ? :) is it possible ?

Regards
> 0 votes

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


# Question
Title: Override a CSS or JS file from the parent theme
Adding in the child theme a CSS file with the same name as the parent theme CSS file overrides the parent file. It doesn't seem to work JavaScript files.

How can I override a JavaScript file loaded from the parent theme?

# Answer
> 1 votes
You can use `hook_js_alter` to replace your JS file (from parent theme) with the one in your child theme.

```
function child_theme_name_doc_js_alter(&$javascript) {
  $javascript['themes/parent_theme_name/js/parent_theme_name_navigation.js']['data'] = drupal_get_path('theme', 'child_theme_name') . '/js/child_theme_name_navigation.js';
}

```

# Answer
> 0 votes
in the theme.info

```
libraries-override:
  parent_theme_name/library_name:
    css:
      base:
        ; deactivate a file
        css/parent_theme_name_language_switcher.css: false
    js:
      ; override a file
      js/parent_theme_name_navigation.js: js/child_theme_name_navigation.js

```

---
Tags: javascript
---


# Question
Title: How can i store a base64 image to my site's private folder?
I'm trying to store a base64 image from a Signature field plugin (the plugin outputs a base64 text). But before i can store it to the private folder, i have to first convert it as a png image. This is how i normally do it if i just upload an image:

```
    // Signature Field on FormBuilder
    $form['signature'] = [
        '#type' => 'managed_file',
        '#title' => $this->t('Signature'),
        '#upload_location' => 'private://requestformfiles',
        '#upload_validators' => [
        'file_validate_extensions' => ['png jpg',],
        ],
    ];

    // Pre-saving
    $image = $form_state->getValue('signature');
    $file = File::load( $image[0] );
    $file->setPermanent();
    $file->save();

```

But with a base64 image, i have to do this first:

```
    $image = $form_state->getValue('signature');
    $data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $image));
    file_put_contents('storage/signature.png', $data);

```

My problem is with `file_put_contents`. The save location is usually done in `'#upload_location'`, but i don't know how to do this in `file_put_contents`.

Any help is appreciated!

# Answer
> 1 votes
`file_put_contents` supports stream wrappers, so:

```
file_put_contents('private://path/to/storage/signature.png', $data);

```

---
Tags: webforms
---


title: Error on local clone (MAMP)

text:
# Question
Title: Error on local clone (MAMP)
I cloned a version of a Drupal 8.9.20 site to a local installation (MAMP PRO). That seemed to word, but when I call the site I get an error:

`The website encountered an unexpected error. Please try again later.`

With verbose error mode I get further:

```
Error: Call to a member function id() on bool in Drupal\Core\Entity\EntityStorageBase->setStaticCache() (line 188 of core/lib/Drupal/Core/Entity/EntityStorageBase.php).
Drupal\Core\Entity\EntityStorageBase->setStaticCache(Array) (Line: 311)
Drupal\Core\Entity\EntityStorageBase->loadMultiple(Array) (Line: 188)
Drupal\Core\Entity\EntityRepository->getCanonicalMultiple('node', Array, Array) (Line: 180)
Drupal\Core\Entity\EntityRepository->getCanonical('node', '236', Array) (Line: 149)
Drupal\Core\ParamConverter\EntityConverter->convert('236', Array, 'node', Array) (Line: 100)
Drupal\Core\ParamConverter\ParamConverterManager->convert(Array) (Line: 89)
Drupal\Core\Access\AccessManager->checkNamedRoute('entity.node.canonical', Array, Object, 1) (Line: 212)
Drupal\Core\Menu\DefaultMenuLinkTreeManipulators->menuLinkCheckAccess(Object) (Line: 92)
Drupal\Core\Menu\DefaultMenuLinkTreeManipulators->checkAccess(Array) (Line: 96)
Drupal\Core\Menu\DefaultMenuLinkTreeManipulators->checkAccess(Array) (Line: 96)
Drupal\Core\Menu\DefaultMenuLinkTreeManipulators->checkAccess(Array)
call_user_func(Array, Array) (Line: 148)
Drupal\Core\Menu\MenuLinkTree->transform(Array, Array) (Line: 56)
Drupal\pg_helper\BreadcrumbBuilder->build(Object) (Line: 47)
Drupal\pg_fe_users\Theme\ThemeswitcherNegotiator::is_internal() (Line: 23)
Drupal\pg_fe_users\Theme\ThemeswitcherNegotiator->applies(Object) (Line: 67)
Drupal\Core\Theme\ThemeNegotiator->determineActiveTheme(Object) (Line: 405)
Drupal\Core\Theme\ThemeManager->initTheme(Object) (Line: 96)
Drupal\Core\Theme\ThemeManager->getActiveTheme() (Line: 43)
Drupal\Core\Cache\Context\ThemeCacheContext->getContext(NULL) (Line: 118)
Drupal\Core\Cache\Context\CacheContextsManager->convertTokensToKeys(Array) (Line: 307)
Drupal\Core\Render\RenderCache->createCacheID(Array) (Line: 66)
Drupal\Core\Render\RenderCache->get(Array) (Line: 109)
Drupal\Core\Render\PlaceholderingRenderCache->get(Array) (Line: 77)
Drupal\Core\Render\RenderCache->get(Array) (Line: 109)
Drupal\Core\Render\PlaceholderingRenderCache->get(Array) (Line: 137)
Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber->onRequest(Object, 'kernel.request', Object)
call_user_func(Array, Object, 'kernel.request', Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.request', Object) (Line: 127)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 191)
Drupal\page_cache\StackMiddleware\PageCache->fetch(Object, 1, 1) (Line: 128)
Drupal\page_cache\StackMiddleware\PageCache->lookup(Object, 1, 1) (Line: 82)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 70)
Drupal\pg_fe_users\StackMiddleware\PgPageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 708)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

```

What could be the reason? Any hints how to resolve this?

For your advice many thanks in advance!

## Solution:

The advice from @4k4 solved the problem:

Rebuilding the cache by `http://www.example.com/core/rebuild.php` removed the error message.

# Answer
> 2 votes
Rebuilding the cache by http://www.example.com/core/rebuild.php removed the error message.

See https://www.drupal.org/docs/user\_guide/en/prevent-cache-clear.html#s-using-the-rebuild-script

This is a quick fix to remove the cached page which prevents the site from loading. To find what is causing the error you could use the site in the state it is before the cache clear and xdebug the variables to find the boolean which is wrongly put in place of an entity.

---
Tags: caching
---


# Question
Title: How do i save a base64 decoded image to file_managed?
I'm trying to save my image to Drupal's `file_managed` table. However, my image is coming from base64 decode:

```
 $filename = "sign-".$user->id(); // returns "sign-1234"
 $image_raw = $form_state->getValue('signature'); // returns base64 string of png
 $data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $image_raw));
 $image = file_put_contents('private://requestformfiles/'.$filename.'.png', $data);

 $file = File::load($image); // does not get anything
 $file->setPermanent(); // fails
 $file->save();

 $result = $connection->insert('request_id')
        ->fields([
            ...
            'signature' => $image,
            ...
        ])
        ->execute();

```

From what i see, My file successfully uploads into the private files folder, and `image` returns a random 4 digit number. However, when setting it to `file_managed` in the Database, it fails, since `File::load` cannot see my `$image`.

Any help is again, appreciated.

# Answer
I actually didn't have to use `File` entity for this, what i actually needed was `file_save_data()`

```
$filename = "nrsign-".$user->id();
$files_data = preg_replace('#^data:application/\w+;base64,#i', '', $image_raw);
$file_data = base64_decode($files_data);
$file = file_save_data($file_data, "private://requestformfiles/".$filename.".png", FILE_EXISTS_RENAME);

echo $file->id();

```

`file_save_data` creates the file and saves a record in `files_managed` as well. `$file->id();` returns the `$fid` for the created file.
> 3 votes

---
Tags: database, webforms, files
---


# Question
Title: Use AJAX not working when view is rendered programmatically
I have a view that is being rendered like this

```
$view = Views::getView('view_id');
$view->setDisplay('block_1');
$view->execute();
$render = $view->render();
$html = \Drupal::service('renderer')->render($render);

```

The $html variable is being returned in the build method of a Block

```
public function build() {
    return array(
      '#theme' => 'theme_template',
      '#view' => $html,
    );
  }

```

Then being outputted in the twig file `{{ view }}`

The view is being rendered but the pagination does not use ajax instead it reloads the page with the query string ?page=1

I have found a similar question but this is for drupal 7: Use ajax not working in views block displayed programmatically

Thank you in advance!

# Answer
Try like this

```
public function build() {
    $view = Views::getView('view_name');
    $view->setDisplay('block_1');
    $view->execute();
    return [
        '#type' => 'view',
        '#name' => 'view_name',
        '#view' => $view,
        '#display_id' => 'block_1',
        '#embed' => TRUE,
        '#cache' => $view->getCacheTags(),
    ];
}

```

If not use Twig Tweak and on the block's or page's template file do

```
{{ drupal_view('view_name', 'block_1') }}

```

> Twig Tweak module provides a Twig extension with some useful functions and filters that can improve developer experience.
> 0 votes

---
Tags: 8, views
---


# Question
Title: How to hide Forums from anonymous users?
I installed Forum module.
So, I have 'Forums' link in 'Tools' menu corresponding to the path /forum defined in `forum.routing.yml` in which access is defined by `_permission: 'access content'`.
In my site, anonymous users are allowed to "View published content", so they can see the 'Forum' link.
I don't want anonymous users to be able to see forums and, therefore, the forum topics.
I thought to override the \_permission of `forum.routing.yml` but I don't know how to do that?
How can I do that?

Or is there another solution?

# Answer
> 1 votes
You can change the permission associated with a route doing what Altering existing routes and adding new routes based on dynamic ones / Altering existing routes says to do.

* Create a service that is tagged with `name: event_subscriber`
* The class implementing the service extends `RouteSubscriberBase`
* The service class defines its `alterRoutes()` method that in `RouteSubscriberBase` is an abstract method

In your case, the `alterRoutes()` method would be similar to the following one.

```
  /**
   * {@inheritdoc}
   */
  protected function alterRoutes(RouteCollection $collection) {
    if ($route = $collection->get('forum.index')) {
      $route->setRequirement('_permission', 'access forum pages');
    }
    if ($route = $collection->get('forum.page')) {
      $route->setRequirement('_permission', 'access forum pages');
    }
  }

```

Instead of *access forum pages*, you can use a different permission, including an existing one that you think it suits more.

# Answer
> 0 votes
You can use `role: authenticated user` instead.

# Answer
> 0 votes
Looking for a solution to the same problem, I found this alternative: https://www.drupal.org/project/group\_forum There is no documentation though.

The groups module documentation https://www.drupal.org/project/group/issues/2710909 says:

> Classes of a school website is a typical usecase of the Group module.
>
> With a teacher as the administrator, students as the members and the content as the learning material. Articles in the Group are created by the teacher and only visible to the students in the Group. Forums created in the Group are safe places to discuss the class as they are only accessible to the teacher and the students.

They are not working as private for me though.

---
Tags: 8, routes
---


title: Creating a form in a custom views field

text:
# Question
Title: Creating a form in a custom views field
I am working on a bit of functionality that allows a 'form' to be embedded in a custom views field on a view I am working on.

The view is a table list of 'request' entities. The very last column in the table for each row is a 'quick edit' form, that has a custom form with a few fields on it (depending on the entity displayed in the current row). I am trying to figure out how to build a custom views plugin/field that will let me render a working form. I know how to do the logic to show the needed fields conditionally, and know how to build a normal form, but I am not sure how to build one into a views field.

I used \`drush generate plugin-views-field' and I can render form elements in the render() method, but they don't actually do anything as a form isn't actually generated.

Would it be easier/possible to create a form inside module/src/Form (that accepts additional arguments), and render that form using formBuilder-\>getForm() or is there a way I can build and render the form inside of a views plugin?

The form needs to work via ajax, so that you can make the quick-edit without reloading the page.

Any help would be greatly appreciated.

According to the comments below, it looks like I can do something like:

```
$form = \Drupal::formBuilder()->getForm('Drupal\resume\Form\WorkForm');
$form->sub_id = id;
return $form;

```

To render the form, and then inside the formbuilder use the sub\_id variable to attach it to the ajax callback and wrapper element.

# Answer
Yes, for a Drupal form you need a form class processed by FormBuilder. You can place the resulting form build anywhere on the page, views fields are not different from other page elements like for example blocks. Tricky in your case is to have multiple instances of the same form on the page. Then you need unique form IDs, ajax wrappers and submit elements. See Using the same form more than once per page with AJAX callbacks

Also be aware that Views Ajax and Form API Ajax have different endpoints and using both together adds more to the complexitiy. See Enabling AJAX in Views breaks Form API AJAX button (Drupal 8)
> 2 votes

---
Tags: views, 9
---


# Question
Title: How can I overwrite existing file and keep same filename when uploading new
I have content type 'Document' and added the 'Upload document' field with type 'File' I want to replace file and update the node. I'm using below code

```
function custom_file_upload_form_alter(&$form, $form_state, $form_id) {
  if($form_id == "test_node_form") {
    $form['#submit'][] = 'custom_fileupload_submit';
  }
}

function custom_fileupload_submit(&$form, &$form_state) {
 $file = file_save_upload('field_document', array(
    'file_validate_extensions' => array('pdf'), // Validate extensions.
    'public://', FILE_EXISTS_REPLACE
  ));
  if ($file) {
    // Move the file, into the Drupal file system
    if ($file = file_move($file, 'public://', FILE_EXISTS_REPLACE)) {
      // Save the file for use in the submit handler.
      $form_state['storage']['file'] = $file;
    }
    else {
      form_set_error('file', t('Failed to write the uploaded file the site\'s file folder.'));
    }
  }
  else {
    form_set_error('file', t('No file was uploaded.'));
  }
}

```

Here file\_save\_upload() not working. I have debug the $file variable but it's print nothing.

# Answer
You can just use the Upload File Replace module to solve this use case instead of custom code:

> This is a small utility module that automatically stops Drupal from renaming new files upload via filefield CCK. When 2 files with the same name exist, the older files will be renamed.
> 2 votes

---
Tags: 7, files
---


title: How can I use a token in a mailto link?

text:
# Question
Title: How can I use a token in a mailto link?
I installed the *Token* and the *Token filter* modules.

I use a *mailto* link in the body of a block.

```
<a href="mailto:info@mydomain.com?subject=The subject I want&body=Can you send me my invitelink for [site:name] please?">info@mydomain.com</a>

```

The token isn't replaced by its value.

How can I use a token in that link?

# Answer
> 0 votes
Mark the "Replace tokens" checkbox as checked for the "Text Format" which you have chosen while creating the block. Text Format configurations can be found with this path admin/config/content/formats

---
Tags: 7, tokens
---


# Question
Title: Does the "Search keywords" exposed filter depend on the core search index?
If I create an exposed *Search keywords* filter for a view, does this functionality depend on the core search engine? Do I need to index the site at admin/config/search/pages for a *Search keywords* filter to work?

# Answer
> 0 votes
Yes, the "Search Keywords" filter depends on the core search engine.

---
Tags: 8, views, search
---


# Question
Title: Can routing use parameters already in the URL?
I'm actually using D9 to build a system with entities using sub-entities. The main entity system use the following path : /item/{item} Each sub entity is related to a main entity and use this path : /item/{item}/sub\_item/{sub\_item}

So to access the edit or delete form, the following pathes are required :

/item/{item}/sub\_item/{sub\_item}/edit /item/{item}/sub\_item/{sub\_item}/delete

For example : /item/1/sub\_item/4/edit

I declared the following route :

```
entity.sub_item.edit_form:
  path: '/item/{item}/sub_item/{sub_item}/edit'
  defaults:
    _entity_form: 'sub_item.edit'
    _title: 'Edit sub item'
  options:
    _admin_route: TRUE
    parameters:
      item:
        type: entity:item
        with_config_overrides: TRUE
      sub_item:
        type: entity:sub_item
        with_config_overrides: TRUE
  requirements:
    _permission: 'administer site configuration'

```

Edit and Delete links are generated by list builder from getOperations. The list builder is on the following route : /item/1/sub\_items (this is the "collection" to show the sub-items attached to main item).

I was hoping that the fact the current URL contained item/{item} can be directly re-used by the link generator, but it's not the fact...

> Symfony\Component\Routing\Exception\MissingMandatoryParametersException : Some mandatory parameters are missing ("item") to generate a URL for route "entity.sub\_item.edit\_form". in Drupal\Core\Routing\UrlGenerator-\>doGenerate() (line 181 of /core/lib/Drupal/Core/Routing/UrlGenerator.php).

I tried to build a specific htmlRouteProvider class for my sub-item entity class but in this case too, the routes are built when cache are cleared, and I don't have access to the item in the URL to set it...

So... My question is : I'm missing something to do it easily, or must I re-implement the "toUrl()" method of my sub-item entity class to include the new "item" parameter "on the fly" ?

Thanks in advance for any suggestion.

PS : it's the solution I have actually in my sub-item entity class :

```
  public function toUrl($rel = 'canonical', array $options = []) {
    $uri = parent::toUrl($rel, $options);
    $uri->setRouteParameter('item', \Drupal::routeMatch()->getRawParameter('item'));
    return $uri;
  }

```

But maybe a better solution can be found ?

# Answer
I would override `SubItem::urlRouteParameters()` and make this independent from the current route match so that the entity can build links on all pages:

```
  protected function urlRouteParameters($rel) {
    $parameters = parent::urlRouteParameters($rel);
    // assuming the parent relationship is a reference field
    $parameters['item'] = $this->parent->target_id;
    // if the reference field is in the parent you have to run an entity query
    return $parameters;
  }

```
> 2 votes

---
Tags: routes, 9
---


# Question
Title: How to stop cron process without rebooting my server?
I have tried the following:

```
drush php-eval "\Drupal::lock()->release('cron');"

```

This had no effect. I'm still seeing "Attempting to re-run cron" errors pile up in the log.

I also tried the mysql query:

```
DELETE FROM semaphore WHERE name = 'cron';

```

The query ran fine, but had no effect. I'm still seeing "Attempting to re-run cron" errors pile up in the log.

I also checked the processes:

```
ps aux | grep cron

```

I saw a number of Drupal-related cron processes, and killed them all.

I then repeated...

```
drush php-eval "\Drupal::lock()->release('cron');"

```

None of this has had any effect. I clear the log, and then new "Attempting to re-run cron" errors appear.

# Answer
> 0 votes
Check if the "Automated Cron" core module is enabled. If so, you'll find a setting at /admin/config/system/cron where you can set the so called poor man's cron (cron triggered by site traffic) to be executed "never".

If no other cron has been configured, like a server cron executing `drush cron` for example or external service that periodically visits the hashed cron URL (which can be found on the same page as the poor man's cron), setting poor man's cron to be executed "never" should then completely stop any cron running on your site.

---
Tags: 8, drush, cron
---


title: How can I remove PDF download button?

text:
# Question
Title: How can I remove PDF download button?
I am using the pdf\_reader module and showing my PDF on the node. Now, I am supposed to hide the download button. For this purpose, I wrote the below javascript file:

```
jQuery(document).ready(function($) {
  document.querySelector('#download').style.display = 'none';
});

```

It's also in my theme's libraries.yml file. The last thing I did was write a hook\_preprocess\_node implementation and put in the below code:

```
  $node = \Drupal::routeMatch()->getParameter('node');
  if ($node->getType() == 'e_dergi') {
    $variables['#attached']['library'][] = 'conference_lite/custom';
  }

```

But I can't hide the download button for the life of me. What else should I try?

# Answer
> 0 votes
If your theme name is fluffiness in "fluffiness.info.yml" add following lines

```
libraries:
  - fluffiness/global-scripts

```

in your file "fluffiness.libraries.yml" add following lines

```
global-scripts:
  version: 1.x
js:
  js/fluffiness.js: {}

dependencies:
  - core/jquery
  - core/drupal

```

in your file "js/fluffiness.js" add following code

```
(function (Drupal, drupalSettings, once) {
   Drupal.behaviors.hideElement = {
     attach: function (context, settings) {
      jQuery("#download").hide();
     }
   }
 } (Drupal, drupalSettings, once));

```

---
Tags: 8, javascript
---


# Question
Title: How to change the content moderation state in a custom submit handler?
I am trying to change the content moderation state from `draft` to `submitted` programatically. The Content Moderation module adds a field to content types with a dropdown to change the state, but I want to hide this field from users and instead show a custom submit handler that changes the form state.

I can change the default value of the moderation field with code like this:

```
  $form['moderation_state']['widget'][0]['state']['#default_value'] = "submitted";

```

But, how do I change the value for the content moderation field using `$form_state` in the submit handler?

```
  $form_state->setValue('moderation_state', 'submitted');`

```

does not work like it does for fields.

Here is the debug output for `kint($form['moderation_state']['widget'][0])`:

# Answer
To change the moderation state you need first to get the entity:

```
$entity = $form_state->getFormObject()->getEntity();

```

and then change the state:

```
$entity->set('moderation_state', 'submitted');

```

and save:

```
$entity->save();

```

All the code:

```
/**
 * Submit callback to submit for approval
 */
function draft2submit_callback(array &$form, FormStateInterface &$form_state) {
  // Getting the entity.
  $entity = $form_state->getFormObject()->getEntity();
  // Changing the moderation state.
  $entity->set('moderation_state', 'submitted');
  // Saving the entity.
  $entity->save();
}

```
> 5 votes

# Answer
I had to solve this problem too, and found two ways to do it:

**Option 1:**

Set the widget type to value, and set the default value to `submitted`. I also removed the current state message showing on the form

```
    /**
     * Implements hook_form_alter().
     */
    function your_module_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {

      // may want to do some checks here ...

      $form['moderation_state']['widget'][0]['current']['#access'] = false;
      $form['moderation_state']['widget'][0]['state']['#type'] = 'value';
      $form['moderation_state']['widget'][0]['state']['#default_value'] = 'submitted';
    }

```

Using Option 1 this could fail validation if the current moderation state doesn't have a transition to `submitted` for the current user.

**Option 2:**

Add a validation callback function, and set the value in there:

```
    /**
     * Implements hook_form_alter().
     */
    function your_module_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {

      // may want to do some checks here ...

      $form['moderation_state']['#access'] = false;

      if (isset($form['#validate'])) {
        array_unshift($form['#validate'], '_your_module_set_moderation_state_to_submitted');
      } else {
        $form['#validate'][] = '_your_module_set_moderation_state_to_submitted';
      }
    }

    /**
     * @param $form
     *   Nested array of form elements that comprise the form.
     * @param $form_state
     *   The current state of the form.
     */
    function _your_module_set_moderation_state_to_submitted(array &$form, \Drupal\Core\Form\FormStateInterface $form_state) {
      $form_state->setValue(['moderation_state', '0', 'value'], 'submitted');
    }

```

I found I needed to use a validation callback, as otherwise it would run the validation before attempting to set the value, this would fail the validation if I didn't have a transition configured for it to remain at the same moderation state.

The other thing to note with Option 2 is that by using `setValue` you add a validated value. Therefore depending on how you've configured your workflows that may not be a transition that is otherwise allowed.
> 4 votes

# Answer
I found a way to change the moderation state.

```
$node = \Drupal::routeMatch()->getParameter('node');
$moderation_state = $node->moderation_state->value;
$is_approver = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id())->hasRole('approver');

switch ($moderation_state) {
  case 'draft':
    if ($is_approver) {
      if (!empty($node->get('publish_on')->value)) {
        $form['moderation_state']['widget'][0]['state']['#default_value'] = 'scheduled_publish';
      }
      else {
        $form['moderation_state']['widget'][0]['state']['#default_value'] = 'draft';
      }
    }
    else {
      $form['moderation_state']['widget'][0]['state']['#default_value'] = 'draft';
    }
    break;
  case 'needs_review':
    if ($is_approver) {
      if (!empty($node->get('publish_on')->value)) {
        $form['moderation_state']['widget'][0]['state']['#default_value'] = 'scheduled_publish';
      }
      else {
        $form['moderation_state']['widget'][0]['state']['#default_value'] = 'draft';
      }
    }
    else {
      $form['moderation_state']['widget'][0]['state']['#default_value'] = 'draft';
    }
    break;
  case 'scheduled_publish':
    $form['moderation_state']['widget'][0]['state']['#default_value'] = 'scheduled_publish';
    break;
  default:
    $form['moderation_state']['widget'][0]['state']['#default_value'] = 'draft';
    break;
}

```
> 0 votes

---
Tags: 8, forms, workflows
---


title: How to get the base URL of a site

text:
# Question
Title: How to get the base URL of a site
My site is on http://drupal8.local/. How do I get the *drupal8.local* part of that URL?

`Url::fromRoute('<'current'>')` or `base_path()` returns the path parth of the URL; For example, for http://drupal8.local/a/b/c/d/e/f, they return '`/a/b/c/d/e/f'` when I just need to get `'drupal8.local'`.

How can I get that part of the URL?

# Answer
You can get the hostname, "drupal8.local", directly from the `getHost()` request:

```
$host = \Drupal::request()->getHost();

```

In some cases you might want to get the schema as well, fx `https://drupal8.local`:

```
$host = \Drupal::request()->getSchemeAndHttpHost();

```
> 114 votes

# Answer
There are some warnings about directly accessing the request object in this way in `\Drupal::request`:

```
 * Note: The use of this wrapper in particular is especially discouraged. Most
 * code should not need to access the request directly.  Doing so means it
 * will only function when handling an HTTP request, and will require special
 * modification or wrapping when run from a command line tool, from certain
 * queue processors, or from automated tests.
 *
 * If code must access the request, it is considerably better to register
 * an object with the Service Container and give it a setRequest() method
 * that is configured to run when the service is created.  That way, the
 * correct request object can always be provided by the container and the
 * service can still be unit tested.

```

Any form controller extending `\Drupal\Core\Form\FormBase` automatically has this dependency injected, and it may be accessed using:

```
$this->getRequest()->getSchemeAndHttpHost()

```

I think (but haven't tested) that a regular page controller extending `\Drupal\Core\Controller\ControllerBase` could provide the `request_stack` service by overriding the `\Drupal\Core\Controller\ControllerBase::create` function, and then setting a `$request` property in the constructor. This is described really well for forms, and the same process should apply for page controllers: https://www.drupal.org/docs/8/api/services-and-dependency-injection/dependency-injection-for-a-form.
> 10 votes

# Answer
If you'd like to do this with dependency injection and a service, then you can use RequestStack:

```
use Symfony\Component\HttpFoundation\RequestStack;

```

And define it like this:

```
protected $request;

public function __construct(..., RequestStack $request_stack) {
  ...
  $this->request = $request_stack->getCurrentRequest();
}

public static function create(ContainerInterface $container, ...) {
  return new static(
    ...
    $container->get('request_stack')
  )
}

```

And then declare it like this:

```
$this->request->getHost()
$this->request->getSchemeAndHttpHost()

```
> 10 votes

# Answer
Taking into account the "*warnings about directly accessing the request object in this way in \Drupal::request*" that *Shaun Dychko* mentioned, perhaps a good option to get the hostname is obtain it from the *$base\_url* global variable, with the help of php function *parse\_url*:

```
global $base_url;
$base_url_parts = parse_url($base_url);
$host = $base_url_parts['host'];

```
> 9 votes

# Answer
Code below is how core defines the `[site:url]` token. This works best in all cases for me in drupal 8 & 9:

```
$url_options = [
  'absolute' => TRUE,
  'language' => \Drupal::languageManager()->getCurrentLanguage(),
];
$site_url = Url::fromRoute('<front>', [], $url_options)->toString();

```
> 4 votes

# Answer
```
<?php
$url = \Drupal\Core\Url::fromUserInput('/', ['absolute' => TRUE])->toString();
?>

```
> 0 votes

# Answer
```
\Drupal::request()->getBaseUrl()

```
> 0 votes

---
Tags: 8, uri
---


# Question
Title: How to programmatically append a Paragraph to another Paragraph?
I have a node (e.g. a business "company") with a paragraph referenced field (suppose business "sector", with multiple fields). This paragraph has in its fields a reference to another paragraph (suppose "employee" with multiple fields, one of this is a reference to a taxonomy term). In a `hook_form_submit()`, with `$form` and `FormStateInterface $form_state` as parameters, I need to programmatically associate multiple employees paragraph to a sector paragraph.

```
...
$node = Node::load($id);
$sector = Paragraph::load($node->get('field_sector')->target_id);

/**
 * List of taxonomy terms loaded elsewhere.
 * I've added a custom elment to the select with "_all" employees
 * in order to associate programmatically all the employees to the $sector.
 *
 * @var array $employees
 */
foreach ($employees as $employee) {
    $paragraph = Paragraph::create([
        'type' => 'employee',
    ]);
    $paragraph->set('field_name', $employee->get('field_name')->value);
    $paragraph->set('field_age', $employee->get('field_age')->value);
    ...
    $paragraph->save();

    $sector->set('field_employee', $paragraph); // here I don't know how to append to the sector
    $sector->save();
}

```

I tried to associate each $employee to the $sector but with `$sector->set('field_employee', $paragraph);` syntax or with `$sector->appendItem($paragraph)`, that works for nodes, it doesn't work.

Is there a way to programmatically add one paragraph to another?

Visualizing the question, in the image below, when I save the entity with custom option "All employees" (`_all`) selected, I'd like to attach all the 4 paragraph employees associated to the "a selected sector" paragraph (removing `_all`).

Thanks in advance.

**EDIT 1**

I saw the suggested answer Programmatically append multiple paragraphs to entity reference field on node but it resolve how to attach a Paragraph to a `$node`, not a Paragraph to a Paragraph of the `$node`.

I've try also this:

```
$employee->setParentEntity($sector, 'field_of_reference');
$employee->save();

```

but still does not append the `$employee` to the `$sector`.

**EDIT 2**

I've try to follow the suggested posts but I can't figure how to adapt that code inside a `hook_form_submit()`.

Thanks anyway to all, I think its a bad construction on my code.

# Answer
> 1 votes
The problems start with how you load the paragraph. You can't load it like a stand-alone entity:

```
$sector = Paragraph::load($node->get('field_sector')->target_id);

```

Instead load it via the reference field:

```
$sector = $node->get('field_sector')->entity;

```

Then you can add newly created paragraphs without saving, also nested ones, and when you are ready you can save the parent entity.

See Create nested paragraphs programmatically

---
Tags: 9, paragraphs
---


# Question
Title: How do I get the un-truncated error message from dblog?
The "Recent log messages" is very handy to track down errors on sites. While this works great for errors in PHP code, it is often unhelpful for errors in Twig code. E.g. I've this error message in my log:

> User error: "attributes" is an invalid render array key in Drupal\Core\Render\Element::children() (Zeile 98 in /web/core/lib/Drupal/Core/Render/Element.php)
>
> #0 /web/core/includes/bootstrap.inc(346): \_drupal\_error\_handler\_real(256, '"attributes" is...', '/var/www/vhosts...', 98) #1 \[internal function\]: \_drupal\_error\_handler(256, '"attributes" is...', '/var/www/vhosts...', 98, Array)
>
> (47 more lines here)

This strack trace has 47 points, most of them from Drupal core. The error is obviously in my custom theme.

> #11 /web/core/lib/Drupal/Core/Theme/ThemeManager.php(384): twig\_render\_template('themes/custom/w...', Array)

Due this line I suspect one of my custom Twig templates is incorrect, but I can't figure out which one, due the truncated filename.

How can I get the full error message of one specific line in the stack trace? If I would know the full name of the file mentioned in line #11, it would greatly help me to fix my error.

# Answer
You are getting the result of PHP built-in backtracing. Drupal is using debug\_backtrace() for displaying and Exception::getTraceAsString was added for logging in Drupal 8.2.x. See the change record. The second one is a very fast and efficient backtracing method, it doesn't run out of memory when handling deeply nested code which is typically for Drupal rendering templates. However, it might not provide all information you are looking for.

If you need a fully working stack trace use Xdebug to catch the exception (no breakpoint needed).

https://marketplace.visualstudio.com/items?itemName=xdebug.php-debug
> 2 votes

---
Tags: debugging
---


# Question
Title: how to use an entity query to make a sortable table
I need to use an entity query such as this:

```
$query = \Drupal::entityQuery('node')
->condition('type', 'blog_post')
->sort('field');

```

$nids = $query-\>execute();

to make a table that is sortable in a custom module . I found instructions on how to do this with a normal query , (below) how can I make this work for this entity query

```
  $header = array(
  // We make it sortable by name.
  array('data' => $this->t('Name'), 'field' => 'name', 'sort' => 'asc'),
  array('data' => $this->t('Content')),
);

$db = \Drupal::database();
$query = $db->select('config','c');
$query->fields('c', array('name'));
// The actual action of sorting the rows is here.
$table_sort = $query->extend('Drupal\Core\Database\Query\TableSortExtender')
                    ->orderByHeader($header);
// Limit the rows to 20 for each page.
$pager = $table_sort->extend('Drupal\Core\Database\Query\PagerSelectExtender')
                    ->limit(20);
$result = $pager->execute();

// Populate the rows.
$rows = array();
foreach($result as $row) {
  $rows[] = array('data' => array(
    'name' => $row->name,
    'content' => '[BLOB]', // This hardcoded [BLOB] is just for display purpose only.
  ));
}

// The table description.
$build = array(
  '#markup' => t('List of All Configurations')
);

// Generate the table.
$build['config_table'] = array(
  '#theme' => 'table',
  '#header' => $header,
  '#rows' => $rows,
);

// Finally add the pager.
$build['pager'] = array(
  '#type' => 'pager'
);

return $build;

```

} }

# Answer
> 1 votes
EntityQuery doesn't appear to have the extend() function that this example relies on, so much of what's happening in the example will need to be done manually.

You can get the sort parameters from the request object

```
$sort_field = \Drupal::request()->query->get('order');
$sort_order = \Drupal::request()->query->get('sort');

```

With those, you can update your query to something like.

```
$query = \Drupal::entityQuery('node')
  ->condition('type', 'blog_post')
  ->sort($sort_field, $sort_direction);
$nids = $query->execute();
$nodes = \Drupal\node\Entity\Node::loadMultiple($nids);

```

Then use $nodes to build your $rows array as in the example.

# Answer
> 0 votes
EntityQuery have a tableSort() method that you can use to update the sorting from the URL parameters.

---
Tags: 8
---


# Question
Title: Cannot install bootstrap theme in drupal 8 via composer fresh install
I set up d8 site with:

`composer create-project drupal-composer/drupal-project:8.x-dev my_test_site --stability dev --no-interaction`

Then installed the db and drupal with: `drush site-install`

Fully working D8 (8.3.3) with no errors at all.

I go to curate the composer.json file with some themes and modules to play around with it to get familiar:

`composer require drupal/bootstrap`

When this command runs, it results in the following error:

> Could not find package drupal/bootstrap at any version for your minimum-stability (stable). Check the package spelling or your minimum-stability

Inside my composer.json (after install)

```
{
    "name": "drupal-composer/drupal-project",
    "description": "Project template for Drupal 8 projects with composer",
    "type": "project",
    "license": "GPL-2.0+",
    "authors": [
        {
            "name": "",
            "role": ""
        }
    ],
    "repositories": [
        {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        }
    ],
    "require": {
        "composer/installers": "^1.2",
        "cweagans/composer-patches": "^1.6",
        "drupal-composer/drupal-scaffold": "^2.2",
        "drupal/console": "~1.0",
        "drupal/core": "~8.0",
        "drush/drush": "~8.0",
        "webflo/drupal-finder": "^0.3.0",
        "webmozart/path-util": "^2.3"
    },
    "require-dev": {
        "behat/mink": "~1.7",
        "behat/mink-goutte-driver": "~1.2",
        "jcalderonzumba/gastonjs": "~1.0.2",
        "jcalderonzumba/mink-phantomjs-driver": "~0.3.1",
        "mikey179/vfsstream": "~1.2",
        "phpunit/phpunit": ">=4.8.28 <5",
        "symfony/css-selector": "~2.8"
    },
    "conflict": {
        "drupal/drupal": "*"
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
      "sort-packages": true
    },
    "autoload": {
        "classmap": [
            "scripts/composer/ScriptHandler.php"
        ]
    },
    "scripts": {
        "drupal-scaffold": "DrupalComposer\\DrupalScaffold\\Plugin::scaffold",
        "pre-install-cmd": [
            "DrupalProject\\composer\\ScriptHandler::checkComposerVersion"
        ],
        "pre-update-cmd": [
            "DrupalProject\\composer\\ScriptHandler::checkComposerVersion"
        ],
        "post-install-cmd": [
            "DrupalProject\\composer\\ScriptHandler::createRequiredFiles"
        ],
        "post-update-cmd": [
            "DrupalProject\\composer\\ScriptHandler::createRequiredFiles"
        ]
    },
    "extra": {
        "installer-paths": {
            "web/core": ["type:drupal-core"],
            "web/libraries/{$name}": ["type:drupal-library"],
            "web/modules/contrib/{$name}": ["type:drupal-module"],
            "web/profiles/contrib/{$name}": ["type:drupal-profile"],
            "web/themes/contrib/{$name}": ["type:drupal-theme"],
            "drush/contrib/{$name}": ["type:drupal-drush"]
        }
    }
}

```

I've followed the solutions on Installing Bootstrap theme using Composer , but it seems all the answers are all defaults already in my installation unless i'm missing something?

I've tried several different combinations of versions available for the bootstrap theme and it's the same message every-time. I have also tried to change my overall projects stability with no luck.

I'm not too familiar with composer so I am assuming I am missing something small. Going through the documentation I am literally finding nothing to help solve this issue with composer. I have had no issues installing bootstrap before everything was on packages.drupal.org

Any ideas to why I cannot install bootstrap theme as a dependency or am I approaching this entirely wrong?

# Answer
Sounds like you're in the `<project_root>/web` folder. You need to be in `<project_root>` when using the Drupal Project to manage modules.

Just `cd ..` and run `composer require drupal/bootstrap` again, it should be fine.
> 3 votes

# Answer
Make sure you run `composer require` from the same directory that has your `composer.json` file.

The bootstrap module for a D8 site also requires a specific version. Try the following:

`composer require 'drupal/bootstrap:^3.23'`
> 0 votes

---
Tags: 8, composer
---


# Question
Title: How to define where to display form_state->setError when using multiple ajax callbacks?
I am working on some custom functionality inside of a views table view that enables a 'quick edit' form as an available field via views field plugin.

The form is rendered to each row separately using a unique sub\_id passed to the form builder for each row.

I have the form working, and it does the submit stuff correctly, but the problem is I need to do two things on ajax callback, so I am using the AjaxResponse() system to do two different actions.

The first action is updating the 'value' of a specific column in the views row. The second is essentially just doing return $form; to return the form.

The problem is, when the form does validation the validation works, except the messages do not show up until I refresh the page. I can't figure out how to tell it which wrapper to use to display the form message, as I am passing two different ones to the ajax response since I need to do two changes.

The code I am using inside of my ajax callback is this:

```
public function quickEditAjax(&$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();

    $response = new AjaxResponse();

    $status = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($values['status']);
    $response->addCommand(new ReplaceCommand('.request-status-'. $values['id'],$status->getName()));
    $response->addCommand(new ReplaceCommand('#quick-edit-wrapper-'. $this->sub_id,$form));

    return $response;
  }

```

In where `#quick-edit-wrapper-$this->sub_id` is the unique #id set on the form, and `.request-status-$values['id']` is the class attached to the table view column I am trying to change.

Both the form and the table column have the correct id and class on them, and the column updates successfully via the ajax addCommand() callback.

The validation error messages do not show up in either wrapper, but I would like it to show up in the `#quick-edit-wrapper` wrapper. If there are no validation errors and the submit goes through, I also pass a success message and that message doesn't show up either until I refresh the page.

Is there a way I can specifically tell the messages what wrapper to render in? The ajax response seems to be getting confused with which one to use.

# Answer
Add a status messages block to the form:

```
if ($form_state->hasAnyErrors()) {
  $form['status_messages'] = [
    '#type' => 'status_messages',
    '#weight' => -1000,
  ];
  $form['#sorted'] = FALSE;
}
$response->addCommand(new ReplaceCommand('#quick-edit-wrapper-' . $this->sub_id, $form));

```
> 1 votes

---
Tags: ajax, 9
---


# Question
Title: How can I display the NID in a views table template?
I want to take the NID field and display is as the row ID in a Views table. (I can then use that ID as an anchor to jump to the correct row in the table.)

However, I cannot for the life of me, find a way to 'print' the NID value in the views-view-table.html.twig template (I've changed the template name to match my view).

In a views-view-unformatted.html.twig template I've used the following (which works perfectly):

```
{{row.content['#row']._entity.nid[0].value}}

```

But that doesn't work in the table template.

Finding the correct syntax to print fields in different templates seems to be a mystery.

Thanks in advance for any help you can give.

# Answer
I have tried template\_preprocess\_views\_view\_table function. You may also try in your theme's YOURTHEMENAME.theme file to override as follow.

```
function YOURTHEMENAME_preprocess_views_view_table(&$variables) {
  foreach ($variables['rows'] as $num => $row) {
    $row['attributes']['id'] = $variables['rows'][$num]['columns']['nid']['content'][0]['field_output']['#markup'];
  }
}

```

As in above the screen you can see NID field in view is added as id of row in table. Although its showing spaces around nid but id is added further you can refine it as per your requirement.
> 0 votes

---
Tags: views
---


# Question
Title: Reverse proxy and auto_complete with mixed content
I have an apache configuration with reverse proxy (IP of this server: `192.168.1.82`) to handle my new D9 server:

**192.168.1.82 :** 443 is passed to 192.168.1.87 as HTTP(80)

```
<VirtualHost *:443>
    ServerName www.mydomain.be
    ServerAlias mydomain.be
    NameVirtualHost www.mydomain.be

    ProxyPreserveHost On
    ProxyPass / http://192.168.1.87:80/
    ProxyPassReverse / http://192.168.1.87/
    SSLProxyCheckPeerCN Off
    SSLProxyCheckPeerName Off
    SSLProxyVerify none
    ...
</VirtualHost>

```

I think it is called SSL Termination

**192.168.1.82 :** 80 is redirected as https (443)

```
<VirtualHost *:80>
    ServerName www.mydomain.be
    Redirect permanent / https://www.mydomain.be/
</VirtualHost>

```

**192.168.1.87 :** settings.php

```
$settings['reverse_proxy'] = TRUE;
$settings['reverse_proxy_addresses'] = [
  '192.168.1.82',
];
$_SERVER['HTTPS'] = 'on';
$settings['ssl'] = TRUE;

```

Unfortunately the autocomplete feature of an entity reference field request a non https (unsecure) endpoint (Mixed content):

```
http://www.mydomain.be/fr/entity_reference_autocomplete/node/default:node/3veI...I?q=t

```

What can I do to force the https... I will accept the most ugly hack if it is working (yes, I am here)

**Test 1**: ProxyPass https instead of http \[will not work, see below\]

I have adapted the 82 virtual host as follow;

```
SSLProxyEngine on
ProxyPass / https://192.168.1.87/
ProxyPassReverse / https://192.168.1.87/

```

=\>This time I don't have the mixed content problem, but I have `ERR_TOO_MANY_REDIRECTS` again for this entity autocomplete endpoint

**Test 2**: hack Symfony\Component\HttpFoundation\Request::isSecure()

Here is my new isSecure() function:

```
public function isSecure(){
  return TRUE;
}

```

By doing this, the autocomplete url use https, but this time, I got `ERR_TOO_MANY_REDIRECTS`

```
GET https://www.mydomain.be/fr/entity_reference_autocomplete/node/default%3Anode/3ve...I?q=T net::ERR_TOO_MANY_REDIRECTS

```

I have really no clue from where it can come

# Answer
Try to set X-Forwarded-\* headers in the Apache reverse proxy:

```
<VirtualHost *:443>
    ServerName www.mydomain.be
    ServerAlias mydomain.be
    NameVirtualHost www.mydomain.be

    ProxyPreserveHost On
    ProxyPass / http://192.168.1.87:80/
    ProxyPassReverse / http://192.168.1.87/

    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "443"

```

These are the headers which the reverse proxy configuration in settings.php needs.

You can check the presence of the headers at *www.mydomain.be/admin/reports/status/php* in the section **HTTP Headers Information**

---

In such a setup using X-Forward-\* headers is the general approach to allow Drupal to build absolute links with the correct protocol to avoid the mixed content error.

However, Drupal pages can be built completely with relative links and this is how Drupal is setup out-of-the-box, including core autocomplete fields. So you could review autocomplete routes in contrib/custom code and remove the `absolute` option to make them relative.

---

**Redirecting**

To avoid further commenting, Drupal doesn't redirect, out-of-the-box. Redirecting is not connected to the issue, it only makes it harder to debug. It's impossible to tell from afar which code you might have implemented which is redirecting. It could also be that the redirects are still cached, permanent redirects get cached for weeks, even if you have removed the redirect code.
> 2 votes

# Answer
The htaccess file in Drupal should be able to force all traffic as HTTPS. There are some comments in the file, but something like this should work (used in several projects):

```
  # Force all traffic to HTTPS, except a local instance
  RewriteCond %{HTTPS} off
  RewriteCond %{HTTP:X-Forwarded-Proto} !https
  RewriteCond %{HTTP_HOST} !^local\.dev\.domain$ [NC]
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

  # Modify the RewriteBase if you are using Drupal in a subdirectory or in a
  # VirtualDocumentRoot and the rewrite rules are not working properly.
  # For example if your site is at http://example.com/drupal uncomment and
  # modify the following line:
  # RewriteBase /drupal
  #
  # If your site is running in a VirtualDocumentRoot at http://example.com/,
  # uncomment the following line:
  # RewriteBase /

```

The third line is optional - it would exempt a local dev environment from the rewrite. If you use a local SSL, you can omit that line.

If Apache is serving all requests, it will pass through these rules, evaluate them and do the rewrite.

You can test rules here: https://htaccess.madewithlove.com/

Here is the test: https://htaccess.madewithlove.com?share=69ce1303-b1af-4041-aecf-a32f2ecd1bfb
> 1 votes

---
Tags: proxies
---


title: Upgrade a site from 8.5.13 to 9

text:
# Question
Title: Upgrade a site from 8.5.13 to 9
I've an old Drupal 8.5.x site. There are too many custom and contributed modules. We need to update the site to latest version of modules, Drupal core, and Composer.

What is the ideal way to approach the upgrade?
Should I directly try Composer 2 and require Drupal 9?
Should I update the code base in batches?
Should I do something else?

It also uses JSONAPI as contributed module, which is now a Drupal core module.
Is it fine to run `composer remove drupal/jsonapi` before updating Drupal core?
Should I be worried about its content?

# Answer
> 3 votes
*I've an older drupal 8 site in 8.5.x version. There are too many custom & contrib modules, eg acquia/blt, lightening, etc.*

OK, there is no simple answer to this. Check the Acquia site how to proceed with their no longer supported products.

But I'm trying to answer the other questions:

*We need to update the site to latest, modules, core, etc. It uses Composer 1. What is the ideal way to approach the upgrade?*

Keep Composer 1 until you have finished the update process and by doing this remove any packages which don't work with Composer 2.

*Should I directly try composer 2 and require drupal 9 or should I update the codebase in batches? eg first update to 8.9.20 and then to 9.x?*

You need to update to the latest Drupal 8 first and run `update.php`. This is in the release notes of Drupal 9. The reason is they removed older Drupal 8 update hooks and if you would update directly to Drupal 9 without running update.php on the latest Drupal 8 you are missing those update hooks and you can't get rid of the error message on the Status page no matter how often you are running the update script.

*It also uses jsonapi as a contrib module which i see is now merged to core drupal. Is it fine to simple composer remove drupal/jsonapi before update drupal/core? Should i be worried about its contents?*

JSON API doesn't have content and there is not much to configure. So you should be fine with un-installing the contrib module in Drupal before you remove it with Composer and then enable the core module.

# Answer
> 2 votes
If you haven't read it yet, here is the official documentation for upgrading from D8 to D9 : https://www.drupal.org/docs/upgrading-drupal/how-to-prepare-your-drupal-7-or-8-site-for-drupal-9/upgrading-a-drupal-8-site

To summarize:

* Update your core to the latest 8.x version (8.9.20)
* Update your contrib modules and dependencies to the latest compatible version and ensure these modules are compatible with D9 core (some may not be maintained anymore, for instance)
* Update your custom modules and themes to be compatible with Drupal 9 (I recommend you to use Upgrade status module to help you)
* Once you are done and your website runs smoothly, you may require the 9.x core.

It may be a cumbersome process, but if you respect the steps order, everything should go well.

Good luck :-)

---
Tags: 9, upgrading
---