# Question
Title: Composer not applying patch: exceeded the timeout of 300 seconds
Since my update to the new OSX (Ventura 13) I'm having problems using composer. The biggest problem I have is that my patches aren't patched and end up with and exceeded the timeout of 300 seconds after a while. I didn't change my composer.json file or the patches. This only occurs on my local site, the remote sites run smoothly.

What I tried to fix this is updating and reinstalling composer. I'm running composer 2.4.4. at the moment.

A regular `composer update` or `composer install` works like it should except when I have patches added to the composer.json file. I gets stuck running the patch.

When I do `ctrl+c` a few times the patch is being patched but is not added to the composer.lock file. I add it to the lock file by hand to have everything working but I want to fix this so I don't have to hack to get everything like it should.

I tried `composer install -v` but I'm not getting any further. The out put is as follows:

```
patch '-p1' --no-backup-if-mismatch -d 'public_html/core' < '/var/folders/k0/fk82ww894lvcgdkm2485dyww0000gn/T/638dea49da104.patch'
Executing command (CWD): patch '-p1' --no-backup-if-mismatch -d 'public_html/core' < '/var/folders/k0/fk82ww894lvcgdkm2485dyww0000gn/T/638dea49da104.patch'
File to patch:
   Could not apply patch! Skipping. The error was: The process "patch '-p1' --no-backup-if-mismatch -d 'public_html/core' < '/var/folders/k0/fk82ww894lvcgdkm2485dyww0000gn/T/638dea49da104.patch'" exceeded the timeout of 300 seconds.

```

One other thing I've noticed is that since the update I get this kind of messages: `composer/installers contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins Do you trust "composer/installers" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json)`

Because of this I looked at my composer file to see if the patch plugin is added and it is.

```
"allow-plugins": {
            "composer/installers": true,
            "drupal/console-extend-plugin": true,
            "cweagans/composer-patches": true,
            "drupal/core-composer-scaffold": true,
            "drupal/core-project-message": true
        }

```

What can I do to find out why the patch is not running and giving me a timeout? And has s the allowed-plugin part anything to do with this?

The full composer.json file contains:

```
{
    "name": "drupal-composer/drupal-project",
    "description": "Project template for Drupal 8 projects with composer",
    "type": "project",
    "license": "GPL-2.0-or-later",
    "authors": [
        {
            "name": "",
            "role": ""
        }
    ],
    "repositories": [
        {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        }
    ],
    "require": {
        "composer/installers": "^1.2",
        "cweagans/composer-patches": "^1.6",
        "drupal/addanother": "^1.1",
        "drupal/admin_toolbar": "^3.0",
        "drupal/advagg": "^4.0",
        "drupal/animated_gif": "^1.1",
        "drupal/antibot": "^2.0",
        "drupal/console": "^1.0.2",
        "drupal/core": "^9.0",
        "drupal/core-composer-scaffold": "^9",
        "drupal/core-project-message": "^9",
        "drupal/core-recommended": "^9",
        "drupal/ctools": "^3.0",
        "drupal/devel": "^4.1",
        "drupal/eck": "^1.0@alpha",
        "drupal/editor_advanced_link": "^1.4",
        "drupal/entity_type_clone": "^1.7",
        "drupal/entityqueue": "^1.1",
        "drupal/field_group": "^3.2",
        "drupal/gin": "^3.0@alpha",
        "drupal/gin_login": "^1.0",
        "drupal/gin_toolbar": "^1.0@beta",
        "drupal/honeypot": "^2.0",
        "drupal/httpswww": "^2.0",
        "drupal/login_destination": "2.x-dev",
        "drupal/login_history": "^1.0",
        "drupal/mailsystem": "^4.3",
        "drupal/metatag": "^1.5",
        "drupal/node_view_permissions": "^1.2",
        "drupal/override_node_options": "^2.4",
        "drupal/paragraphs": "^1.5",
        "drupal/pathauto": "^1.2",
        "drupal/rabbit_hole": "^1.0@beta",
        "drupal/recaptcha": "^3.0",
        "drupal/redirect": "^1.3",
        "drupal/redis": "^1.4",
        "drupal/restui": "^1.16",
        "drupal/smtp": "^1.0",
        "drupal/tablefield": "^2.0@alpha",
        "drupal/token": "^1.3",
        "drupal/user_current_paths": "^2.0",
        "drupal/user_restrictions": "^2.0",
        "drupal/video_embed_field": "^2.0",
        "drupal/views_data_export": "^1.0",
        "drupal/views_field_view": "^1.0@beta",
        "drupal/webform": "^6.0",
        "drupal/weight": "^3.3",
        "drush/drush": "^10.3",
        "symfony/var-dumper": "^5.1",
        "vlucas/phpdotenv": "^2.4",
        "webflo/drupal-finder": "^1.0.0",
        "webmozart/path-util": "^2.3"
    },
    "conflict": {
        "drupal/drupal": "*"
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
        "sort-packages": true,
        "allow-plugins": {
            "composer/installers": true,
            "drupal/console-extend-plugin": true,
            "cweagans/composer-patches": true,
            "drupal/core-composer-scaffold": true,
            "drupal/core-project-message": true
        }
    },
    "autoload": {
        "classmap": [
            "scripts/composer/ScriptHandler.php"
        ],
        "files": ["load.environment.php"]
    },
    "scripts": {
        "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": {
            "public_html/core": ["type:drupal-core"],
            "public_html/libraries/{$name}": ["type:drupal-library"],
            "public_html/modules/contrib/{$name}": ["type:drupal-module"],
            "public_html/profiles/contrib/{$name}": ["type:drupal-profile"],
            "public_html/themes/contrib/{$name}": ["type:drupal-theme"],
            "drush/Commands/{$name}": ["type:drupal-drush"]
        },
        "patches": {
            "drupal/core":{
                "Entity reference Fix": "https://www.drupal.org/files/issues/2019-03-26/user_cant_reference_unpublished_content-2845144-24.patch"
            },
            "drupal/token":{
                "Path Alias Language Fix - Token Issue": "https://www.drupal.org/files/issues/2019-03-14/2945272-8-token-language.patch"
            },
            "drupal/rules":{
                "Drupal Rules Fix": "https://www.drupal.org/files/issues/2725525-14.fatal_error_call_to_role_id.patch"
            },
            "drupal/recaptcha":{
                "Drupal Captcha Fix": "https://www.drupal.org/files/issues/2019-11-15/3035883-29-workaround.patch"
            }

        },
        "drupal-scaffold": {
            "locations": {
                "web-root": "public_html/"
            },
            "file-mapping": {
                "[web-root]/sites/development.services.yml": false
            }
        }
    }
}

```

Thanks a lot.

# Answer
> 18 votes
Thanks @cilefen for pointing me in the right direction. For me solution 423 of this thread fixed the problem: https://github.com/cweagans/composer-patches/issues/423#issuecomment-1301026697

The solution suggested in the comment by Mike Ohara is: *On that note, what seemed to fix this for me with additional testing was installing the gnu patch via homebrew. (https://formulae.brew.sh/formula/gpatch) `brew install gpatch` which installs patch GNU patch 2.7.6 After which, no issues with patches applying, including the one that failed for @dpi*

---
Tags: 9, composer
---


# Question
Title: Can users be forced to insert only plain text by default in CKEditor?
I know there is "Paste Text" button in CKEditor, and I can limit allowed HTML tags.
But it's very hard to explain clients to use specific button when they insert text.
As result they often insert "dirt" texts with HTML tags.

As I remember there was setting in early versions of CKEditor to force insert plain text by default but cannot find it in current version.

Is there any solution for the problem?

UPDATE: I don't want to restrict user to use some tags. But user should get "clean" plain text without HTML tags when insert text.

# Answer
You want to change the ckeditor configuration to always paste as plain text.

This defined in https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR\_config.html#cfg-forcePasteAsPlainText

It comes down to the following JavaScript configuration:

```
// All content will be pasted as plain text.
config.forcePasteAsPlainText = true;

```

Have a look here for where to set it Is there advanced configuration for CKEditor in Drupal 8?
> 2 votes

# Answer
Eventually I used module CKEditor custom config and set in custom configuration: `forcePasteAsPlainText = true`
> 1 votes

# Answer
You can use the Drupal module Paste Format to **force pasting as plain text**.

Two notes:

1. The original module is for Drupal 7. But in the issues is a module and **hints for Drupal 8||9**. The link above goes directly to this issue.
2. This module **only works for CKEditor 4** and therefore is not suitable for CKEditor 5 shipped with Drupal ^10. But it could work with the contributed module CKEditor 4 (not tested).
> 0 votes

---
Tags: 8, wysiwyg
---


# Question
Title: How to find unused or old twig template files?
There are times when fields are deleted from a Content type, but there is no way of knowing if there is a related field twig template without manually looking in our repository.

Other than looking for file names, are there any utilities or other methods to find twig templates that are not being used?

# Answer
> 2 votes
It's difficult to find a deterministic method, so you probably need some kind of usage statistics.

A simple statistical method would be to clear the twig php cache:

```
\Drupal\Core\PhpStorage\PhpStorageFactory::get('twig')->deleteAll();

```

Then run the site for some time and check the twig php cache (/sites/default/files/php/twig) for twig files not having a compiled php template.

# Answer
> 1 votes
You could use drush twig:unused for this:

```
drush twig:unused --field=template /var/www/project_name/docroot/modules/custom,/var/www/project_name/docroot/themes/custom

```

Crawl your site first. More information at the drush site here: https://www.drush.org/latest/commands/twig\_unused/

---
Tags: 8, theming, entities
---


# Question
Title: "InvalidArgumentException: Field taxonomy_vocabulary_15 is unknown"
I am trying to publish a *Related\_article\_link* node, but I get the following exception error.

> InvalidArgumentException: Field taxonomy\_vocabulary\_15 is unknown. in Drupal\Core\Entity\ContentEntityBase-\>getTranslatedField() (line 587 of /mnt/www/html/pllfahcvvibjg/docroot/core/lib/Drupal/Core/Entity/ContentEntityBase.php).

I tried running update.php, `drush cr`, and `drush updb`, but I am still getting that error.

# Answer
Mostly you lost a taxonomy term and there is a content piece in that page that is looking for the term. Taxonomies are not saved in configuration so If you updated your db or changed the environment and you haven't created that term you will get an error.
> 0 votes

---
Tags: taxonomy-terms
---


title: Add a download link to menu

text:
# Question
Title: Add a download link to menu
I am trying to add a link to a managed pdf file to the footer menu. Right now I am using a controller which uses a specific route in order to download the file:

```
// src/Controller/DownloadController.php
class DownloadController extends ControllerBase {
  public function downloadPdf() {
    $config = \Drupal::config('example.settings');
    $pdf = $config->get('pdf');
    if ($pdf) {
      $file = File::load($pdf[0]);
      $filename = $file->getFileName();
      header("Content-Type: application/pdf");
      header("Content-Disposition: attachment;filename=$filename");
      print file_get_contents($file->getFileUri());
    }
  }
}

// example.routing.yml
example.download:
  path: 'example/download'
  defaults:
    _controller: '\Drupal\example\Controller\DownloadController::downloadPdf'
    _title: 'Download PDF'
  requirements:
    _permission: 'access content'

```

After I have activated the module I added a new link named `Download PDF` to the footer menu. This link points to `example/download`, this seems to work, but I was wondering if there is a better approach. If possible, I would like to add the path to the file to new menu item instead.

# Answer
> 1 votes
For menu items, you can quickly configure the contributed menu\_link\_attributes module to include a download link attribute.

It's a 'low code' option if there ever was one; the module even has a user interface right on your site for customizing your configuration:

1. add the module: `composer require drupal/menu_link_attributes`
2. enable the module: `drush en menu_link_attributes`
3. visit the 'manage attributes' configuration page at /admin/config/menu\_link\_attributes/config
4. add the following lines to the end of the edit textarea (note the indentation; it should have 2 spaces in front of the first line and 4 in front of the second line):
```
  download:
    filename: ''

```
5. add a menu item in the menu of your choice (example using the main menu: /admin/structure/menu/manage/main/add)
6. in the 'attributes' section of the 'Add menu link' page, enter a filename in the 'download' textfield and save the new link with the other desired values
7. export your configuration to code: `drush cex`

Your new configuration should look something like the following:

```
attributes:
  class:
    label: ''
    description: ''
  download:
    description: 'Enter a name to assign to the file. Leave this field blank to exclude the download attribute.'
    filename: ''
  target:
    label: ''
    description: ''
    options:
      _blank: 'New window (_blank)'
      _self: 'Same window (_self)'
    default_value: ''

```

I've added a merge request to include the download attribute out of the box, tho I've also indicated it is a minor request. The MR implements the download attributed as described in MDN documentation.

---
Tags: 8, navigation, files
---


# Question
Title: How do I specify ALL source node types in upgrade_d7_node_complete_book migration yaml
Drupal migrate\_plus creates a default migration yaml for migrating books: upgrade\_d7\_node\_complete\_book.yml

```
langcode: en
status: true
dependencies: {  }
id: upgrade_d7_node_complete_book
class: Drupal\node\Plugin\migrate\D7NodeTranslation
field_plugin_method: null
cck_plugin_method: null
migration_tags:
  - 'Drupal 7'
  - Content
migration_group: migrate_drupal_7
label: 'Node complete (Book page)'
source:
  plugin: d7_node_complete
  node_type: book

```

As you see, the default source node\_type is "book". However, I would like to migrate ALL of my source content types to the Drupal 9 book content type. How do I configure this?

# Answer
> 0 votes
This is how it is done in d7\_node

```
 * @code
 * source:
 *   plugin: d7_node
 *   node_type: [page, test]
 * @endcode
 *
 * In this example nodes of type page and test are retrieved from the source
 * database.

```

I am assuming it holds true for d7\_node\_complete.

---
Tags: migrations
---


# Question
Title: Correct schema for an Entity Reference in config settings
### Background

I am creating a schema for a custom module's config settings, which are saved from a simple settings form. It has some basic fields, such as a checkbox for a Boolean value for hiding some data. However, it also has an entity reference field (e.g. `hide_data_terms`) that allows selecting taxonomy terms from a specific bundle `data_terms`. It will save the term IDs to the settings YAML.

Here's my attempt at a **my\_module.schema.yml** so far:

```
my_module.settings:
  type: mapping
  label: Settings
  mapping:
    hide_data:
      type: boolean
      label: 'Hide Data'
    hide_data_terms:
      type: entity_reference_selection.default:taxonomy_term
      label: 'Hide Data for Terms'

```

### Problem

I'm not sure if `entity_reference_selection.default:taxonomy_term` is correct. Also, I have three terms saved from the settings page, and when using Config Inspector, it shows errors like this:

```
Name              | Label     | Type      | Value | Error
------------------------------------------------------------------
hide_data_terms.0 | Undefined | undefined | 1234  | missing schema
hide_data_terms.1 | Undefined | undefined | 2034  | missing schema
hide_data_terms.2 | Undefined | undefined | 3287  | missing schema

```

**my\_module.settings.yml** looks like this, with `hide_data_terms` containing an array of taxonomy term IDs:

```
hide_data: false
hide_data_terms:
  - 1234
  - 2034
  - 3287

```

What's wrong with the schema, if anything, or what should it be? I can't create a schema for each array element, because there can be any number of terms selected, or none of them.

### Another Question:

The settings YAML does not have a "default config hash" for some reason. Most config YAMLs have it. Is that needed, and why isn't that in there?

Edit: I found the answer to the default config hash question. That is only used when the config is added on module install. See ConfigInstaller.php and search for `default_config_hash`.

# Answer
> 4 votes
Using `entity_reference_selection.default:taxonomy_term` type is incorrect as this config is used for field settings in the Entity reference type fields.

It is defined in the `core/config/schema/core.data_types.schema.yml` as `entity_reference_selection.default:*`.

So if you replace this type in your configuration with its definition it would look like this:

```
my_module.settings:
  type: mapping
  label: Settings
  mapping:
    hide_data:
      type: boolean
      label: 'Hide Data'
    hide_data_terms:
      type: mapping
      label: 'Hide Data for Terms'
      mapping:
        target_type:
          type: string
          label: 'Type of item to reference'
        target_bundles:
          type: sequence
          label: 'types'
          nullable: true
          sequence:
            type: string
            label: 'Bundle'
        sort:
          type: mapping
          label: 'Sort settings'
          mapping:
            field:
              type: string
              label: 'Sort by'
            direction:
              type: string
              label: 'Sort direction'
        auto_create:
          type: boolean
          label: 'Create referenced entities if they don''t already exist'
        auto_create_bundle:
          type: string
          label: 'Bundle assigned to the auto-created entities.'

```

Which is why you are getting the missing schema error.

As pointed out by @unusedspoon in the comment, you should use the sequence type for specifying an array of values.

The correct schema would look like this:

```
my_module.settings:
  type: mapping
  label: Settings
  mapping:
    hide_data:
      type: boolean
      label: 'Hide Data'
    hide_data_terms:
      type: sequence
      label: 'Hide Data for Terms'
      sequence:
        type: integer
        label: 'Term ID'

```

---
Tags: entities, 9, configuration
---


# Question
Title: Customize "view modes" and "form modes" based on role
Drupal 8 has extended the *View Modes* concept to *Form modes*

1. Is it possible to assign a role to both "View Modes" and "Form Modes"?
2. How does one assign a mode both view mode or form mode to be shown at a particular place ? Say I wish to Full content view mode shown at certain page and Teaser view mode show in a block at another location. Similarly I want form mode A show during create and form B during edit.

For example there is a content type with following Fields

* Title : displayed publicly, editable by author
* Body : displayed publicly, editable by author
* Project code : Not displayed publicly, displayed and editable by author
* System code : only visible/editable by admin

Essentially this could be an interesting and performant way to implement field permissions. The field permissions module has no port for Drupal 8 yet.

# Answer
Nothing in core uses form modes - it's an API waiting for contrib to make use of. This, and the question of when to manipulate form fields and when form modes, is discussed at: https://www.drupal.org/node/2530086.

There Berdir says "Showing/Hiding fields but keep them otherwise the same is IMHO a perfect use case for hook\_entity\_field\_access() not switching out the form display. I'd only try to do something like \[switching form mode\] when you want to show different widgets based on the user roles."

In general, managing display differently for different roles is easy, managing forms differently is more difficult.

Alternatives to the field permissions module for managing display (NOT forms):

The classic answer might be that this is a job for the Panels family, but it's mostly not quite ready for D8. Page manager is however quite usable and does much of what you want. For specifically created pages, it can control the content based on role. What it won't do is take over the rendering of all nodes of a certain content type.

Display suite is D8 ready, and allows you to show fields based on permissions by using token fields. See https://swsblog.stanford.edu/blog/using-display-suite-provide-field-level-permissions for a description of the procedure in D7, which is only cosmetically changed for D8.
> 2 votes

# Answer
Check out the Form Mode Control module.

> In Drupal 8, you can create "form modes" which are for any content entity a different organization of the form (show / hidden, order, form widget, etc.).
>
> Issue is that you can't actually use them except for register / edit profile.
>
> This module allows you :
>
> * To define access to each form mode for the different roles.
> * To define for each role, each bundle of each entity which form mode should be taken by default during the creation of the content and the edition. Of course you should grant access before defining this. If a user has multiple roles, the weight of the roles is taken into account (heaviest one).
> * To access any of them if you have the permission by adding a simple parameter node/add/article?display=form\_mode\_machine\_name.
> 2 votes

# Answer
After a lot of reading and pushing buttons, I was able to figure out how to add Custom "Form Mode" without using hooks or messing with API. As Berdir mention user.module is active for creating a custom form mode to display as needed, be it for user registration, profiling, etc.

What I did was "tricking" Drupal through url, like this: Go to /admin/structure/display-modes/form, where you will find that only User form modes can be added (/admin/structure/display-modes/add/user), the all you have to do is replace the /add/user part for /add/node or whatever entity type you wish.

Once you create a custom form mode display, it will "automagically" include the entity blocks you can find in Display modes, with their links and all...
> 1 votes

# Answer
It is also fairly easy to utilize this in a custom hook (inspired by Form Mode Control module): hook\_entity\_form\_display\_alter is your friend.

my\_module.module

```

// &$form_display is importent here, as the whole object is swapped out, not just modified
function my_module_entity_form_display_alter(EntityFormDisplayInterface &$form_display, array $context) {

  if (in_array('my_role', \Drupal::currentUser()->getRoles()) && $context['entity_type'] === 'node' && $context['bundle'] === 'my_node_type') {

    $storage = \Drupal::entityTypeManager()->getStorage('entity_form_display');
    $differentDisplay = $storage->load("{$context['entity_type']}.{$context['bundle']}.my_form_display"); // 'my_form_display' was created via /admin/structure/display-modes/form

    if ($differentDisplay) {
      $form_display = $differentDisplay;
    }
  }
}

```

The above example will display my\_node\_type form in the display 'my\_form\_display' for users with the role 'my\_role'.
> 1 votes

# Answer
There is a new module which gives us such functionality https://www.drupal.org/project/role.

> Base module features:
>
> Control user edit form mode per Role
>
> Control user full view per Role
>
> Sub modules:
>
> Role Appearance: Control site theme per user Role Role registration: add a new route 'user/register/{role\_id}' for specific role registration Add a new plugin type RoleConfigElement which allows add extra fields to Role.
> 0 votes

---
Tags: 8, users, forms
---


# Question
Title: How to add an ajax throbber to my theme?
I created a new theme based on Classy.

```
base theme: classy
core_version_requirement: ^8 || ^9

regions:
  header: 'Header'
  content: 'Content'
  footer: 'Footer'

libraries-extend: {}

libraries:
  - my_theme/global

```

```
global:
  version: VERSION
  header: TRUE
  js:
    dist/js/app.js: { minified: true }
  dependencies:
    - core/jquery
    - core/drupal
    - core/ajax
    - core/drupalSettings
    - core/jquery.once
  css:
    theme:
      dist/css/app.css: { minified: true }

```

No matter what I do - I don't get AJAX loading indication in my views or when infinite scroll loads. What am I missing?

What do I define in Drupal to show or use my own throbbing markup? Can't google this thing at all.

If I need to handle this myself in a new there is there any resources where I can read how to create a custom ajax throbber?

# Answer
Here is a way to insert some js logic **before** and **after** a Drupal Ajax request.

```
Drupal.Ajax.prototype.ajax_before_send_original = Drupal.Ajax.prototype.beforeSend;

Drupal.Ajax.prototype.beforeSend = function (xmlhttprequest, options) {
  Drupal.Ajax.prototype.ajax_before_send_original.call(this, xmlhttprequest, options);
  options.complete_original = options.complete;
  options.complete = Drupal.Ajax.prototype.options_complete;

  // BEFORE AJAX LOGIC
  // e.g. jQuery('.listing-ajax-overlay').addClass('active');
}

Drupal.Ajax.prototype.options_complete = function (xmlhttprequest, status) {
  this.complete_original.call(this, xmlhttprequest, status);

  // AFTER AJAX LOGIC
  // e.g. jQuery('.listing-ajax-overlay').removeClass('active');
}

```
> 0 votes

---
Tags: 9
---


# Question
Title: Migrate Module: How skip whole item (not value)
I have a xml file that creates nodes via migrate.

I need to define the following:

Each job has a field "location". I have written a process plugin to process the value When the returned value is "null" ... skip the row (not just the field - skip the whole job item) I thought I do it right by using this yml structure / script

```
process:

  _job_location:
    - plugin: process_job_location
      source: src_job_location
    - plugin: log

  field_job_location_ref:
    - plugin: skip_on_empty
      method: process
      source: _job_location

```

\_job\_location (the processor) returns "null" - still the whole item / node is created. Seems that skip\_on\_empty does just skip the field itself.

How to skip the whole creation of the node?

Thanks

# Answer
Using `method: process` in the plugin config will use the `process()` method in the plugin which throws a `MigrateSkipProcessException` when a field is empty and that will only skip the field.

Using `method: row` will use the `row()` method which throws a `MigrateSkipRowException` on empty field and the migration will skip the whole row.

So use `method: row` for the plugin config.
> 1 votes

---
Tags: migrations
---


# Question
Title: How can i add a class with 'html' tag(not with body) for specified pages (10 nodeID's)?
How can i add a class with 'html' tag(not with body) for some specified pages (10 nodeID's) ? I tried with html preprocess, but didn't worked,

# Answer
You can add `template_preprocess_html` to your module and add the classes via `$variables['html_attributes']['class']`.

Since this is `html.html.twig`'s preprocessor, it has no notion of what a Node is. It could also be rendering a non-node page (e.g. the user login). Some modules may add Node information to the variables, but there is no guarantee. To be safe, you'll have to check if the current route is a node and then check the IDs afterward.

```
function your_module_preprocess_html(&$variables) {
  if ($is_current_rout_is_a_node) {
    if ($is_this_the_right_node) {
      $variables['html_attributes']['class'][] = 'your class';
    }
  }
}

```
> 0 votes

# Answer
You can override html.html.twig in your theme as html--node--\[NID\].html.twig, and add the class into the HTML in that template.

```
<html{{ html_attributes.addAttribute("my attribute") }}>

```
> 0 votes

---
Tags: hooks
---


# Question
Title: How do I compile code with globals in Typescript?
Hi I'd like to use Typescript in my Drupal 9 Theme. I've setup compilation... but once I start declaring new behaviors like so:

```
(function ($: any, Drupal: any) {
  Drupal.behaviors.my_behavior = {
    attach: function (context: any, settings: any) {
    }
  };
})(jQuery, Drupal);

```

Ts compiler give me TS2304: Cannot find name 'jQuery'. and TS2304: Cannot find name 'Drupal'. while everything works fine in vanilla js. Here is my tsconfig.json:

```
{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "sourceMap": true
  }
}

```

Seems variable from the global scope are not loaded with ts files, how can I circumvent this problem and make it works with drupal js framework ?

# Answer
> 1 votes
Thanks to cilefen and https://stackoverflow.com/questions/13252225/call-a-global-variable-inside-module

this works:

```
declare var jQuery: any;
declare var Drupal: any;

(function ($: any, Drupal: any) {
  Drupal.behaviors.api_table_ieceecategories_graphic = {
    attach: function (context: any, settings: any) {},
  };
})(jQuery, Drupal);

```

DISC: I am using "any" type to prove compilation works, good typescript should use precise typing...

---
Tags: 9
---


title: How can I embed a node in a block?

text:
# Question
Title: How can I embed a node in a block?
I need to embed each node I have in a different block. How can I achieve it?

If it makes any difference, I am using Drupal 7.

# Answer
create a block and use the below code to get the node body field content.

```
$node = node_load(YOUR_NODE_ID);
$body_content = $node->body[$node->language][0]['value'];
print $body_content;

```

If you are using a field other than body field, then you should print\_r that $node variable and you will get all content type field relate with particular node.From this array you can get the all values created by content types.
> 5 votes

# Answer
Sounds like Nodes In Block is exactly what you're after. Node Blocks might also help is the first one doesn't.
> 2 votes

# Answer
In Drupal 9, a node can be embedded programmatically like this:

```
  public function build(): array {
    /** @var \Drupal\node\NodeInterface $node */
    $node = $this->nodeStorage->load(self::NID);
    $build['content'][] = [
      '#markup' => Markup::create($node->body->value),
    ];
  }

```

Search for `nodeStorage` in core to see how to set that property in your block class.
> 0 votes

---
Tags: blocks
---


title: Why is ScrollTopCommand not working?

text:
# Question
Title: Why is ScrollTopCommand not working?
I have a node edit form which I submit via ajax and then opens a modal doing this:

```
  $form['actions']['submit'] = array_merge($form['actions']['submit'], [
    '#value' => t('Get quote'),
    '#ajax' => [
      'callback' => 'open_quote_modal',
      'event' => 'click',
    ]
  ]);
  $form['#attached']['library'][] = 'core/drupal.dialog.ajax';

```

This works fine. In my ajax call from this submit I do the following to capture any errors from the node edit form:

```
function open_quote_modal($form, $form_state) {
  $response = new AjaxResponse();

  // Check that there werent any errors from the Quote form.
  if ($form_state->hasAnyErrors()) {
    $allMessages = \Drupal::messenger()->all();
    $allMessages['#type'] = 'status_messages';
    $html = \Drupal::service('renderer')->renderRoot($allMessages);

    // Remove any old messages.
    $response->addCommand(new RemoveCommand('.messages'));
    // Add new messages.
    $response->addCommand(new AfterCommand('div[data-drupal-messages-fallback]', $html));
    // Scroll to top of page.
    $response->addCommand(new ScrollTopCommand('body'));

    return $response;
  }

  // If no errors - code here to show contents of modal
}

```

This also works perfectly, except for the ScrollTopCommand. My errors are shown at the top of the page but I am left at the bottom of the page. There are no js or php errors.

# Answer
> 3 votes
You need to include the `views/views.ajax` lib:

```
$form['#attached']['library'][] = 'views/views.ajax';

```

---
Tags: ajax, 9, modal-dialogs
---


# Question
Title: How to translate breadcrumbs block via drupal_block() in twig?
I am trying to translate the breadcrumbs block in Drupal 9.3 via Twig Tweak I am loading the block in a twig like so:

```
{{ drupal_block('system_breadcrumb_block') }}

```

If I leave it like this, it only returns Home --\> Page\_name (In english) Even if it is another language selected (de). Is there some way to pass a language parameter to this function? Or somehow to indicate that it should be loading the page titles in the current language?

# Answer
I wouldn't try to translate breadcrumbs in Twig. Blocks get the language from the global context and for breadcrumbs it's delegated to the breadcrumb builder which then gets it from the context.

For the most simple case, core path based breadcrumb builder and static page titles, Drupal is using interface translation and you find the translatable string in the translation table after you have used the page the first time.

If you have installed a breadcrumb module or are displaying dynamic page titles you have to add more details to the question.
> 3 votes

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


# Question
Title: How can I display no results text in a template?
I have added no results behaviour text to a view called Events which is a page. This template I am using has a twig called views-view--events--page\_1.twig. I want to add the no results text to this twig template, but I can't find any way to do it. How can this be done?

# Answer
It's always useful to look at the original template (views-view.html.twig). The documentation list the available variables, which in this case are the following.

> * attributes: Remaining HTML attributes for the element
> * css\_name: A css-safe version of the view name
> * css\_class: The user-specified classes names, if any
> * header: The optional header
> * footer: The optional footer
> * rows: The results of the view query, if any
> * empty: The content to display if there are no rows
> * pager: The optional pager next/prev links to display
> * exposed: Exposed widget form/info to display
> * feed\_icons: Optional feed icons to display
> * more: An optional link to the next page of results
> * title: Title of the view, only used when displaying in the admin preview
> * title\_prefix: Additional output populated by modules, intended to be displayed in front of the view title
> * title\_suffix: Additional output populated by modules, intended to be displayed after the view title
> * attachment\_before: An optional attachment view to be displayed before the view content
> * attachment\_after: An optional attachment view to be displayed after the view content
> * dom\_id: Unique id for every view being printed to give unique class for Javascript

`{{ empty }}` appears to be what you're after.
> 4 votes

---
Tags: views, theming
---


# Question
Title: How can you attach a file to a mail using Symfony mailer?
I want to attach a file to a mail from an input file in my form. Here is how I build the mail :

```
$mailManager = \Drupal::service('plugin.manager.mail');
$params['title'] = 'title test';
$params['message'] = 'my message example';
$form_file = $form_state->getValue('my_input_file');
if (isset($form_file[0]) && !empty($form_file[0])) {
      $file = File::load($form_file[0]);
      $params['attachments'][] = $file;
}
$to = 'example@example.com';
$result = $mailManager->mail('my_module', 'my_key', $to, \Drupal::currentUser()->getPreferredLangcode(), $params, NULL, TRUE);

```

I'm also using an EmailBuilder for rendering the mail :

```
/**
 * Defines the Email Builder plug-in for my_module module.
 *
 * @EmailBuilder(
 *   id = "my_module",
 *   sub_types = { },
 * )
 */
class DemandeCreationEmailBuilder extends EmailProcessorBase
{

  /**
   * {@inheritdoc}
   */
  public function preRender(EmailInterface $email)
  {
    $email->setSubject($email->getParam('title'));
    $email->setBody(array(
        'site' => \Drupal::config('system.site')->get('name'),
        'message' => $email->getParam('message'),
        'attachments' => $email->getParam('attachments'), // I tried this but it's not working
      )
    );
  }

}

```

The data from *message* is correctly included in the mail, but the file is not.

I'm using the Symfony Mailer module (version : 1.0.0-alpha7) to send mails. My version of Drupal is 9.

Does anyone know how to solve this problem please ?

# Answer
I haven't used that module yet, but I think its

```
$file = File::load($form_file[0]);
$params['attachments'][] = [
  'filepath' => $file->createFileUrl(FALSE),
  'filename' => $file->getFilename(),
  'filemime' => $file->getMimeType()
];

```
> 0 votes

---
Tags: emails
---


# Question
Title: Why can’t I install the module after uploading it?
I uploaded the Commerce Core module (8.x-2.32) from the */admin/modules/install* tab. After uploading it, the modules list shows the module as disabled. I cannot select the checkbox shown for this module to install it.

Why cannot I select the module to install it?

# Answer
> 3 votes
As it says in the module's project page

> **Drupal 9 / Commerce 2.x**
>
> **Commerce 2.x should only be installed via Composer**. The zip files on this page are provided for informative purposes only.

You need to install composer if you don't have it installed already and then run in your project's Drupal root folder

```
composer require 'drupal/commerce:^2.32'

```

---
Tags: commerce, 9, installation
---


title: Class arguments not being passed

text:
# Question
Title: Class arguments not being passed
Updating the emulsify\_twig extension for D10, for some reason the class arguments aren't being passed... I'm extending Drupal\Core\Template\TwigExtension and using the same default arguments but for some reason it isn't picking up the arguments, resulting in: `ArgumentCountError: Too few arguments to function Drupal\emulsify_twig\BemTwigExtension::__construct(), 0`

This is the relevant code from the class:

```
use Drupal\Core\Template\TwigExtension;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Theme\ThemeManagerInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\File\FileUrlGeneratorInterface;

class BemTwigExtension extends TwigExtension {
  protected $urlGenerator;
  protected $renderer;
  protected $themeManager;
  protected $dateFormatter;
  protected $fileUrlGenerator;

  public function __construct(RendererInterface $renderer, UrlGeneratorInterface $url_generator, ThemeManagerInterface $theme_manager, DateFormatterInterface $date_formatter, FileUrlGeneratorInterface $file_url_generator = NULL) {
    parent::__construct(
      $renderer,
      $url_generator,
      $theme_manager,
      $date_formatter,
      $file_url_generator
    );

    $this->renderer = $renderer;
    $this->urlGenerator = $url_generator;
    $this->themeManager = $theme_manager;
    $this->dateFormatter = $date_formatter;
    $this->fileUrlGenerator = $file_url_generator;
  }

```

Any insight as to why the arguments aren't being passed would be appreciated!

# Answer
> 4 votes
The error message states that no arguments are being passed to the Twig filter extension. Drupal Twig filter extensions must be defined in `[MODULE].services.yml`, and in that service definition, the services to be injected as dependencies are defined. These are the arguments that `BemTwigExtension::__construct` is expecting, but not finding.

You *could* do something like the followingin `emulsify_twig.services.yml`:

```
services:
  emulsify_twig.bem_twig_extension:
    class: Drupal\emulsify_twig\TwigExtension\BemTwigExtension
    tags:
      - { name: twig.extension }
    arguments:
      - '@renderer'
      - '@url_generator'
      ...

```

Entering all the dependencies using their service definition names.

However, in the original post, as `__construct` is passing the arguments to the parent, the parent service definition can be referenced to determine which arguments it expects. In the original ploblem TwigExtension is being extended, and the `TwigExtension` API page lists one service as using it: twig.extension. Viewing the source on `twig.extension` API page shows the services expected by the parent class (the `arguments`):

```
class: Drupal\Core\Template\TwigExtension
arguments:
  - '@renderer'
  - '@url_generator'
  - '@theme.manager'
  - '@date.formatter'
  - '@file_url_generator'
tags:
  - { name: twig.extension, priority: 100 }

```

Then, instead of redefining all these arguments in the extended service definition, the parent can be set, using its arguments and tags as a base. So, back to `emulsify_twig.services.yml` the service would be defined as follows:

```
services:
  emulsify_twig.bem_twig_extension:
    class: Drupal\emulsify_twig\TwigExtension\BemTwigExtension
    parent: twig.extension
    arguments:
      - '@additional_class.1'
      ...

```

Where `@additional_class.1` is the name of any additional services that the extended class will use, that the parent does not. Note that if the extended class does not require any additional services, the `__construct()` method does not need to be implemented in the extended class at all, as the parent implementation will be used when not defined in the child class. However, the service will still need to be defined in `emulsify_twig.services.yml` with the parent set as `twig.extension`.

---
Tags: 10
---


# Question
Title: How to duplicate a node into an external database in Drupal 8
What I am trying to do is to save a copy of a node object after it is inserted into another Drupal database.

As it can be seen in the following piece of code, my idea is to change the database after a node is inserted. Make a copy of the node and save it. Then, return to the default database.

However, seems like entity storage manager is set to default database in node save function. Therefore, the node is getting saved inside the default database again.

```
//... mymodule_node_insert

$node = Node::load($id);
\Drupal\Core\Database\Database::setActiveConnection('external');
$db = \Drupal\Core\Database\Database::getConnection();

// save the node in the shared database
// Create node object with attached file.
$sharedNode = Node::create([
    'type'        => $node->getType();,
    'title'       => $node->getTitle();,
    'body_text'   => $node->get('body')->value,
]);
$sharedNode->save();

\Drupal\Core\Database\Database::setActiveConnection();

```

How can I make this work? Am I following a correct logic?

Any helps would be appreciated. Thanks

# Answer
This seems similar to Database::setActiveConnection not working as expected?. Perhaps the Node object you've instantiated before switching the connection is still going to hold on to the old db settings as the source to save.

The `DatabaseSwitcher` class (found in the above posted question, just under the accepted answer by the original poster) may be an effective way for you to switch the container context in a way that will allow your already instantiated Node object to save in your external DB:

```
//... mymodule_node_insert

$node = Node::load($id);
$db_switcher = new DatabaseSwitcher();
$db_switcher->changeToDifferentDb('external');

// save the node in the shared database
// Create node object with attached file.
$sharedNode = Node::create([
    'type'        => $node->getType();,
    'title'       => $node->getTitle();,
    'body_text'   => $node->get('body')->value,
]);
$sharedNode->save();

$db_switcher->changeToDefaultDb();

```

Hope this works for you!
> 2 votes

# Answer
I too just came across this issue. All the examples on the web only show how to deal with SQL queries. Obviously when working with entities one would use Drupal's entity manager. The trick is to new up a new SqlContentEntityStorage instance

This is what I have done and it works

```

namespace Drupal\fintech_sync\Commands;

use Drupal\Core\Database\Database;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Drupal\Core\Queue\QueueInterface;
use Drupal\Core\State\State;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drush\Commands\DrushCommands;
use Drupal\Core\Queue\QueueFactory;

/**
 * Provides drush commands for fintech_sync module.
 */
class NewCommand extends DrushCommands {

  use StringTranslationTrait;

  /**
   * The queue.
   *
   * @var \Drupal\Core\Queue\QueueInterface
   */
  private QueueInterface $queue;

  /**
   * The state.
   *
   * @var \Drupal\Core\State\State
   */
  private State $state;

  /**
   * SyncCommand constructor.
   */
  public function __construct(QueueFactory $queue) {
    $this->queue = $queue->get('fintech_sync_worker');
    parent::__construct();
  }

  /**
   * Sync dbs.
   *
   * @command fintech_sync:create-accounts
   */
  public function syncCreateAccounts($customLastRun = FALSE): void {
    $this->createAccounts();
    $this->io()->success(t('Creating accounts on queue.'));
  }

  /**
   * Sync dbs.
   *
   * @command fintech_sync:sync-accounts
   */
  public function syncSyncAccounts(): void {
     foreach (['588', '589'] as $accountId) {
      $this->doRemoteSave('account', $accountId);
    }

    $this->io()->success(t('Sync the accounts it remote databes.'));
  }

  public function doRemoteSave(string $entityType, int $id): void {

    /** @var \Drupal\Core\Entity\EntityStorageInterface */
    $entityManager = \Drupal::entityTypeManager();
    $entity = $entityManager->getStorage($entityType)->load($id);

    // Set the database connection key.
    Database::setActiveConnection('replica');

    $database = Database::getConnection();
    $entity_field_manager = \Drupal::service('entity_field.manager');
    $cache = \Drupal::service('cache.entity');
    $language_manager = \Drupal::service('language_manager');
    $memory_cache = \Drupal::service('entity.memory_cache');
    $entity_type_bundle_info = \Drupal::service('entity_type.bundle.info');

    $new = $entity->createDuplicate();
    $new->set('id', $entity->id());
    $new->set('uuid', $entity->uuid());
    $new->set('created', $entity->get('created')->value);
    $new->set('changed', $entity->get('changed')->value);

    $remoteStorage = new SqlContentEntityStorage(
      $entity->getEntityType(),
      $database,
      $entity_field_manager,
      $cache,
      $language_manager,
      $memory_cache,
      $entity_type_bundle_info,
      $entityManager
  );
    // If setting fields (id and uuid) that have a foreign keys it will fail with;
    // Integrity constraint violation error on a second save; so delete it first.
    $remoteStorage->delete([$entity]);
    $remoteStorage->save($new);
  }

}

> 1 votes

---
Tags: 8, nodes, entities, database
---


title: How to separate Twig array via batch

text:
# Question
Title: How to separate Twig array via batch
I'm trying to structure the output of a view into specific HTML for a carousel/slider I'm generating, basically I'm trying to turn a regular list of X people into groups, which I'm then dividing further for the purposes of structuring the HTML as I need

currently my `rows` variable contains X items (likely between 50-100)

* I am trying to split that into `pages` of 12 items
* Each page has 4 `rows` and 3 `columns`

So I want the HTML to look like this

```
<div class="page">
  <div class="row">
    <div class="col">A</div>
    <div class="col">A</div>
    <div class="col">A</div>
  </div>
  <div class="row">
    <div class="col">A</div>
    <div class="col">A</div>
    <div class="col">A</div>
  </div>
...
</div>
...

```

And my current twig is setup like this

```
{% set blank = [] %}

<div id="people-carousel-wrapper">
  <div id="people-carousel-container">
    {% for page in rows|batch(12) %}
      <div class="people-page">
        <div class="container">
          {% for row in page|batch(4, blank) %}
            <div class="row">
              {% for people in row|batch(3, blank) %}
                <div class="people-column col">
                  {{- people.content -}}
                </div>
              {% endfor %}
            </div>
          {% endfor %}
        </div>
      </div>
    {% endfor %}
  </div>
</div>

```

What I'd like to do is have it render out the full list of 12 items per page, regardless of if the number of items divides nicely by 12, except I don't seem to be able to make it render out the remaining HTML items, the twig batch page seems to suggest that you just need to fill in the second parameter for the batch function and it will use that item if nothing is there, at the moment it just stops when there are no more items

# Answer
> 1 votes
Figured it out for anyone wanting to find a similar sort of resolution

I needed to put the 'fill in the blank' part on my first batch, I realised that if I'm splitting that into groups of 12, as long as I fill in the blank spaces there, then I'll know that I've always got 12 items to group into the rows/cols as I need

```
{% set blank = [] %}

<div id="people-carousel-wrapper">
  <div id="people-carousel-container">
    {% for page in rows|batch(12, blank) %}
      <div class="people-page">
        <div class="container">
          {% for row in page|batch(3) %}
            <div class="row">
              {% for people in row %}
                <div class="people-column col">
                  {{- people.content -}}
                </div>
              {% endfor %}
            </div>
          {% endfor %}
        </div>
      </div>
    {% endfor %}
  </div>
</div>

```

---
Tags: 9, theming
---


# Question
Title: Unable to connect to database when launching a new Drupal site with Lando
I tried to set up a new local drupal9 site using Lando, but it is unable to connect to the database and I am getting the following error.

```
Failed to connect to your database server. The server reports the following message: SQLSTATE[HY000] [2002] No such file or directory.

```

Checking the Lando logs shows the following.

```
PDOException: SQLSTATE[HY000] [2002] No such file or directory in /app/web/core/lib/Drupal/Component/DependencyInjection/PhpArrayContainer.php on line 79

```

I checked and it seems to be resolved by putting the location of mysql.sock file in settings.php as shown below. I've got \`PDOException: SQLSTATE\[HY000\] \[2002\] No such file or directory\` when using drush

Then I checked mysql status and found the following.

```
UNIX socket:            /opt/bitnami/mysql/tmp/mysql.sock

```

The final result was as follows. But even if I change the host to 127.0.01, etc., the error message does not change.

```
$databases['default']['default'] = [
  'database' => 'drupal9',
  'username' => 'drupal9',
  'password' => 'drupal9',
  'host' => 'localhost',
  'port' => '3306',
  'driver' => 'mysql',
  'prefix' => '',
  'unix_socket' => '/opt/bitnami/mysql/tmp/mysql.sock',
];

```

If I've made any mistakes so far, please let me know. Thank you.

# Answer
You need to update host value in settings.php to `database`.

`localhost` is not correct for default lando configuration.
> 1 votes

---
Tags: database, 9, installation
---


# Question
Title: How to obtain a node id and product type from the product variation id?
I have a view in Drupal that has a field called Index product variation search: Item ID. Its description is "the item's internal (search API specific) ID".

Here is an example of what this field looks like: **entity:commerce\_product\_variation/111:en**

**What is this number (111)--is it the product\_variation id?**

Basically, I am sending in this number through a POST API call (in javascript). I need to use this number to obtain the node id and the product type for a product?

There is something on How can I retrieve the product ID? but it needs the sku (stock keeping unit) which I don't have.

# Answer
> 1 votes
Load the variation entity through entity type manager dependency injection:

```
$variation = $this->entityTypeManager->getStorage('commerce_product_variation')->load($variationId);

```

Or if you are in a hook:

```
$variation = \Drupal::entityTypeManager()->getStorage('commerce_product_variation')->load($variationId);

```

Then you can retrieve product entity:

```
$product = $variation->product_id->entity;

// Product id
$productId = $product->id();
// Product type
$productType = $product->bundle();

```

---
Tags: nodes, commerce
---


# Question
Title: Serialization of 'Closure' is not allowed in serialize()
i am in the midst of fixing our website (which is built using Drupal version 7.67) that shows many errors after the PHP version is updated into PHP 8.0.

One of the errors that i am stuck now is this particular error

> Exception: Serialization of 'Closure' is not allowed in serialize();

After i did some traces, it appears that this is happening when drupal\_get\_form or drupal\_build\_form is getting called.

Does anyone knows where should I look in the code to find out why is this happening?

# Answer
1. Drupal version 7.67 was released on 8 May 2019. Therefore, your Drupal site is not secured as the latest version as of this writing is 7.93 which was released on 7 December 2022.
2. PHP 8 support was introduced in version 7.79 as per PHP requirements docs.

Thus, you will need to revert back to your previous PHP 7 version and upgrade Drupal to the latest version and then upgrade your PHP to version 8.
> 4 votes

---
Tags: 7, forms
---


# Question
Title: Database update doesn't work after update from 9.2 to 9.3
I have unfortunately not found anything that seems to solve my issue. My Google-fu may be defunct.

I have upgraded a Drupal site from `9.2` to `9.3`. This works as expected with composer (I use `drupal/core-recommended`). But when I proceed to update the database with `drush updb`, it fails with the following error:

```
[previous output excluded for brevity]
>  [notice] Update started: user_post_update_update_roles
>  [error]  Render context is empty, because render() was called outside of a renderRoot() or renderPlain() call. Use renderPlain()/renderRoot() or #lazy_builder/#pre_render instead.
>  [error]  Update failed: user_post_update_update_roles
 [error]  Update aborted by: user_post_update_update_roles
 [error]  Finished performing updates.

```

Using `/update.php` results in this error:

```
user modul
Opdatér update_roles

    Mislykket: LogicException: Render context is empty, because render() was called outside of a renderRoot() or renderPlain() call. Use renderPlain()/renderRoot() or #lazy_builder/#pre_render instead. i Drupal\Core\Render\Renderer->doRender() (linje 245 af .../web/core/lib/Drupal/Core/Render/Renderer.php).

```

I unfortunately haven't been able to find anything that solves the issue, and since I am still fairly new to drupal, I might not know how to google it properly.

It should be noted that there are a bunch of custom modules made by my job, and the highest currently supported version is (unfortunately) 9.3.x, so upgrading to 9.4 as of writing this is a no-no (planning to upgrade the modules, of course).

I have updated the database for every patch release update without failure; this started as soon as I updated to 9.3.0 with the following command:

```
composer require drupal/core-recommended:9.3.0 drupal/core-composer-scaffold:9.3.0 drupal/core-project-message:9.3.0 --update-with-all-dependencies

```

I have updated all the patch releases in 9.2 like so:

```
composer update drupal/core-recommended:9.2.[insert patch release here]

```

All of them followed by a `drush updb && drush cr`.

Other possibly relevant information:

* PHP 7.4 CLI (8.0 in Apache)
* Apache 2.4.54
* MariaDB 10.6.11
* Debian 11.5
* Drush 10.3.6

I thank you in advance. If you need more information, please do say and I will update the question.

# Answer
As @4uk4 said, it was two of the custom modules that called `render()`.

You may get this error if your module uses something like this in Drupal 9:

```
$view = \Drupal::service('renderer')->render($view);

```

This can be fixed by changing it to this:

```
$view = \Drupal::service('renderer')->renderPlain($view);

```
> 1 votes

---
Tags: database, drush, 9, updating
---


title: How do I install on Windows 11?

text:
# Question
Title: How do I install on Windows 11?
I wish to install Drupal 9 on Windows 11 using Drush.

*Drupal on the cloud* solutions (which should be easily accessible from Windows) cost money and not quite what I seek for a local install.
I can install Drupal 9 on WAMP/XAMPP on Windows but I don't want because it doesn't have Drush (and I don't think WSL will help).
I can install Linux, either directly or on a virtual machine, using a distribution like Ubuntu, which I have used over the years, but I encounter several keyboard and mouse issues (slow mouse scrolling, keyboard input problems, etc.) which make hard for me to edit much content.

How do I install Drupal 9 with Drush on Windows 11?

# Answer
If you're on Windows 11, you should consider using Docker with WSL2. This will let you use a WSL installation of Ubuntu, which runs in the hypervisor and will give better performance than a virtual machine in VirtualBox, etc.

However, with WSL2 (different from WSL1), filesystem performance will take a huge hit if you manipulate linux files from Windows. To get around this, you can set up Visual Studio Code or PHPStorm in Windows to access your WSL2 environment. Alternately, you can install the IDE of your choice in WSL2 and run it with wslg support, but this is harder to set up and prone to graphical glitches.

Personally, if you are comfortable with Ubuntu, I would recommend using a docker-based solution inside WSL2 like lando. Lando provides a nice interface for setting up docker containers and has great support out of the box for Drupal as well as many of the Drupal PaaS.

So the basic flow is:

1. Install Ubuntu and upgrade it to WSL2 (it will probably be WSL1 by default).
2. Install docker and lando in WSL2 and set up your drupal site.
3. Install your IDE (assuming it is VSCode or PHPStorm) in Windows and then connect to WSL.
4. Enjoy a complete linux environment from Windows with great performance.

All of the software recommended here is open source (except PHPStorm) and freely available. lando has been around for 10+ years (used to be called Kalabox) and WSL has been around since 2016 and continues to get big upgrades from Microsoft (it's the basis for Windows 11's Android app compatibility), so although it takes time to set this up, you can be reasonably confident that these solutions will continue to be supported well into the future.
> 2 votes

# Answer
If you want to install Drupal 9 on windows 11 then follow these steps which are given on drupal.org Step 1: Get the Code Install the files you need to run Drupal.

Step 2: Install dependencies with composer If you installed or updated the codebase using git, then install required PHP libraries with composer.

Step 3: Create a database Create a database for Drupal to use.

Step 4: Configure your installation Set up the web server and PHP to work together.

Step 5: Run the installer Run the installation script.

Step 6: Status check Check the status of your site at Administration \> Reports \> Status report. Set trusted hosts patterns, create files directories.

Add Composer to an existing site How to convert an existing Drupal site to a composer-managed project. Step by step guide to adding composer to manually installed site.

Building a Drupal site with Git How to use Git to manage the source code for a Drupal site

Drupal Quick Start Command Launch a local demo version of Drupal.

Trusted Host settings Protecting against HTTP HOST Header attacks
> -2 votes

# Answer
I have found the way to install (and upgrade) Drupal 9 and above on Windows 11 extremely cumbersome and not worth the time.

An alternative, for those who need Windows 11 mechanics and keyboard behavior is to hire a shared hosting (which includes SSH and Composer) and install Drupal on that shared hosting while SSHing to this environment from Windows 11.
If working this way, it's probably best to put the website on maintenance mode and `disallow: /` in robots.txt for development time.

If one takes the path I have suggested, while working form Windows 11 the installation pretty much narrows down to the following steps:

```
# Configure DNS records
# Configure database (say, with PHPMyAdmin)

cd WEB_APPLICATION_ROOT
composer create-project drupal/recommended-project WEB_APPLICATION_DIR_NAME
cd WEB_APPLICATION_DIR_NAME
composer require drush/drush
vendor/bin/drush site:install

# Configure web_application_root (example.com/web, done from "domains" in Cpanel)
# Install Drupal from web browser

```
> -3 votes

---
Tags: drush, 9, installation
---


# Question
Title: Is possible to add a field to content moderation's states?
I'm on D 9.4.x and using content moderation module.

Is possible to add a custom field to the states of the workflows\module?

E.g. add a boolean?

# Answer
Out of the box? No.

You will have to create a custom module that adds such boolean field to your content types or entity types.

Via `hook_form_alter` you can use `#ajax` with `#access` OR alternatively use `#states` to show/hide the field when a different moderation state is selected.
> 2 votes

---
Tags: workflows
---


# Question
Title: Commerce Migrate module not listed in migrations
I installed the Commerce Migrate module, and its submodules, `commerce_migrate_commerce` and `csv_example`. When I run `drush migrate:status`, I see the migrations for the `csv_example` listed but none of the `commerce_migrate_commerce` ones?

I likely will have to write my own migration anyways, but I was confuse at this discrepancy.

# Answer
I figured it out. In MigrateToolsCommands.php, we have the following code:

If you dig into the error for the migrations in question, I see the error of `No database connection configured for source plugin variable`. When an item fails the `checkRequirements()`, it simply is not displayed in the list.

In SqlBase.php

it sets the default migration database as `migrate`. Being that the migrations themselves do not specify a key (since that is really site specific), it would rely on the default one, which I did not have set up in my settings.php.

EDIT: I also found out one more issue: even AFTER I had set up a migrate database source key, it still wasn't working. I found that this modules is ONLY meant to migrate from D7. You can see this from the fact that that during the requirements check, it looks for existance of the `system` table, which only exists in d7.
> 2 votes

---
Tags: commerce, migrations
---


# Question
Title: Creating account type where email not required to be unique
I'm developing a platform for Drupal 8 where there are several account types: students, their parents, teachers.

The students are young and we want their accounts associated with their parents' emails for security reasons, and there are cases where the parent has two or more students on the system. Also, each parent and student will have logins to their own areas.

So I need to be able to create student accounts where the email address is not required to be unique. And for the student accounts I need the password management (forgot/reset) to be done by username, not email).

Is it possible? How can I achieve this?

# Answer
This answer is untested; it should only serve as a guidance. Use it at your risk.

```
mymodule_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
  if ($entity_type->id() == 'user') {
    unset($fields['mail']['constraints']['UserMailUnique']);
  }
}

```

Note that once hook\_entity\_base\_field\_info\_alter() and hook\_entity\_bundle\_field\_info\_alter() are documented to get a parameter that doesn't implement an interface with setter methods is fixed, any implementation of `hook_entity_base_field_info_alter()` could need to be rewritten. That is now an issue for Drupal 10.x, which still needs to be fixed.
> 2 votes

# Answer
There is a module with Drupal 7 and Drupal 8 releases that allows to use shared emails: Shared Email. The hook that implements for Drupal 8 is the following one.

```
function sharedemail_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
  // Alter the email text field to allow duplicates.
  if (!empty($fields['mail']) && $entity_type->id() === 'user') {
    $constraints = $fields['mail']->getConstraints();
    unset($constraints['UserMailUnique']);
    $constraints['SharedEmailUnique'] = [];
    $fields['mail']->setConstraints($constraints);
  }
}

```

If you wanted to just disable the unique email restriction in a custom module, you could implement the following hook.

```
function mymodule_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
  if (!empty($fields['mail']) && $entity_type->id() === 'user') {
    $constraints = $fields['mail']->getConstraints();
    unset($constraints['UserMailUnique']);
  }
}

```

The *Shared Email* module does something more, as it allows to create accounts using a shared email only to users with a specific permission, and it allows to restrict the email addresses that can be shared using a list of allowed emails.
I would rather use that module instead of creating a custom module, or adding code to an existing custom module.
> 0 votes

---
Tags: 8
---


# Question
Title: Unsuccessfully trying to get to the correct target_id
So I've been programming a module that needs to show different pictures depending on the language code of the user (en vs. fa). For that I'm trying to get to the right target\_ids. Debug($nodes) shows me the following:

```
        [field_picture_active] => Array
            (
                [x-default] => Array
                    (
                        [0] => Array
                            (
                                [target_id] => 209
                                [alt] => Introdution
                                [title] =>
                                [width] => 320
                                [height] => 320
                            )

                    )

                [fa] => Array
                    (
                        [0] => Array
                            (
                                [target_id] => 241
                                [alt] => test222
                                [title] =>
                                [width] => 320
                                [height] => 320
                            )

                    )

            )

```

The correct target\_id would be 241 under \[fa\] but when I try the following ...

```
foreach ($nodes as $node) {
   $image_field = $node->get('field_picture_active')->first()->getValue();
   $fid = $image_field['target_id'];
}

```

... and then attempt to load the pictures for each nodes (or do debug($fid)), I just get the target\_ids for each node that appear under \[x-default\] instead of \[fa\]. How can I access the target\_ids under \[fa\]? Every other translation works perfectly fine, just those target\_ids are not correct.

Any thoughts on this will be highly appreciated. Thank you very much.

# Answer
If you want the value for a specific language, you should use the translated node. The following code should work

```
foreach ($nodes as $node) {
  if ($node->hasTranslation('fa')) {
    $node = $node->getTranslation('fa');
  }
  $image_field = $node->get('field_picture_active')->first()->getValue();
  $fid = $image_field['target_id'];
}

```

If there is no translation, the default value will be taken.
> 1 votes

---
Tags: nodes
---


# Question
Title: How can I populate radio options on a form with user entities?
I have some user entities and I want to make them available as options to choose in a radio button element on a form.

I can populate the options with a username no problem, so visually I can achieve what I want, but I need to be able to get the user entity that was selected in the form submit function, not just the user name.

I've tried loading the entire user entities into the options array but this throws an error.

I need to to do something like below, but instead of 'entity\_autocomplete' it needs to be of type 'radio'

```
$form['user'] = [
      '#type' => 'entity_autocomplete',
      '#target_type' => 'user',
      '#title' => t('Assign or Unassign a user'),
];

```

When using the above code, the user entity is the value of the form element when submitted, I need to achieve the same thing using radio buttons.

# Answer
> 3 votes
You build an array of options from user entities:

```
$options = [];
foreach ($users as $user) {
  $options[$user->id()] = $user->getDisplayName();
}

$form['user'] = [
  '#type' => 'radios',
  '#title' => $this->t('User'),
  '#options' => $options,
];

```

Then in the submit handler you can get the user ID and load the selected user:

```
$selected_user = \Drupal\user\Entity\User::load($form_state->get('user'));

```

---
Tags: forms
---


# Question
Title: Is there a way to specify order in a search_api query manually given a set of node ids?
Using search\_api I have an query with the following condition

```
$query->condition('nid', [1,5,3,7,10], 'IN')

```

I know I can sort by things like created date or title, but what if I knew the exact order I wanted everything returned in. So in the above example where I'm grabbing the nodes with ids \[1,5,3,7,10\] what if I want the results returned in that order too. So after executing in the array of results the nodes appear in 1,5,3,7,10 order.

I tried using orderBy but that does not appear to be a method of the search\_api query class

> Call to undefined method Drupal\search\_api\Query\Query::orderBy()

UPDATE:

I tried passing a sort function into sort on the query like so

```
      $query->sort(function($a,$b) use ($allowed_nids){
        $pos_a = array_search($a->nid, $allowed_nids);
        $pos_b = array_search($b->nid, $allowed_nids);
        if(($pos_a == $pos_b)){
          return 0;
        }
        return ($pos_a < $pos_b) ? -1 : 1;
      });

```

But that gave me the error

> TypeError: Illegal offset type in isset or empty in Drupal\search\_api\Query\Query-\>sort() (line 465 of modules/contrib/search\_api/src/Query/Query.php).

Which I assume means that it can only take strings for the sort function and not anonymous methods.

# Answer
> 1 votes
The error you are receiving is due to the first argument of sort() expecting the field name, not a function: https://git.drupalcode.org/project/search\_api/-/blob/8.x-1.x/src/Query/Query.php#L462

As to your issue, I don't believe you can sort them in the query itself, but you can sort the results by the array:

```
$nids = [1,5,3,7,10];
$query->condition('nid', $nids, 'IN')
$results = $query->execute();

$sorted_results = array_merge(array_flip($nids), $results);

```

---
Tags: entities, 9
---


title: Twig custom filter return cached value

text:
# Question
Title: Twig custom filter return cached value
I have a custom filter for the twig, but the value of the filter doesn't update. It remains the same till clearing the cache. I want to get the url param and based on the value showing different output in the twig template. Here is the custom twig filter

```
class CustomTwig extends Twig_Extension {

  public function getFunctions(){
        return [
          new TwigFunction('link_to_requirement', [$this, 'linkToRequirement']),
        ];
      }
  public function linkToRequirement($title) {
    $x = $_GET['req'];
    return $x == str_replace(' ', '-', strtolower($title));
  }

}

```

Then use it as `{% if link_to_requirement(paragraph.field_title.value) %}`.

Is there any option to disable the cache for this twig filter, or should I do it in another way?

# Answer
You need to add the cache context for the query parameter.

In this case you can't return it in a render array because you return only a boolean, but you can try to bubble it up:

```
$x = \Drupal::request()->query->get('req');

$twig_bubbleable = [
  '#cache' => [
    'contexts' => ['url.query_args:req'],
  ],
];

\Drupal::service('renderer')->render($twig_bubbleable);

```
> 2 votes

---
Tags: 9
---


# Question
Title: How to allow user registration based on roles?
I have two roles on my site:

* Visitor, the normal user who can register on our site without any admin approval procedure
* Business role, the business user who can register and add their business to our site, with admin approval.

Can anyone suggest how I can allow registration based on role, so that one requires approval, and the other doesn't?

Also there are two different registration links for users whether they want to register as normal or business user; based on which link the user click, the registration process will take place.

# Answer
I would recommend that you have all users register on the same page, and have "business" users register for the right to add businesses using either the Apply for Role module or Organic Groups. Note that Organic Groups will allow you to put a checkbox on the registration page, so business users could check the appropriate request checkbox as they sign up. An admin would have to approve their request to join the "business" group.
> 4 votes

# Answer
Check the Registration Role with Approval module, some details about it (from its project page):

> This module lets administrator to select roles that will be available for selection on registration form. It also allows to select which roles needs admin approval.
>
> During registration user will be presented with optional checkboxes where he can select a role. If role needs admin approval, user account will be blocked until approved by admin. Email will be sent to administrator with roles that are requested and username of user who request it.
> 2 votes

# Answer
Another solution for this is the (fairly new) Select registration roles module. Some more details about it (from its project page):

> The Select Registration Roles module adds a role field on the user registration form. Admin can configure roles to be displayed on the registration form as, and can set roles which require admin approval.

Here is a screenprint of it:

Obviously, by using this module, you wouldn't need 2 registrations links anymore (which should reduce the number of registration errors also, because of using the wrong registration link ...).

**Note**: a stable release is available for either D7 or D8.
> 1 votes

# Answer
If you have the user account creation form but using the Multiple Registration module to update its path, you can use `hook_user_presave()` to update the status of the user with the required role:

```
function MY_MODULE_user_presave(Drupal\Core\Entity\EntityInterface $user) {
  $roles = $user->getRoles();
  if (in_array('ROLE_MACHINE_NAME', $roles)) {
    $user->status->value = 0;
  }
  elseif (in_array('commerce_marketplace_admin', $roles)) {
    $user->status->value = 0;
  }
}

```
> 1 votes

---
Tags: 7, users
---


# Question
Title: Drush fatal error with Declaration of Drupal\Core\Logger\LoggerChannel::log
When I run any drush command or even just drush I get the fatal error:

> Fatal error: Declaration of Drupal\Core\Logger\LoggerChannel::log($level, $message, array $context = \[\]) must be compatible with Psr\Log\LoggerTrait::log($level, Stringable|string $message, array $context = \[\]): void in /core/lib/Drupal/Core/Logger/LoggerChannel.php on line 94

I updated drupal with composer to 9.5 and I'm running PHP 8.1. Here is my composer.json requirements:

```
    "require": {
        "composer/installers": "^1.9",
        "drupal/bootstrap": "^3.24",
        "drupal/captcha": "^1.2",
        "drupal/core-composer-scaffold": "^9.0.0",
        "drupal/core-project-message": "^9.0.0",
        "drupal/core-recommended": "^9.5",
        "drupal/core-vendor-hardening": "^8.8",
        "drupal/feeds": "^3.0@beta",
        "drupal/feeds_ex": "^1.0@alpha",
        "drupal/field_formatter": "^3.0@RC",
        "drupal/google_tag": "^1.5",
        "drupal/gtranslate": "^1.14",
        "drupal/honeypot": "^2.0",
        "drupal/image_popup": "^2.0",
        "drupal/mailsystem": "^4.3",
        "drupal/masquerade": "^2.0@RC",
        "drupal/menu_block": "^1.8",
        "drupal/metatag": "^1.19",
        "drupal/page_manager": "^4.0@beta",
        "drupal/paragraphs": "^1.13",
        "drupal/pathauto": "^1.9",
        "drupal/recaptcha": "^3.0",
        "drupal/recaptcha_element": "^1.0",
        "drupal/redirect": "^1.7",
        "drupal/schema_metatag": "^2.3",
        "drupal/sendgrid_integration": "^2.0@beta",
        "drupal/smtp": "^1.0",
        "drupal/twig_tweak": "^3.1",
        "drupal/views_bootstrap": "^4.3",
        "drupal/webform": "^6.1",
        "drupal/webform_spam_words": "^2.0",
        "drupal/webform_validation": "^2.0@alpha",
        "drupal/yoast_seo": "^2.0@alpha",
        "drush/drush": "^11.4",
        "google/recaptcha": "^1.2"
    },

```

Here are the plugins:

```
    "config": {
        "sort-packages": true,
        "allow-plugins": {
            "composer/installers": true,
            "drupal/core-composer-scaffold": true,
            "drupal/core-project-message": true,
            "drupal/core-vendor-hardening": true,
            "dealerdirect/phpcodesniffer-composer-installer": true
        }
    },

```

I can't run any drush command and I get the following error if I go to my site:

> Fatal error: Declaration of Drupal\dblog\Logger\DbLog::emergency($message, array $context = \[\]) must be compatible with Psr\Log\LoggerInterface::emergency(Stringable|string $message, array $context = \[\]): void in /core/lib/Drupal/Core/Logger/RfcLoggerTrait.php on line 20

Any suggestions on how to proceed?

EDIT\* Additional Info:

PHP Version: 8.1.13

Drupal Core installed packages (from `composer show -i`):

```
drupal/core                                    9.5.0
drupal/core-composer-scaffold                  9.4.9
drupal/core-dev                                9.4.9
drupal/core-project-message                    9.4.9
drupal/core-recommended                        9.5.0
drupal/core-vendor-hardening                   8.9.20

```

# Answer
> 0 votes
We discovered in chat that the reason this occurred is because there is a custom module installing its own Composer dependencies which clash with the ones loaded by Drupal.

---
Tags: drush, 9, composer
---


# Question
Title: How to distinguish between order.paid event when authorization/capture and just capture?
I asked this question back in 2020: How do I programmatically "place" an order? and provided my own answer there:

Provide an event subscriber:

```
  public static function getSubscribedEvents() {
    $events['commerce_order.order.paid'][] = ['placeOrder'];
    return $events;
  }

```

which then applies a transition to the Order:

```
 public function placeOrder($event) {
    $order = $event->getOrder();
    $order->getState()->applyTransitionById('place');
    return;
 }

```

This has worked well for the past 2 years but client now wants to split payment authorize and capture. This requires a later step after accepting payment to "capture" the payment. Although the payment capture seems to work and changes payment state to completed; the order balance is not reduced to $0. Removing my code to fix the Order being placed (on admin authorize and capture payments) allows capture to work correctly.

I can likely trigger my transition by something which distinguishes between the 2 types of payments; but suspect I am likely doing something wrong in how I am placing the Order.

# EDIT

Changed title to better clarify the requirement.

# Answer
> 0 votes
Looking at default Event Subscriber from the Payment module, it seems as though I am subscribing to the correct event (commerce\_order.order.paid) and I am correctly setting the Order to "placed" with:

```
$order->getState()->applyTransitionById('place');

```

The issue is then, that I need to execute this when I auth/capture but not when I capture only (as this partially breaks the capture process). This is my code to determine which of these has triggered the order.paid event and allows me to only "place" the order for the correct one.

```
  public function placeOrder($event) {
    $order = $event->getOrder();

    // Check Payment to see if we are just Capturing now.
    $payment = $this->getPayment($order_id);
    $authorized = $payment->authorized->value;

    // This only needs to be done when in Admin flow
    // - also, don't do this if just Capturing payment
    if (isStaff() && !$authorized) {
      $order->getState()->applyTransitionById('place');
    }
  }

  private function getPayment($order_id) {
    $payments = \Drupal::entityTypeManager()
      ->getStorage('commerce_payment')
      ->loadByProperties(['order_id' => $order_id]);
    $payment = current($payments);
    return $payment;
  }

```

This does seem a bit convoluted; so possibly there is a bug tied up in Commerce here somewhere. Commerce maintainers have suggested in the past that the admin payment flow is less supported than the customer flow - so possibly that explains the requirement for this.

# Answer
> 1 votes
The order of operations here is this:

1. You create a payment on the backend.
2. Previously you were capturing immediately, resulting in a completed payment.
3. When a completed payment is saved, its `postSave()` function requests an update to the order via the `PaymentOrderUpdater` service, which recalculates the related order's `total_paid` field at the end of the page request via its destructor (the `destruct()` function).
4. The `total_paid` is calculated afresh. If it doesn't match the current `total_paid` value on the order, the order will be saved.
5. (Note: the first time a draft order is saved, its `paid_event_dispatched` boolean gets initialized to `FALSE` in its data array. This is important to the next step.)
6. When the order is saved by the `PaymentOrderUpdater` at the end of its `updateOrder()` function, the `OrderStorage` checks in the presave process to see if the `total_paid` is less than order equal to the order total. If so, it dispatches the `OrderEvents::ORDER_PAID` event you're depending on.
7. After all order paid subscribers execute, including to apply a state transition, the order is saved.

I don't see why changing from an authorization + capture workflow to an authorization only + capture later workflow would change this process. At the end of the day, steps 3 - 7 only activate when a *completed* payment is saved, and the process should be no different.

If the `PaymentOrderUpdater` service is somehow not getting a chance to function, I suppose that would create the instance you're seeing ... but if removing your subscriber solves things, then it sounds more like your subscriber is failing. However, if it is failing, I'd expect you'd see some sort of error. The most common failure I can imagine would be the transition failing to apply because the order is not in a draft state any longer. Since your logic wouldn't get activated until destruction, I suppose the HTTP response has already been streamed, but the save ultimately fails.

You can check your PHP error logs are add debugging to your subscriber, but my hunch is these orders you want to see the balance reduced to $0 on are already placed - i.e. no longer in the `draft` state.

---
Tags: commerce, 9
---


# Question
Title: How to add an item constraint to a field
How do I define an item level constraint, as opposed to a constraint on an item list?

In the comments of \Drupal\Core\Field\FieldConfigInterface, there is this note:

```
   * If you wish to apply a constraint to a \Drupal\Core\Field\FieldItem instead
   * of a property or FieldItemList, you can use the
   * \Drupal\Core\Field\FieldConfigBase::getItemDefinition() method.
   * @code
   *   // Add a constraint to the 'field_entity_reference' FieldItem (entity
   *   // reference item).
   *   $fields['field_entity_reference']->getItemDefinition()->addConstraint('MyCustomFieldItemValidationPlugin', []);

```

Presumably this would be run inside hook\_entity\_bundle\_field\_info\_alter()?

I am trying this as shown here. It accepts the constraint, you can see it in the definition, but it never runs.

Is there some further undocumented detail for doing this? Or is this the wrong hook?

# Answer
> 1 votes
This hook seems indeed not to be the right place. When the item definitions are recreated later your custom code will not run again.

More common are constraints on the field property, which are added in a persistent way to the field item via the property constraint table of the field definition. To fill this table use addPropertyConstraints():

```
function mymodule_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
  $field_name = 'field_example';
  if ($entity_type->id() == 'entity_test' && $bundle == 'entity_test' && !empty($fields[$field_name])) {
    // Add a property constraint using
    // \Drupal\Core\Field\FieldConfigInterface::addPropertyConstraints().
    $fields[$field_name]->addPropertyConstraints('value', [
      'Range' => [
        'min' => 0,
        'max' => 32,
      ],
    ]);
  }
}

```

Code is from `field_test.module`.

---
Tags: hooks
---


# Question
Title: Problem with PHP version on Ubuntu on Windows when installing Drush
I'm trying to install Drupal 10 with DDEV with these instructions: https://ddev.readthedocs.io/en/latest/users/quickstart/#drupal. I'm on Ubuntu on Windows (WSL2). Ubuntu version: 20.04. Windows 10. When I try to run the command `ddev composer require drush/drush` I get errors.

```
Using version ^11.4 for drush/drush
./composer.json has been updated
Running composer update drush/drush
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - drupal/core 10.0.0 requires php >=8.1.0 -> your php version (8.0.14) does not satisfy that requirement.
    - drupal/core-recommended 10.0.0 requires drupal/core 10.0.0 -> satisfiable by drupal/core[10.0.0].
    - drupal/core-recommended is locked to version 10.0.0 and an update of this package was not requested.

You can also try re-running composer require with an explicit version constraint, e.g. "composer require drush/drush:*" to figure out if any version is installable, or "composer require drush/drush:^2.1" if you know which you need.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.
composer [require drush/drush] failed, composer command failed: exit status 2. stderr=

```

I upgraded PHP. `php -v` reports I installed PHP 8.2.0.

How can Composer say I am using PHP 8.0.14?

# Answer
> 4 votes
You’re executing `PHP` on your local machine, which has PHP 8.2 installed. You’re executing `composer` inside the VM, which has PHP 8.0 installed. You need to upgrade PHP inside your VM.

See Extending and Customizing Environments for instructions to do that in DDev.

---
Tags: composer, 10
---


# Question
Title: AJAX button on table rows to delete rows
I have a standard form with a table. I can add lines to the table via AJAX.
I also like to delete the lines using AJAX. But I don't know exactly where and how to add the buttons.

Here is my code to build the table inside the standard form building function:

```
  ...
  $aPersonsTable = array();
  foreach ($aPersons as $key => $value) {
    $row = array($value['dname'],'HERE IS THE PLACE WHERE THE BUTTON SHOULD SHOW UP');
    $aPersonsTable[]=$row;
  }

  $form['persons']['ptable'] = array(
    '#theme' => 'table',
    '#header' => $pheader,
    '#rows' => isset($aPersonsTable)?$aPersonsTable:null,
    '#disabled' => TRUE,
    '#title' => 'Users currently assigned',
    '#empty' => t('No users assigned yet!'),
    '#prefix' => '<div id="ptable_wrapper">',
    '#suffix' => '</div>',
  );
  ...

```

I'd like to have the button at 'HERE IS THE PLACE WHERE THE BUTTON SHOULD SHOW UP' :-)

I tried something like:

```
$row = array($value['dname'],array(
  '#type' => 'submit',
  '#value'=> 'Delete person',
  '#attributes' => array('id'=>$value['id']),
  '#ajax'=> array(
    'callback' => 'delete_person_ajax_callback',
  )
));

```

Any ideas? I googled and stackexchanged a lot, but did not find the right solution. Thx.

# Answer
> 1 votes
I found the answer using drupal\_render(). The buttons are now generated in each row, havin their own ids, so that I can read the triggering element in the callback function. Now I only have the problem whe I click one of the buttons, the complete form is submitted. There seems to be no ajax callback. I will search further an will the edit the answer...

```
  foreach (aPersons as $key => $value) {
    $form_button['button'] = array(
      '#id' => 'del_'.$key,
      '#type' => 'button',
      '#value' => 'Delete',
      '#ajax' => array(
        'callback' => 'delete_person_ajax_callback',
      )
    );
    $deleteButton = drupal_render($form_button['button']);
    $row = array($value['dname'],$deleteButton);
    $aPersonsTable[]=$row;
  }

```

# Answer
> 1 votes
I had the same issue with drupal 8.

The issue occured when several buttons/submits shared the same "#value". Drupal doesn't seem to handle the callbacks correctly in this case.

For me, the solution was to make each button's "#value" unique.

# Answer
> 0 votes
I have fixed the above issues. Button element rendering through theme row data array not using a function like drupal\_render(). Each row's theme table passes by reference. The respective row triggers the ajax callback function individually.

```
foreach ($Persons as $key => $value) {
    $form_button['button_'. $key] = array(
      '#id' => 'del_'.$key,
      '#type' => 'button',
      '#submit' => array('delete_person_button_submit'),
      '#value' => 'Delete',
      '#ajax' => array(
        'callback' => 'delete_person_ajax_callback',
      )
    );
    $row = array('data' => &$form_button['button_'. $key]);
    $aPersonsTable[] = $row;
  }

```

---
Tags: forms, ajax
---


# Question
Title: Multiple exposed form blocks with different fields
Scenario:

View fields:

```
name
gender
age
especialty

```

exposed form block (1) fields:

```
name
especialty

```

exposed form block (2) fields: (This is also I want to have but as a separate block)

```
 name
 age
 gender

```

I am looking for a way in which I can have **two different exposed form blocks** but with different search fields.

I am using Drupal 8. Any help would be appreciated. Thanks!

# Answer
> 1 votes
On my Drupal 9.5x project, the old duplicate page method works. Steps:

* Create a page display with all the desired fields and the set of exposed filters you want in block1.
* Duplicate the page display.(Path = same as the first.)
* On the duplicated page, remove the block1 exposed filters and add the filters wanted in block2.
* Check the expose filters in a block option on both page displays.
* Go to block layout and add the two exposed filter blocks to the page for the view.

In my case I have auto-refresh enabled and the submit button disabled. The filters apply as expected.

---
Tags: views, 8
---


title: Get custom fields assigned to taxonomy

text:
# Question
Title: Get custom fields assigned to taxonomy
How to get custom fields assigned to taxonomy in Drupal 8. What I have done so far is:

```
$contact_countries = \Drupal::service('entity_type.manager')->getStorage("taxonomy_term")->loadTree('contact_country');

```

$contact\_countries now holds taxonomies, I can get name of taxonomy and ID, but I also created custom field in taxonomy, how can I get it?

With this code

```
foreach($contact_countries as $contact_countrie) {
        $terms[] = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($contact_countrie->tid);
        $variables['contact_countries'] = $terms;
    }

```

I'm getting object(Drupal\taxonomy\Entity\Term) with protected values. I can see my custom fields values there but can't access it.

# Answer
> 3 votes
You can access fields using getFields() on the term object: https://api.drupal.org/api/drupal/core!modules!taxonomy!src!Entity!Term.php/class/Term/8.2.x

Or you can use get(): https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21ContentEntityBase.php/function/ContentEntityBase%3A%3Aget/8.2.x

# Answer
> 5 votes
I done it like this:

```
$contact_countries = \Drupal::service('entity_type.manager')->getStorage("taxonomy_term")->loadTree('contact_country');

$terms = array();

foreach($contact_countries as $contact_countrie) {
    $terms[] = array(
        'contact_country' => $contact_countrie->name,
        'contact_phone' => \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($contact_countrie->tid)->get('field_phone')->getValue()[0]['value'],
        'contact_flag' => \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($contact_countrie->tid)->get('field_category_flag')->entity->uri->value,
    );
}

```

Here I have fields field\_phone (text field) and field\_category\_flag (file field).

# Answer
> 3 votes
I did it this way.

```
$countries = \Drupal::service('entity_type.manager')->getStorage("taxonomy_term")->loadTree('countries',0,NULL,TRUE);

/* Using First Country : $countries[0] */
$region = $countries[0]->get('field_region')->target_id;
$description = $countries[0]->get('field_description')->value;

```

# Answer
> 0 votes
```
$current_entity_lang = $entity->get('langcode')->value;
//version and so current revision
$translated_entity = $entity->getTranslation($current_entity_lang);
// if single value for the taxo
$value=$translated_entity->get('field_name')->referencedEntities()[0]->getName();
//else loop the values to get name
$values=$translated_entity->get('field_name')->referencedEntities();

```

# Answer
> 0 votes
With Drupal 9, the following code worked for me with a small-sized taxonomy.

```
$vid = 'taxonomy_identifier';
$custom_field = 'field_identifier';
$output_array = [];

$terms =\Drupal::entityTypeManager()
  ->getStorage('taxonomy_term')
  ->loadTree($vid, 0, 2, TRUE);

foreach ($terms as $term) {
  foreach ($term->getFields(false) as $field) {
    if ($field->getName() == $custom_field) {
      $item_value = $field->getString();
      if ($item_value !== "") {
        $output_array[] = $item_value;
      }
    }
  }
}

print_r($output_array);

```

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


# Question
Title: Empty node references on node creation and on node load
I never noticed it, but:

* If I create a node containing a reference and set the reference field to null, the field is still set as an `EntityReferenceFieldItemList`, e.g. the following code

```
echo "Creating a node with ref_field=null", PHP_EOL ;
$node = Node::create([
    'type' => 'my_type',
    'uid' => \Drupal::currentUser()->id(),
    'title' => "title",
    'field_ref_field' => null,
]) ;
// $node->field_ref_field = null ;
$node->save() ;

echo "Ref field is a " . gettype($node->field_ref_field) . ", and more specifically: " . get_class($node->field_ref_field), PHP_EOL ;
echo "Its id is ", $node->id(), PHP_EOL ;

```

produces on output

```
Creating a node with ref_field=null
Ref field is a object, and more specifically: Drupal\Core\Field\EntityReferenceFieldItemList
Its id is 933461

```

The same result occurs if I set ref\_field to `null` after node creation, uncommenting the line that follows.

* If I reload the field,

```
$node = Node::load(933461) ;
echo "Ref field is a " . gettype($evento->field_seduta), PHP_EOL ;

```

the result is

```
Field seduta is a NULL

```

As a consequence of this behaviour, to check if a reference field is valid I have either to check both the field itself and its target\_id for `null`ness,

```
if (! $node->field_ref_field || ! $node->field_ref_field->target_id)

```

that is annoying, or to make sure that a certain code fragment is reached after node creation or node loading, that is fragile.

Am I missing something? What is the reason of this strange behaviour?

# Answer
> 2 votes
The value of the field will be NULL, but the field itself is a FieldItem. That's how Drupal works, as the FieldItem class manages the values of the field, even when there are no values set.

The solution to your conditional is to check if the field is empty:

```
if (!empty($node->field_ref_field)) {
  // There are values.
}
else {
  // There are no values.
}

```

---
Tags: nodes
---


# Question
Title: Views does not show content if any of fields from relationship are empty
I have a view which displays fields from a content type but it also has a relationship to any entities which have a reference field to a node of this content type.

I have things like a title and body text plus some custom text fields on the view, the title and body are from the node.

However these do not display unless the referenced fields are not empty.

How can I get the view to display these fields still when the entity fields are empty?

# Answer
You can achieve your requirement by unchecking **Require this relationship** option on relationship field.
> 1 votes

# Answer
I recently had the same issue in Drupal 9 and had a terrible time figuring it out. My view is of one content type and has several relationships, including two to content in two entity reference fields on the content type. If either of those fields was empty for a particular node, it didn't display in the view. If I removed those relationships, everything showed up, but I needed them to display some data.

In my case I solved it by checking the "Disable SQL rewriting" option (in the "Advanced" tab \> Query Settings). You want to be extremely careful with this as it will disable any node access checks and may show content to users who aren't supposed to see it, so you'll have to make sure to add access controls somewhere else in the view if necessary. In my case it's done through validation on a contextual filter, or it could be the view access settings.

This seems like a Drupal bug but I couldn't find any reports of it on drupal.org.
> 0 votes

---
Tags: views
---