title: Unable to access private file?

text:
# Question
Title: Unable to access private file?
I had this issue before, and last time the problem was that node was unpublished. The private file became accessible when the node was published.

This time, however, I'm not using a node. I'm just using Drupals file manage system to store my own files for my own custom module. SO I generated a url for an image file like so:

```
$imageFile = file_load($userInput['fid']);
$style = \Drupal::entityTypeManager()->getStorage('image_style')->load('thumbnail');
$url = $style->buildUrl($imageFile->getFileUri());

```

If I print out the URL, I get:

```
http://localhost/system/files/styles/thumbnail/private/cfiles/test.png?itok=Le14o4Zs

```

But when I access that, i get "access denied".

What am I missing?

# Answer
> 7 votes
In Drupal 8, private file permissions by default are given according to the entity to which they are attached. If the user has permission to view the entity, they will have permission to view the file.

If you are not attaching the file to an entity, then you will need to implement hook\_file\_download(), where you will determine whether or not the user has permission to access the file, and return a value accordingly. Currently, because you have no implemented this, access is denied by default.

Note that this hook can be implemented even when the file is attached to an entity to provide additional access checks and/or additional headers.

# Answer
> 2 votes
Another nice way to negotiate file access according some more complex conditions than `hook_file_download($uri)` allows you to check for, is to implement `hook_ENTITY_TYPE_access` for the file entity and check if the `$operation` equals `'download'` like in the snippet below. There you also have access to the actual `$file` entity.

```
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\file\FileInterface;

/**
 * Implements hook_ENTITY_TYPE_access().
 */
function MYMODULE_file_access(FileInterface $file, $operation, AccountInterface $account) {
  if ($operation === 'download') {
    // Do access stuff ...
    // ...
    // ...
  }
  // No opinion.
  return AccessResult::neutral();
}

```

# Answer
> 2 votes
Like Jaypan said, If you are not attaching the file to an entity, then you will need to implement hook\_file\_download(), where you will determine whether or not the user has permission to access the file.

Here is a code example that can help :

```
/**
 * Implements hook_file_download().
 */
function mymodule_file_download($uri) {
  // Check if the file is private.
  if (StreamWrapperManager::getScheme($uri) == 'private') {

    // Exclude file not in location.
    if (strpos($uri, '/location/') === false) {
      return NULL;
    }

    $account = Drupal::currentUser();
    $user_roles = $account->getRoles();

    // Check if user has the authorized role.
    if (in_array('administrator', $user_roles)
      || in_array('country_administrator', $user_roles)
      || in_array('super_administrator', $user_roles)) {
      return ['Content-disposition' => 'attachment'];
    }
  }

  return NULL;
}

```

---
Tags: 8, media
---


title: Migrate a two-textfield field

text:
# Question
Title: Migrate a two-textfield field
I'm looking to migrate a text field from Drupal 6 to Drupal 9. The field has two text fields.

The table description returned by `describe content_field_telfono ;`  is the following.

| Field | Type | Null | Key | Default | Extra |
| --- | --- | --- | --- | --- | --- |
| vid | int(10) unsigned | NO | PRI | 0 |  |
| nid | int(10) unsigned | NO | MUL | 0 |  |
| field\_telfono\_value | varchar(10) | YES |  | NULL |  |
| delta | int(10) unsigned | NO | PRI | 0 |  |

The table content returned by `select * from content_field_telfono limit 0,2;` is the following.

| vid | nid | field\_telfono\_value | delta |
| --- | --- | --- | --- |
| 48 | 48 | xxxxxxxxx | 0 |
| 48 | 48 | xxxxxxxxx | 1 |

I found examples to migrate a multi-value. I tried with the following migration.

```
  field_school_phone:
    plugin: sub_process
    source: field_telfono
    process:
      value: field_telfono_value

```

# Answer
> -1 votes
have you seen this? migration using csv and yml for multivalued image field

anyway i think if you have the multivalued field separated by commas, it should work directly

---
Tags: 9, migrations
---


# Question
Title: Link render array style attribute getting stripped in event subscriber
I'm trying to generate a link as part of a string which will get sent by email. The link has to be styled to look like a button.

I'm doing this in a token event subscriber.

Here's my current code:

```
$url = Url::fromUri('https://google.com');
$link = new Link('Click me', $url);
$link = $link->toRenderable();
$link['#attributes'] = [
  'class' => ['nm-share', 'nm-share-' . $type_name],
  'target' => '_top',
  'style' => 'display:inline-block;width:213px;height:30px;color:#FFFFFF;text-decoration:none;text-align:center;padd  ing:15px 0px 0px;background:' . $colour . ';font:normal 17px/17px Arial, Helvetica, sans-serif;box-sizing:content-box;-webki  t-box-sizing:content-box;-moz-box-sizing:content-box;',
];

```

When the link is rendered it has the `class` and `target` attributes, but the `style` attribute is missing. How can I stop that from happening?

Converting my code to use an inline\_template element seems like a messy solution.

The weird thing is if I put the same code in a drush script and run the script the style attribute does get rendered.

# Answer
> 0 votes
Well this turned out to not be about render arrays at all.

I was using devel\_debug() to send the rendered string to my drupal\_debug.txt, and it turns out devel\_debug() passes the text it receives through a text filter which strips out the style tag. The rendered string does in fact contain the style attribute.

To confuse my situation further, the rendered string was getting passed to another drupal instance via an api call, and that instance was also stripping out the style tags.

Ultimately this came down to symfony\_mailer module stripping out style tags from the email body.

---
Tags: 9
---


# Question
Title: How do I programmatically alter the links displayed in the main navigation menu?
The main navigation menu in the site I am currently working on has a lot of menus. I want to hide the disabled ones.

I figured out that it is rendered via the *menu\_edit\_form* form.

```
entity.menu.edit_form:
  path: '/admin/structure/menu/manage/{menu}'
  defaults:
    _entity_form: 'menu.edit'
    _title_callback: '\Drupal\menu_ui\Controller\MenuController::menuTitle'
  requirements:
    _entity_access: 'menu.update'

```

I could not locate the menu edit form from the above entry. I am thinking of a doing form alter but is there a better way to alter the links shown in the form and also how do we locate the form that is used to display the link.

# Answer
> 0 votes
I figured out how to do this.

The form actually resides at

`Drupal\menu_ui\MenuForm`

As this is an entity form it has to be set/defined in the annotation of the ContentEntityType 'menu'. This is where the form class is usually linked with the 'menu.edit' found in the routing file \_entity\_form entry.

However I could not find such an annotation at first. Then I finally figured out where this is defined

```
/**
 * Implements hook_entity_type_build().
 */
function menu_ui_entity_type_build(array &$entity_types) {
  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
  $entity_types['menu']
    ->setFormClass('add', 'Drupal\menu_ui\MenuForm')
    ->setFormClass('edit', 'Drupal\menu_ui\MenuForm')
    ->setFormClass('delete', 'Drupal\menu_ui\Form\MenuDeleteForm')
    ->setListBuilderClass('Drupal\menu_ui\MenuListBuilder')
    ->setLinkTemplate('add-form', '/admin/structure/menu/add')
    ->setLinkTemplate('delete-form', '/admin/structure/menu/manage/{menu}/delete')
    ->setLinkTemplate('edit-form', '/admin/structure/menu/manage/{menu}')
    ->setLinkTemplate('add-link-form', '/admin/structure/menu/manage/{menu}/add')
    ->setLinkTemplate('collection', '/admin/structure/menu');

  if (isset($entity_types['node'])) {
    $entity_types['node']->addConstraint('MenuSettings', []);
  }
}

```

The above was found in the menu\_ui.module. So I learned today that there is alternative way to define the entity form.

So based on the above findings and to answer the question - to alter the Menu edit form links I did the following

1. I proceeded to extend the MenuForm in my custom module
2. I added a hook\_entity\_type\_alter in my custom module where I linked the new form with the route.

```
/**
 * Implements hook_entity_type_alter().
 */
function my_custom_module_entity_type_alter(&$entity_types) {
  $entity_types['menu']
    ->setFormClass('edit', '\Drupal\my_custom_module\MyCustomMenuForm');
}

```

and voila I could get the new extended custom form in the url instead of the old one.

---
Tags: navigation, 9
---


title: What cache service should I use?

text:
# Question
Title: What cache service should I use?
I just used a cache service explicitely for the first time, in a function that calls a remote service. The result is a simple string that may change day by day, but it's very rare that it changes for the past – so I expire it at midnight.

I injected `cache.default` in my controller – then I saw that in core services there is also a service called `cache.data`. What's the difference? Is there any reason to prefer one to the other?

# Answer
> ## Cache bins
>
> Cache storage is separated into "bins", each containing various cache items. Each bin can be configured separately; see Configuration.
>
> When you request a cache object, you can specify the bin name in your call to \Drupal::cache(). Alternatively, you can request a bin by getting service "cache.nameofbin" from the container. The default bin is called **default**, with service name `cache.default`, it is used to store common and frequently used caches.
>
> Other common cache bins are the following:
>
> * **bootstrap:** Data needed from the beginning to the end of most requests, that has a very strict limit on variations and is invalidated rarely.
> * **render:** Contains cached HTML strings like cached pages and blocks, can grow to large size.
> * **data:** Contains data that can vary by path or similar context.
> * **discovery:** Contains cached discovery data for things such as plugins, views\_data, or YAML discovered data such as library info.

https://api.drupal.org/api/drupal/core!core.api.php/group/cache
> 4 votes

---
Tags: 9, caching
---


title: Auto send userA's profile URL to userB

text:
# Question
Title: Auto send userA's profile URL to userB
I thought this could be easy, but I don't know what's the best way to achieve this.

I have an acting "job" application site, userA need to finish his "profile2" first which including photos, weight, height etc.. userB will post a job node, then userA will click an "apply" button within the job node, userB will receive a message/email which including the userA's profile URL, then userB can look at userA's profile to decide if this person is ok for his job. I can't figure out which module I should use to make this process works, email/webform/privatemessage ? if you can suggest how to make this works. thanks

# Answer
> 1 votes
You could build a flow like this using the Flag module.

General steps

1. Create a flag, **Apply for job** that targets the job node entity. Make it a per-user flag, not a global flag.
2. Give job applicants permission to flag job nodes.
3. Create a view that show's the job poster all the flags on their job node, and use a relationship to pull in each applicant's profile.

---
Tags: users
---


# Question
Title: Database error when execute drush migrate:status
I'm trying to do a 'file to media' migration on a d8 installation. Following the readme on the module I have created a custom module and created the two yaml files. After enabling the module and `drush ms` i get the following error:

```
SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed

```

The error appears on my local (DDEV) and my production environment. Drush works otherwise. `drush sql-cli` works.

I think i'm missing something. Do i have to set a database reference somewhere? Happy to provide additional information when needed, as i'm clueless atm.

Thanks for pointing me in the right direction.

Edit: output of `drush ms -v`

```
Exception trace:
  at myproject/docroot/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php:416
 PDO->__construct() at myproject/docroot/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php:416
 Drupal\Core\Database\Driver\mysql\Connection::open() at myproject/docroot/core/lib/Drupal/Core/Database/Database.php:374
 Drupal\Core\Database\Database::openConnection() at myproject/docroot/core/lib/Drupal/Core/Database/Database.php:169
 Drupal\Core\Database\Database::getConnection() at myproject/docroot/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php:201
 Drupal\migrate\Plugin\migrate\source\SqlBase->setUpDatabase() at myproject/docroot/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php:154
 Drupal\migrate\Plugin\migrate\source\SqlBase->getDatabase() at myproject/docroot/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php:221
 Drupal\migrate\Plugin\migrate\source\SqlBase->checkRequirements() at myproject/docroot/core/modules/migrate_drupal/src/Plugin/migrate/source/DrupalSqlBase.php:112
 Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase->checkRequirements() at myproject/docroot/modules/contrib/metatag/src/Plugin/migrate/source/d7/MetatagFieldInstanceDeriver.php:69
 Drupal\metatag\Plugin\migrate\source\d7\MetatagFieldInstanceDeriver->getDerivativeDefinitions() at myproject/docroot/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php:101
 Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator->getDerivatives() at myproject/docroot/core/lib/Drupal/Component/Plugin/Discovery/DerivativeDiscoveryDecorator.php:87
 Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator->getDefinitions() at myproject/docroot/core/modules/migrate/src/Plugin/MigrationPluginManager.php:262
 Drupal\migrate\Plugin\MigrationPluginManager->findDefinitions() at myproject/docroot/core/lib/Drupal/Core/Plugin/DefaultPluginManager.php:175
 Drupal\Core\Plugin\DefaultPluginManager->getDefinitions() at myproject/docroot/core/modules/migrate/src/Plugin/MigrationPluginManager.php:109
 Drupal\migrate\Plugin\MigrationPluginManager->createInstances() at myproject/docroot/modules/contrib/migrate_tools/src/Commands/MigrateToolsCommands.php:697
 Drupal\migrate_tools\Commands\MigrateToolsCommands->migrationsList() at myproject/docroot/modules/contrib/migrate_tools/src/Commands/MigrateToolsCommands.php:135
 Drupal\migrate_tools\Commands\MigrateToolsCommands->status() at n/a:n/a
 call_user_func_array() at myproject/vendor/consolidation/annotated-command/src/CommandProcessor.php:257
 Consolidation\AnnotatedCommand\CommandProcessor->runCommandCallback() at myproject/vendor/consolidation/annotated-command/src/CommandProcessor.php:212
 Consolidation\AnnotatedCommand\CommandProcessor->validateRunAndAlter() at myproject/vendor/consolidation/annotated-command/src/CommandProcessor.php:176
 Consolidation\AnnotatedCommand\CommandProcessor->process() at myproject/vendor/consolidation/annotated-command/src/AnnotatedCommand.php:302
 Consolidation\AnnotatedCommand\AnnotatedCommand->execute() at myproject/vendor/symfony/console/Command/Command.php:255
 Symfony\Component\Console\Command\Command->run() at myproject/vendor/symfony/console/Application.php:1005
 Symfony\Component\Console\Application->doRunCommand() at myproject/vendor/symfony/console/Application.php:255
 Symfony\Component\Console\Application->doRun() at myproject/vendor/symfony/console/Application.php:148
 Symfony\Component\Console\Application->run() at myproject/vendor/drush/drush/src/Runtime/Runtime.php:118
 Drush\Runtime\Runtime->doRun() at myproject/vendor/drush/drush/src/Runtime/Runtime.php:49
 Drush\Runtime\Runtime->run() at myproject/vendor/drush/drush/drush.php:72
 require() at myproject/vendor/drush/drush/includes/preflight.inc:18
 drush_main() at phar:///usr/local/bin/drush/bin/drush.php:143
 require() at /usr/local/bin/drush:10

```

**Update2:** I have tried the whole process with a vanilla drupal 8.9.11, some manually created nodes with managed files (image) and all worked like a charm. So there must be something in my project going wrong.

# Answer
> 0 votes
I have (finally!) resolved the problem:

1. Starting from scratch
2. I had setup a new Thunder distribution with Drupal 9.1.0 (Thunder 6.1.1)
3. Instead of using the UI-version of migrate-update i did the migration from the d7 source with drush. For this the source database was additionally imported into the ddev-environment.
4. After this was done, the file to media migration worked without database errors.

# Answer
> 1 votes
This is because it cannot connect to the old database. If you use **ddev** you have two options:

1. Create a new instance for the old database.
2. Import the old database on current instance as a second database.

See more on https://stackoverflow.com/q/49785023/1365264

---
Tags: 8, drush, migrations
---


# Question
Title: Form custom with method GET remove form_build_id and op from GET variables
If I create a custom form with get method:

```
$form['#method'] = 'get';

```

When I click the submit button, many variables are populated with GET Can I remove them cleanly according to the drupal logic?

# Answer
You need to alter the form after it has been built, for example

```
$build = [];
$build['filter'] = $this->formBuilder->getForm(LibrarySearch::class);
$build['filter']['form_id']['#access'] = FALSE;
$build['filter']['form_build_id']['#access'] = FALSE;
$build['filter']['form_token']['#access'] = FALSE;

```

Once the form has been turned into a render array, you can set the access to `FALSE` for those items. This is also documented in the core Search module.
> 4 votes

# Answer
For me, unsetting inside form\_alter didn't work. I had to do it in a different way.

Add this inside form\_alter hook.

```
  $form['#after_build'][] = 'function_name';

```

Later add a separate function and unset inside that.

```
function function_name($form){

  // Unset variables to cleanup the url after submission
    unset($form['form_token']);
    unset($form['form_build_id']);
    unset($form['form_id']);
    return $form;
  }

```
> 1 votes

# Answer
Another way to solve this problem.

Implement a hook form alter in your corresponding module in the

`[name_of_your_module].module` file, just add

```
/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Need to don't see the parameters 'form_build_id' and 'form_id' in the url.
 */
function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
  unset($form['form_build_id'], $form['form_id']);
}

```
> 0 votes

# Answer
Needs to alter the form to unset **form\_id** and **form\_build\_id**. In bellow code **formid** is the id of the form where you want to remove **form\_id** and **form\_build\_id**.

function mymodule\_form\_formid\_alter(&$form, &$form\_state, $form\_id) {

unset($form\['form\_build\_id'\], $form\['form\_id'\]);

}
> 0 votes

---
Tags: 8, forms
---


# Question
Title: Composer upgrade to 9.4.x fails, my site is stuck on 9.3.x
My Drupal 9 site is stuck on the 9.3.x track, I cannot upgrade to 9.4.x. If I use the standard upgrade command:

```
composer update "drupal/core-*" --with-all-dependencies

```

Then it upgrades to the latest 9.3 version (currently 9.3.22), but no further.

If I try to force to 9.4.7 (or any 9.4.x version) with:

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

```

This fails with the composer error

> Problem 1 \- Root composer.json requires drupal/core-recommended 9.4.7 -\> satisfiable by drupal/core-recommended\[9.4.7\]. \- drupal/core-recommended 9.4.7 requires drupal/core 9.4.7 -\> found drupal/core\[9.4.7\] but these were not loaded, likely because it conflicts with another require.

If I try to find out why:

```
composer prohibits drupal/core 9.4.7

```

then I get:

> drupal/core-recommended 9.3.22 requires drupal/core (9.3.22)
>
> drupal/mysql56 1.3.0 requires drupal/core (~9.0.0-beta3 || 9.1.\* || 9.2.\* || 9.3.\*)
>
> drupal/core 9.4.7 requires symfony/polyfill-iconv (^1.25)
>
> drupal/legacy-project dev-main does not require symfony/polyfill-iconv (but v1.23.0 is installed)
>
> drupal/core 9.4.7 requires symfony/polyfill-php80 (^1.25)
>
> drupal/legacy-project dev-main does not require symfony/polyfill-php80 (but v1.23.1 is installed)
>
> drupal/core 9.4.7 requires laminas/laminas-feed (^2.17)
>
> drupal/legacy-project dev-main does not require laminas/laminas-feed (but 2.15.0 is installed)
>
> drupal/core 9.4.7 requires egulias/email-validator (^2.1.22|^3.2)
>
> drupal/legacy-project dev-main does not require egulias/email-validator (but 3.1.2 is installed)
>
> drupal/core 9.4.7 requires composer/semver (^3.3)
>
> drupal/legacy-project dev-main does not require composer/semver (but 3.2.6 is installed)

Should I also include all these in the composer statement? I have tried:

```
lando composer require drupal/core-recommended:9.4.7 drupal/core-composer-scaffold:9.4.7 drupal/core-project-message:9.4.7 symfony/polyfill-iconv laminas/laminas-feed egulias/email-validator composer/semver --update-with-all-dependencies

```

But this gives similar Problem 1 as before.

Any help much appreciated.

As requested, here is the composer.json file in full:

```
{
    "name": "drupal/legacy-project",
    "description": "Project template for Drupal 9 projects with composer following drupal/drupal layout",
    "type": "project",
    "license": "GPL-2.0-or-later",
    "homepage": "https://www.drupal.org/project/drupal",
    "support": {
        "docs": "https://www.drupal.org/docs/user_guide/en/index.html",
        "chat": "https://www.drupal.org/node/314178"
    },
    "repositories": [
        {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        }
    ],
    "require": {
        "composer/installers": "^1.9",
        "cweagans/composer-patches": "^1.7",
        "drupal/administerusersbyrole": "^3.2",
        "drupal/anchor_link": "^2.5",
        "drupal/autologout": "^1.4",
        "drupal/ckeditor_resize": "^1.3",
        "drupal/core-composer-scaffold": "^9.3",
        "drupal/core-project-message": "^9.3",
        "drupal/core-recommended": "^9.3",
        "drupal/core-vendor-hardening": "^9.3",
        "drupal/csv_serialization": "^2.1",
        "drupal/ctools": "^3.11",
        "drupal/embed": "^1.6",
        "drupal/entity_browser": "^2.8",
        "drupal/entityreference_filter": "^1.4",
        "drupal/field_group": "^3.3",
        "drupal/field_permissions": "^1.2",
        "drupal/google_analytics": "^3.1",
        "drupal/insert_view": "^2.0",
        "drupal/juicebox": "^3.0@alpha",
        "drupal/linkit": "^5.0@beta",
        "drupal/login_history": "^1.1",
        "drupal/mail_login": "^2.6",
        "drupal/media_directories": "^2.0",
        "drupal/media_library_edit": "^2.3",
        "drupal/menu_breadcrumb": "^1.16",
        "drupal/menu_position": "1.x-dev",
        "drupal/mysql56": "^1.3",
        "drupal/pathauto": "^1.11",
        "drupal/redirect": "^1.8",
        "drupal/role_watchdog": "^2.0",
        "drupal/roleassign": "^1.0@beta",
        "drupal/security_review": "^1.0@alpha",
        "drupal/tabtamer": "2.x-dev@dev",
        "drupal/token": "^1.11",
        "drupal/token_filter": "^1.4",
        "drupal/views_data_export": "^1.1",
        "drupal/webform": "^6.1",
        "drush/drush": "^11.0",
        "mikehaertl/phpwkhtmltopdf": "~2.1",
        "tecnickcom/tcpdf": "~6"
    },
    "conflict": {
        "drupal/drupal": "*"
    },
    "minimum-stability": "stable",
    "prefer-stable": true,
    "config": {
        "sort-packages": true,
        "allow-plugins": {
            "composer/installers": true,
            "cweagans/composer-patches": true,
            "drupal/core-composer-scaffold": true,
            "drupal/core-project-message": true,
            "drupal/core-vendor-hardening": true
        },
        "process-timeout": 0
    },
    "extra": {
        "drupal-scaffold": {
            "locations": {
                "web-root": "./"
            }
        },
        "installer-paths": {
            "core": [
                "type:drupal-core"
            ],
            "libraries/{$name}": [
                "type:drupal-library"
            ],
            "modules/contrib/{$name}": [
                "type:drupal-module"
            ],
            "profiles/contrib/{$name}": [
                "type:drupal-profile"
            ],
            "themes/contrib/{$name}": [
                "type:drupal-theme"
            ],
            "drush/Commands/contrib/{$name}": [
                "type:drupal-drush"
            ],
            "modules/custom/{$name}": [
                "type:drupal-custom-module"
            ],
            "profiles/custom/{$name}": [
                "type:drupal-custom-profile"
            ],
            "themes/custom/{$name}": [
                "type:drupal-custom-theme"
            ]
        },
        "drupal-core-project-message": {
            "include-keys": [
                "homepage",
                "support"
            ],
            "post-create-project-cmd-message": [
                "<bg=blue;fg=white>                                                         </>",
                "<bg=blue;fg=white>  Congratulations, you’ve installed the Drupal codebase  </>",
                "<bg=blue;fg=white>  from the drupal/legacy-project template!               </>",
                "<bg=blue;fg=white>                                                         </>",
                "",
                "<bg=yellow;fg=black>Next steps</>:",
                "  * Install the site: https://www.drupal.org/docs/8/install",
                "  * Read the user guide: https://www.drupal.org/docs/user_guide/en/index.html",
                "  * Get support: https://www.drupal.org/support",
                "  * Get involved with the Drupal community:",
                "      https://www.drupal.org/getting-involved",
                "  * Remove the plugin that prints this message:",
                "      composer remove drupal/core-project-message"
            ]
        },
        "enable-patching": true,
        "patches": {
            "drupal/core": {
                "Arbitrary sizing of media - images for CKEditor: https://www.drupal.org/project/drupal/issues/3132211": "https://www.drupal.org/files/issues/2021-12-08/3132211_drupal_media_ckeditor_resize_17.patch"
            }
        }
    }
}

```

# Answer
The cause appears to be:

```
drupal/mysql56 1.3.0 requires drupal/core (~9.0.0-beta3 || 9.1.* || 9.2.* || 9.3.*)

```

That unsupported version of `drupal/mysql56` does not allow Drupal 9.4 or higher.
> 2 votes

---
Tags: composer
---


# Question
Title: What does rebuilding content access permissions do?
Since installing the node access module I see the following message randomly.

> Content access permissions need to be rebuilt.

Will rebuilding them remove all the node access permissions already set? What does "rebuilding" do? Why do I get this message?

# Answer
> 5 votes
There's a quote in the comments on this post that puts it nicely:

> Drupal maintains a table of who can access what; this needs to be rebuilt when a new module affecting user access is enabled.

Think of it as a cache-clear for node access data, except that it's quite complicated so needs to be run as a batch job rather than all at once (e.g. on a cron run).

Since node access is a sensitive issue it's also not wise to rely on scheduled jobs to make the necessary changes, hence why this is all done in one go.

# Answer
> 0 votes
I also was getting this error, after installing the **Book Access** module in Drupal 6. It turns out I hadn't created any books yet, so that after I had clicked the check box to enable the new installed module, drupal was unable to find found any book permissions with which to initialise the new database table that **Book Access** uses.

I was able to get rid of the error by

1. disabling **Book Access**
2. creating a book page
    * no need for content, but do include at least a title
    * remember to select "new book" from the dropdown box in the "Book Outline" section of the "edit" tab
3. enabling **Book Access** again

Your situation may be similar.

# Answer
> 0 votes
I've been frustrated at times trying to find how to run this process manually on D8 / D9 - top Google results are useless. So, if you know you have a content access issue (content that should be viewable is being restricted, for example), then navigate to:

`yoursite.com/admin/reports/status/rebuild`

The reason is that a problem with content access permissions is shown as an item on your status report, and the rebuild command comes from there. But you can navigate directly to the above URL at any time if you need to kick off a rebuild. (Don't do it casually as it's a tedious operation - only if you know you have content that is incorrectly being hidden, or not hidden, especially by a custom module or a wacky contrib module like `permissions_by_term`.)

---
Tags: users
---


title: How do I display a node in a block?

text:
# Question
Title: How do I display a node in a block?
I would like to display a node as a block in Drupal 8, but I don't know how to do this. I know in Drupal 7 I could use the Nodeblock module to accomplish this task, but there isn't a Drupal 8 version of it (and it looks like that there never will be).

Can this be accomplished using another module that I am not aware of?

# Answer
You can add a file to your module at `src/Plugin/Block/YourBlock.php`

```
namespace Drupal\your_module\Plugin\Block;
use Drupal\Core\Block\BlockBase;

/**
 * Provides a block.
 * @Block(
 *   id = "your_block",
 *   admin_label = @Translation("YourBlock")
 * )
 */
class YourBlock extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {

    $nid = 2;
    $entity_type = 'node';
    $view_mode = 'teaser';

    $view_builder = \Drupal::entityTypeManager()->getViewBuilder($entity_type);
    $storage = \Drupal::entityManager()->getStorage($entity_type);
    $node = $storage->load($nid);
    $build = $view_builder->view($node, $view_mode);

    return $build;

  }

  ...

```

I'm sure with a little effort you can continue this by using blockForm, blockSubmit to set the node id/type/view\_mode etc.
> 2 votes

# Answer
There's a module for that now: Quick Node Block. \m/
> 0 votes

---
Tags: nodes, 8, blocks
---


# Question
Title: Programmatically add values in a select field: issues when submitting
I'm inserting some options in the #options element of the select render array:

```
foreach ($files['files'] as $file) {
    $form['field_session_row']['widget'][0]['subform'][$field_name]['widget']['#options'][$file['ll_id']] = $file['ll_name'];
}

```

This ends in an error under the select:

```
The value you selected is not a valid choice.

```

I've also tried to set the `#validated` element to `TRUE` and unsetting the `#element_validate` in order to bypass the form element validation. However, when I submit the form I get the following error:

```
TypeError: Drupal\Core\Field\WidgetBase::massageFormValues(): Argument #1 ($values) must be of type array, string given, called in /var/www/vhosts/newEcmwf/web/core/lib/Drupal/Core/Field/WidgetBase.php on line 400 in Drupal\Core\Field\WidgetBase->massageFormValues() (line 547 of core/lib/Drupal/Core/Field/WidgetBase.php).

```

Dumping `$values` it turns out `$values` when the error is triggered is `_none`.

How can I fix it?

Thanks

Code: Code (optimized and changed compared to the other thread):

```
/**
 * Implements hook_form_alter().
 *
 * @throws \Drupal\Core\Entity\EntityStorageException
 *
 * @noinspection PhpUnusedParameterInspection
 * @noinspection PhpUnused
 * @noinspection UnusedFunctionResultInspection
 */
function livelink_form_alter(array &$form, FormStateInterface $form_state, $form_id): void {
    if ($form_id === 'node_committee_session_form' || $form_id === 'node_committee_session_edit_form') {
        foreach ($form as $field_id => $field) {
            if (preg_match('/^field_livelink_field_document_..$/', $field_id)) {
                $id = Arr::get($form, "$field_id.widget.0.value.#default_value");
                Arr::set($form, "$field_id.widget.0.list-button", [
                  '#type' => 'button',
                  '#name' => "button_$field_id",
                  '#value' => !empty($id) ? t('Refresh') : t('List'),
                  '#attributes' => ['onclick' => 'return (false);'],
                  '#ajax' => [
                    'callback' => 'livelink_get_files_callback',
                    'wrapper' => "$field_id-folder-info",
                    'effect' => 'fade',
                    'related_field' => $field_id,
                    'select_field' => str_replace('field_livelink_', '', $field_id) . '_select'
                  ],
                ]);
                Arr::set($form, "$field_id.widget.0.folder-info-div", [
                  '#markup' => !empty($id) ? livelink_render_files_from_cache($id) : '',
                  '#prefix' => "<div id='$field_id-folder-info'>",
                  '#suffix' => '</div>',
                ]);
            }
        }

        $session_rows = Arr::where(Arr::get($form, 'field_session_row.widget'), fn ($item, $key) => is_int($key) && is_array($item));
        foreach ($session_rows as $index => $session_row) {
            $subform = &$form['field_session_row']['widget'][$index]['subform'];

            $fields = collect($subform)
              ->filter(fn($value, $field_name) => preg_match('/^field_document_.._select$/', $field_name));
            foreach ($fields as $field_name => $value) {
                $select = &$subform[$field_name]['widget'];
                $select['#prefix'] = "<div class='livelink-field-wrapper' id='{$field_name}_$index'>";
                $select['#suffix'] = '</div>';
                // Get files
                $field = str_replace('_select', '', $field_name);

                // Load files options
                $folder_id = Arr::get($form, "field_livelink_$field.widget.0.value.#default_value");
                if ($folder_id) {
                    $files = livelink_load_files_cache($folder_id);
                    foreach (array_column($files, 'll_name', 'll_id') as $id => $name) {
                        $select['#options'][(string) $id] = $name;
                    }
                }
            }
        }
    }
}

/**
 * AJAX callback to trigger querying a file list from Livelink.
 *
 * @noinspection PhpUnused
 * @noinspection PhpUnusedParameterInspection
 */
function livelink_get_files_callback(array &$form, FormStateInterface $form_state, string $language): AjaxResponse {
    $ajax_info = $form_state->getTriggeringElement()['#ajax'];

    $response = new AjaxResponse();

    $id = $form_state->getValue($ajax_info['related_field'])[0]['value'];
    if ($id) {
        try {
            $response->addCommand(new HtmlCommand('#' . $ajax_info['wrapper'], livelink_render_new_files($id)));
        } catch (GuzzleException) {
            return $response;
        }
        $response->addCommand(new InvokeCommand("[name='{$form_state->getTriggeringElement()['#name']}']", 'val', [t('Refresh')]));

        $response->addCommand(new MessageCommand('The file listing will not be saved until the page is saved.', null, ['type' => 'warning']));

        $files = livelink_load_files_cache($id);
        $files_options = array_column($files, 'll_name', 'll_id');

        $form_state->setRebuild();

        foreach ($form['field_session_row']['widget'] as $index => $widget) {
            if (is_int($index) && is_array($form['field_session_row']['widget'][$index])) {
                $select = $form['field_session_row']['widget'][$index]['subform'][$ajax_info['select_field']]['widget'];

                foreach ($files_options as $id => $name) {
                    $select['#options'][(string) $id] = $name;
                }
                $response->addCommand(new ReplaceCommand("div.livelink-field-wrapper[id^='{$ajax_info['select_field']}']", $select));
            }
        }
    }

    return $response;
}

```

# Answer
The answer was in this comment: https://drupal.stackexchange.com/a/264719/108326 Basically you have to override the allowed\_values function of the field and set the new options
> -1 votes

---
Tags: forms, 9
---


title: image styles not being created

text:
# Question
Title: image styles not being created
I've got a production site running 9.4.6 in which each user profile includes an image, and the image has to appear as both a thumbnail and as max325 image styles at various points. These image styles are not being created. I carefully followed all suggestions here without luck. You can see the problem here if that's helpful.

# Answer
Turns out my web host had nginx installed. It wasn't in their help files and I wasn't aware. As soon as that was removed, the image styles created smoothly. Thanks for all your comments!
> 0 votes

---
Tags: 9
---


# Question
Title: Using Twig how can I get the summary of the body field to use in a template?
So I have a textarea with summary and I want to display the summary before the content. So if I just use `{{ content.body }}` the text is displayed without the summary.

How can I get the summary ?

`{{ content.body.summary }}` doesn't seem to do the trick

# Answer
In your THEME.theme file you can just define it too:

```
function THEME_preprocess_node(&$variables) {
$variables['node_teaser'] = ['#markup' => $variables['node']->body->summary];
}

```

And then display it with:

```
{{ node_teaser }}

```
> 5 votes

# Answer
The only way I managed to solve this is:

if you only want to target the value of the summary, you can target the entity you're on. If you're on a node then you can do this :

```
node.body.summary

```

In a paragraph

```
paragraph.field_body.summary

```

You can also get the summary front content like this :

```
content.body['#object'].body.summary

```

Not great but will do for now.
> 27 votes

# Answer
To build on what 4k4 wrote (and updated for 2018):

You first choose the way you'd like the field formatted, then you print it.

1) Go to Structure \> Content Types \> YOUR CONTENT TYPE \> Manage Display \> YOUR VIEW MODE.

2) Under the "Formatter" column, choose "Summary or Trimmed."

3) Save.

4) In your twig file you should be able to just print {{ body }} (this is what works for me, but correct me if I'm wrong and I'll update).

This works for me using the node in a View block, and should work on the node as well.
> 3 votes

# Answer
I got it to work by simply using

```
{{ content.field_description['#items'][0].summary }}

```

wherein my description field is field\_description
> 2 votes

# Answer
It depend on how you have configure the body field. By default, Drupal has content.body; however, many Drupal developers avoid using it "as it comes" because its particular process may cause issues. If you go to *Structure \> Content Types \> YOUR CONTENT TYPE*, you can see the name of your field. On *Structure \> Content Types \> YOUR CONTENT TYPE \> Manage Display \> YOUR VIEW MODE*, you can change how your field is rendered and add different view modes to use for specific use cases. Finally, if you haven't been able to find a solution for your project, you could use devel or kint debug to see your project configuration and find the correct answer.
> 0 votes

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


# Question
Title: How to set a URL alias for a custom entity type generated with drush?
I created a custom content entity type with the command `drush generate entity:content`. Now I want to set a URL alias pattern at `/admin/config/search/path/patterns`, but my new custom content entity type is not available. How can I add URL aliases to this type?

# Answer
The custom entity type needs to have a `path` base field.

You can add it to `/src/MyEntity.php` in the `baseFieldDefinitions()` function:

```
$fields['path'] = BaseFieldDefinition::create('path')
  ->setLabel(t('URL alias'))
  ->setTranslatable(TRUE)
  ->setDisplayOptions('form', [
    'type' => 'path',
    'weight' => 30,
  ])
  ->setDisplayConfigurable('form', TRUE)
  ->setComputed(TRUE);

```

Note that you need to uninstall the module containing the entity definition, make this change, and then re-enable the module, or run a database query to avoid messing up your DB.

Reference: Discussion on changing the way this is handled in core
> 1 votes

---
Tags: entities, 9
---


# Question
Title: Get parent Paragraph Entity from Referenced View
I have a custom paragraph type - which has 2 fields:

* `Display Mode`,
* `View` to be rendered

I want to let users choose `Display Mode` in this paragraph, then I will render `view` dynamically based on this `Display Mode` value.

The problem is, it seems there is no way to get this `Display Mode` value inside view template(`views-view-unformatted.html.twig`) or hook (`HOOK_preprocess_views_view`).

Only what I can access is `view object`, which definitely does not have any parent entity info.

Any idea?

# Answer
All entities (\*) in Drupal are meant to be stand-alone and self-contained, so do it the other way round: Instead of querying upwards from the view, pass the field value downwards from the paragraph template to the view as a parameter.

E.g. create a `paragraph.html.twig` template and then call the view with the paramater from your paragraph field (using the Twig Tweak module):

```
{{ drupal_view('my_view_id', paragraph.field_display_mode.0.value) }}

```

The first parameter of `drupal_view` is the machine name of the view, the 2nd parameter is the machine name of the display in that view.

(\*) Paragraphs is kind of an exception as it is by data-model explicitly designed to be directly depending on a parent entity.
> 0 votes

# Answer
It sounds like you need Viewsreference. With this you just need 1 field on the paragraph, the viewsreference field, which provides a widget to select the view (autocomplete, or select) and the display ID, as well as it lets you limit to pre-defined list of views, and display types.
> 0 votes

---
Tags: views
---


# Question
Title: How to replace the default text of the home page, when it is empty?
On the Drupal 9 home page, there is a text displayed by default, when no content has been created.

I want to modify the text of this page, when there is no result. I go to the "frontpage" view and add an unfiltered text field in "Behavior when there are no results".

My problem is that it has no effect. I still have the default text that appears.

How to replace the default text of the home page, when it is empty ?

# Answer
Based on who is asking I assume this is Olivero theme and this is about the "Congratulations and welcome to the Drupal community" message, although you did not specify. If that is the case, you must override the template `core/themes/olivero/templates/views/views-view--frontpage.html.twig`.
> 1 votes

---
Tags: views, 9
---


title: Get Translated Field Label for Entity

text:
# Question
Title: Get Translated Field Label for Entity
I have a field I have translated. But I can not figure out how to get that translated field label programmatically. I've found a few posts on here, but none of them work for me.

Pretty easy to get the default field label:

```
$fieldDefinition = $model->get($field)->getFieldDefinition();
$fieldLabel = $fieldDefinition->getLabel();

```

Does anyone know a way to get that in 2022?

I thought the answer might lie in here somewhere, but so far no luck. Just trying to grab the spanish translation right now...

```
$language_manager = \Drupal::languageManager();

$language = $language_manager->getLanguage('es');
$original_language = $language_manager->getConfigOverrideLanguage();
$language_manager->setConfigOverrideLanguage($language);

```

Any help would be great.

# Answer
> 0 votes
Config translation works in the background as override. So you don't need to do anything.

Unless have a very specific use cases, like sending an email in a different language. Then you can change the config override language, like the code you've shown so far, and reset it after you've sent the email:

```
use Drupal\Core\Field\Entity\BaseFieldOverride;
use Drupal\field\Entity\FieldConfig;

...

$language_manager = \Drupal::languageManager();

$language = $language_manager->getLanguage('es');
$original_language = $language_manager->getConfigOverrideLanguage();
$language_manager->setConfigOverrideLanguage($language);

// load a new field definition object instead of referencing the one stored in the entity
// in case of a translated base field:
$field_definition = BaseFieldOverride::loadByName($entity->getEntityTypeId(), $entity->bundle(), $field_name);
// in case of a translated configured field:
$field_definition = FieldConfig::loadByName($entity->getEntityTypeId(), $entity->bundle(), $field_name);

$field_label = $field_definition->getLabel();

$language_manager->setConfigOverrideLanguage($original_language);

```

---
Tags: 9
---


# Question
Title: How to add Flag Link field to view based on Search Index?
So, I am building a faceted search view on my product display, but I cannot add the field for the Flag link. I can get fields that reference the User's who used a flag, but no relationship that I can add, allows me to access my flag link as a field.

There are references to this problem Add Flag link to Search Index and Flag Module Integration, but no obvious solution. Thoughts? Recipies?

# Answer
> 0 votes
This doesn't work out of the box, but there's a patch for this https://www.drupal.org/node/1362298

# Answer
> 0 votes
Here's the answer for Drupal 8/9

This is how I accomplished this task. I'm making the assumption the flag has already been created and that it has "Display link as field" checked in it's configuration. Also this howto is tailored to nodes, but it can be used on any other entity type as well with a few adjustments to urls and pathways to where the display modes are edited:

1. To make the Title field configurable on nodes, in a custom module add the following hook as defined over at https://drupal.stackexchange.com/a/178476/5638. This only applies if the content you are working on are nodes. Custom entities can usually skip this step.

```
function mymodule_entity_base_field_info_alter(&$fields, $entity_type) {
  if ($entity_type->id() == 'node') {
    if (isset($fields['title'])) {
      $fields['title']->setDisplayConfigurable('view', TRUE);
    }
  }
}

```
2. Navigate to Structure -\> Display Modes (/admin/structure/display-modes)
3. Click on "View Modes" (/admin/structure/display-modes/view)
4. Scroll down and click on Add new Content view mode (/admin/structure/display-modes/view/add/node)
5. Type in the name "Favorite Field" and click Save
6. Navigate back to Structure -\> Content Types (/admin/structure/types)
7. Click Manage display next to a content type you want to show the favorite field for in your view.
8. Click on Custom Display Settings to expand it
9. Select "Favorite Field"
10. Click Save
11. Select the "Favorite Field" tab from the top
12. Remove all fields except your favorite field
13. click Save.
14. Repeat steps 6-13 for each content type you wish to display in your search API View.
15. Navigate to Structure -\> Views
16. Click Edit next to your view
17. In the fields section of your view click "Add"
18. Make sure to Check the "For" drop down incase you want it only for this display
19. In the search, type "rendered"
20. Choose "Rendered Item"
21. Click Apply
22. Choose your options as you wish to format this field
23. Make sure you choose "Favorite Flag" from Display Mode.
24. Click Apply

At this point, if your content is indexed, you should see in the preview, the "I Like" link show up and should be have as configured. Here is a quick screenshot of a test view I did

And another instance in the wild with a custom entity using the OpenKJ module and the table display plugin instead of unformatted list. Flag's Javascript links work and everything.

---
Tags: views, commerce, search, flags
---


# Question
Title: How do I free a variable set using variable_set()?
I have used `variable_get()`, and `variable_set()` in my form search, but when I visit another page, and come to the module again, it shows the previous results. How can I free the variable at the time of reloading the module?

```
/**
* @file
* The theme system, which controls the output of Drupal.
*/
function myform_help($path, $arg) {
    switch ($path) {
        case "admin/help#myform":
        return '<p>' . t("MyForm Module") . '</p>';
        break;
    }
}

function myform_menu() {
    $items['myform/newform'] = array(
        'type' => MENU_CALLBACK,
        'access arguments' => array('access content'),
        'page callback' => 'drupal_get_form',
        'page arguments' => array('myform_newform'),
        'access callback' =>TRUE
    );
    return $items;
}

function myform_newform($form, &$form_state) {
    //Create a list of headers for your Html table (see Drupal 7 docs for theme_table here

    $form['search'] = array(
        '#type' => 'textfield',
        '#title' => t('Search for Members'),
        '#size' => 60,
        '#maxlength' => 128
    );
    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => t('Search'),
        '#submit' => array('myform_newform_submit'),
    );
    $header = array(
        // The header gives the table the information it needs in order to make
        // the query calls for ordering.
        array('data' => t('ID'), 'field' => 't.id'),
        array('data' => t('First Name'), 'field' => 't.fname'),
        array('data' => t('Last Name'), 'field' => 't.lname'),
    );

    if((variable_get('results'))!="") {
        $query = db_select('myform', 't')
            ->extend('TableSort')        //Sorting Extender
            ->orderByHeader($header)
            ->extend('PagerDefault')
            ->condition('lname',variable_get('results'),'=')
            ->limit(2)
            ->fields('t', array('id', 'fname', 'lname'));
        $results = $query->execute();
        foreach($results as $node)
        {
            $rows[$node->id]=array('data'=>(array)$node);
        }
    }
    else {
        $rows = array();
    }
    $form['pager_table'] = array(
        '#theme' => 'table',
        '#header' => $header,
        '#rows' => $rows,
        '#empty' => t('Empty Rows')
    );
    // attach the pager theme
    $form['pager_pager'] = array('#theme' => 'pager');
    return $form;
}

function myform_newform_submit($form,&$form_state) {
    variable_set('results',$form_state['values']['search']);
}

```

# Answer
> 0 votes
In this specific case, you don't need to use persistent variables. It's sufficient to set `$form_state['rebuild']` to `TRUE` in the form submission handler and set a value in the `$form_state` array that is then checked by the form builder function. The workflow in these cases is the following.

* The form is used to ask input from users
* The form submission handler uses that input to query the database and stores the result in `$form_state` (for example, in `$form_state['rows']`)
* The form submission handler sets `$form_state['rebuild']` to `TRUE`
* The form builder checks the value in `$form_state` is set (for example, with `if (isset($form_state['rows'])) { /* ... */ }`) and shows those values in a table before the form

The array key used to store the value just needs to be a key that doesn't conflict with Drupal core or contributed modules core. To avoid that, the key name is usually prefixed by the module machine name (or it's the module machine name).

---
Tags: forms, configuration
---


# Question
Title: How to display a block on the home page when the user is authenticated or anonymous?
I created two custom blocks. I want to display its two blocks only when the home page view is empty.

I want the custom block with id 11 to be displayed for anonymous users.

I want the custom block with id 12 to be displayed for authenticated users.

So I copied the `views-view--frontpage.html.twig` template into my sub-theme.

What should I add in the code, to obtain this result ? Thanks

```
  {% if rows %}
    <div class="view-content">
      {{ rows }}
    </div>
  {% elseif empty %}
    {{ empty }}
  {% endif %}

```

# Answer
The title to this question asks a pretty simple question, but the need to show content based on user login complicates things a bit.

There are several ways to accomplish your task, including creating a custom Views Area Handler Plugin where you render the blocks you want programmatically with the if statement checking for a logged in user. See How to create a simple views area plugin. You would then set that plugin in the "No results behavior" section of your view.

Another way would be to use views hooks found in views.api.php to accomplish this. Keep in mind the views hook run order. In this way, you likely add both blocks to the "No results behavior" using the "Global: Rendered entity - Custom block" plugin. In likely any of `hook_views_post_build`, `hook_views_pre_execute`, `views_post_execute`, or `views_pre_render` would do the same check to see if a user is logged in but remove one of the blocks from the `empty` portion of the view's display options based on the results.

If you want to do this in the theme layer, (which I'm making an assumption you do since you posted a twig file), you will need to use a preprocessor for your view, setting a variable to check to see if the user is logged in with a solution simular to this one. Then I would suggest installing and using Twig Tweak and using twig to render the blocks you want as defined in their documentation.

Your preprocessor would end up something like:

```
function mymodule_preprocess_views_view(&$variables) {
  if ($variables['view']->id() == 'frontpage') {
    $variables['logged_in'] = \Drupal::currentUser()->isAuthenticated();
  }
}

```

Your twig would end up looking something like

```
  {% if rows %}
    <div class="view-content">
      {{ rows }}
    </div>
  {% elseif empty %}
    {% if logged_in %}
      {{ drupal_entity('block_content', '12' ) }}
    {% else %}
      {{ drupal_entity('block_content', '11' ) }}
    {% endif %}
  {% endif %}

```
> 0 votes

---
Tags: views, theming, blocks, 9
---


# Question
Title: Remove duplicated email in views data export
My site contains users with duplicated emails which is fine for my use case.

I need to export the user's fields into an xlsx but, this time, without duplicated email. For this I have created a Users view with a Data Export display attached to it and I have added the following code:

```
function mymodule_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  if ($view_id == 'my_view' && $display_id == 'my_export') {
    $query->addField('users_field_data', 'mail', '', [
      'function' => 'groupby',
    ]);
    $query->addGroupBy('users_field_data.mail');
  }
}

```

This kind of code is working well on the node table to remove duplicated ID:

Example:

```
  $query->addField('node', 'nid', 'node_nid', [
    'function' => 'groupby',
  ]);
  $query->addGroupBy('node.nid');

```

But it is not working to remove the duplicate emails... any idea on what is wrong?

Here is the query like it is showed by the views GUI:

```
SELECT "users_field_data"."langcode" AS "users_field_data_langcode", "users_field_data"."uid" AS "uid", "user__field_user_address"."field_user_address_postal_code" AS "user__field_user_address_field_user_address_postal_code", "users_field_data"."created" AS "users_field_data_created", MIN(users_field_data.uid) AS "uid_1"
FROM
{users_field_data} "users_field_data"
LEFT JOIN {user__field_user_address} "user__field_user_address" ON users_field_data.uid = user__field_user_address.entity_id AND user__field_user_address.deleted = '0'
WHERE "users_field_data"."uid" != '0'
GROUP BY users_field_data.mail, users_field_data_langcode, users_field_data.uid, user__field_user_address_field_user_address_postal_code, users_field_data_created
ORDER BY "users_field_data_created" DESC

```

# Answer
> 1 votes
Since the uid is not unique, you need to remove this group by condition. Try to change your query to

```
function mymodule_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  if ($view_id == 'my_view' && $display_id == 'my_export') {
    $query->addField('users_field_data', 'mail', '', [
      'function' => 'groupby',
    ]);
    $query->groupby = ['users_field_data.mail'];
  }
}
```

This will only group by the email field and will remove this duplicates.

---
Tags: views
---


# Question
Title: How to make Drupal to login and send email via Gmail?
I have a Drupal 9 website with a core contact form (I don't use Webform).

I have two Gmail accounts, one by which I want to send email and one to which I should receive the email.

So I need a way to make Drupal log in to my *Gmail\_account\_1* and use it to send email (contact form inquiries) from it to my *Gmail\_account\_2*.

I think that in the Linux world this methodology is named *sSMTP*.

# Answer
You can do this with the SMTP module, but Gmail has some odd configuration and you may run into issues, including having to manually log in to the Gmail account and check "allow insecure apps" every few weeks.

So I would recommend not doing this and instead using a professional mail service like SendGrid to send mail instead.
> 1 votes

---
Tags: 9, emails
---


# Question
Title: All routes resolve to entity.user.edit_form for authenticated users
This is a new one for me:

All routes, for an authenticated user, resolve to `entity.user.edit_form`.

Anonymous users are able to browse all public-facing pages of the site without any problems.

This is the route:

```
$ ddev drush core:route --name=entity.user.edit_form
name: entity.user.edit_form
path: '/user/{user}/edit'
defaults:
  _entity_form: user.default
  _title_callback: 'Drupal\user\Controller\UserController::userTitle'
requirements:
  user: \d+
  _entity_access: user.update
options:
  _admin_route: true
  parameters:
    user:
      type: 'entity:user'
      converter: paramconverter.entity
  _access_checks:
    - access_check.entity

```

There doesn't seem to be anything wrong with this particular route -- it's all the *other* ones that don't behave as expected.

For what it's worth:

```
Drupal version   : 9.4.5
PHP version      : 7.4.30

```

The problem surfaced on a remote production site running on Microsoft Azure (Kudu / IIS); I have imported its database, for testing purposes, into a DDEV-Local environment (Docker / Linux).

In the remote environment, the following route-related errors appeared in the dblog:

```
$ ddev drush ws
 --------- -------------- ------------------ ---------- -------------------------------------------------
  ID        Date           Type               Severity   Message
 --------- -------------- ------------------ ---------- -------------------------------------------------
  5692475   04/Oct 20:10   php                Error      Symfony\Component\Routing\Exception\RouteNotFou
                                                         ndException: Route "devel.configs_list" does
                                                         not exist. in
                                                         Drupal\Core\Routing\RouteProvider->getRouteByNa
                                                         me() (line 206 of D:\home\site\wwwr
  5692474   04/Oct 20:10   php                Error      Symfony\Component\Routing\Exception\RouteNotFou
                                                         ndException: Route "devel.configs_list" does
                                                         not exist. in
                                                         Drupal\Core\Routing\RouteProvider->getRouteByNa
                                                         me() (line 206 of D:\home\site\wwwr
  5692473   04/Oct 20:10   php                Error      Symfony\Component\Routing\Exception\RouteNotFou
                                                         ndException: Route "devel.configs_list" does
                                                         not exist. in
                                                         Drupal\Core\Routing\RouteProvider->getRouteByNa
                                                         me() (line 206 of D:\home\site\wwwr
  5692472   04/Oct 20:10   php                Error      Symfony\Component\Routing\Exception\RouteNotFou
                                                         ndException: Route "devel.configs_list" does
                                                         not exist. in
                                                         Drupal\Core\Routing\RouteProvider->getRouteByNa
                                                         me() (line 206 of D:\home\site\wwwr
 --------- -------------- ------------------ ---------- -------------------------------------------------

```

In the DDEV-Local environment, I executed the following commands:

```
$ ddev drush eval '\Drupal::service("router.builder")->rebuild();'
$ ddev drush cr
 [success] Cache rebuild complete.

```

After rebuilding the routes, the error no longer appears in the logs; however, all routes now arrive at the logged-in user's profile edit form.

In comments, @jaypan said:

> Disable the devel module and any devel related modules, and see if that resolves it.

This is a good suggestion. Those modules are already disabled:

```
$ ddev drush pml |grep devel
  Development                          Devel (devel)                           Disabled   4.1.3
  Development                          Devel Generate (devel_generate)         Disabled   4.1.3
  Webform                              Webform Devel (webform_devel)           Disabled   6.1.2

```

They are present in the `composer.json`:

```
$ grep devel composer.json
        "drupal/devel": "^4.1",
        "drupal/devel_generate": "^4.1",

```

I am able to enable them without error:

```
$ ddev drush en devel devel_generate
 [success] Successfully enabled: devel, devel_generate

```

This does not fix the routes.

I am able to disable them without error:

```
$ ddev drush pmu devel devel_generate
 [success] Successfully uninstalled: devel, devel_generate

```

This also does not fix the routes.

The previous developer was unable to use Drush in this environment and appears to have been using raw SQL queries to clear caches (`truncate` all the cache tables) and disable modules. The errors are quite likely related to that approach.

# Update (2022-10-07)

In comments, @cilefen asked:

> Did any known platform or codebase change precipitate this? Are any custom modules installed? Is there a version control log? Have you restored from backups to identify when or how this changed?

I still do not have access to the client's VPN, so I can't access their version control repositories directly. We have restored the database from backups that predate the problem, so I now think the problem may be caused by Azure DevOps being configured to deploy the built artifact on top of the previously-installed files.

Troubleshooting from another angle, I have used `curl` to capture an authentication cookie:

```
$ curl --cookie cookie.txt --cookie-jar cookie.txt $(ddev drush uli)

```

Now, when I use `curl` to request a page as an authenticated user, I receive this:

```
$ curl --cookie cookie.txt https://clientsite.ddev.site
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   414    0   414    0     0   3568      0 --:--:-- --:--:-- --:--:--  3568
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="refresh" content="0;url='https://clientsite.ddev.site/user/1/edit'" />

        <title>Redirecting to https://clientsite.ddev.site/user/1/edit</title>
    </head>
    <body>
        Redirecting to <a href="https://clientsite.ddev.site/user/1/edit">https://clientsite.ddev.site/user/1/edit</a>.
    </body>
</html>%

```

This appears to show that the redirect is caused by `<meta http-equiv="refresh" content="0;url='https://clientsite.ddev.site/user/1/edit'" />` rather than by corruption in the routing table.

I hope I'm getting close to resolving this. (If not, I might add a bounty to the question in 10 hours!)

# Answer
> 0 votes
I figured out what was causing the redirect, and it was something perfectly normal and obvious: the Password Policy module.

I had been using `drush uli` to log in as User 1, but the site had a password expiry policy, and User 1 had not logged in for a long time ... so its password was expired.

I'm just so used to ignoring the message that says "change your password" that I didn't read it :)

Resetting the User 1 password made the redirect go away.

I might open an Issue Queue for Password Policy to suggest that the module should implement a different route to reset the password, rather than re-using the default profile edit page.

---
Tags: routes, 9
---


title: Combining line items in cart

text:
# Question
Title: Combining line items in cart
I am trying to "hide" individual line item values on my shopping cart. Is there a way to combine line items (possibly based on a term applied to each) such that they show as 1 item with the subtotal as the unit price?

As an example:

ungrouped:

* item A - $100
* item B - $50
* item C - $25
* item D - $200
* item E - $50
* item F - $25

grouped

* item A, B, C - $175
* item D, E, F - $275

where line items A, B, C would be tagged when added to cart as Group 1 and C, E, F would be tagged with Group 2.

I am not sure this is doable in the View directly; but possibly in one of the view alter hooks?

## Update:

I am able to use hook\_views\_pre\_render on the commerce\_cart\_form. From there I can access the line items, evaluate them and remove the line items I want to group in to main item. I just need to sort out what I need to modify to alter the displayed price of the main item. My guess is that I can't easily to do it here without saving the Order Item. I don't really want to modify the Order at all. I just want to display the cart differently.

## Update 2:

Starting to think this is not possible without modifying the stored line item entity. Even preprocessing the Views table where I have access to each cell of the table; it seems as though $variables\['rows'\] does not use its values from the preprocess function.

Perhaps JS is the only (ugly) was to accomplish this. :(

# Answer
> 0 votes
Wouldn't it be more accurate to use attributes on the line items?

Or why do you have this "hidden" line items?

---
Tags: commerce, 9
---


# Question
Title: Link tags in template file auto closing.
I’m having an issue wrapping a link around some output in a template file. I have the right template file; and I can put text like ‘start here’ and ‘end here’ and it prints out where I want the ‘a href’ tag to start and end.

However when I put in the starting ‘a href’ it auto closes. I can put in a ‘div’ and that doesn’t auto close. I’ve tried `<div href="javascript:void(0)" onclick="window.location.assign("'.$link.'")” >` and although that html output looks right it doesn’t work either.

I’ve also used at ‘function l’ but can’t pass the $content in.

Any ideas how I can either stop the auto close, get the javascript to work or a function I can use to output the link but will except the content being passed in.

Here's my code

```
print '<a href="'.$link.'" >';
     print $field->content;
     print '</a>';

```

# Answer
> 0 votes
The problem here was that there where links in the content being outputted. Once I changed that the links stopped auto closing.

# Answer
> 0 votes
Use filter\_xss on `$field->content`. You can filter out the anchor tags this way.

---
Tags: theming, navigation
---


# Question
Title: In a template, is it possible to get the content of a block by the block ID?
I am working with some view templates in Drupal 8, and I have the block ID of another view block I want to pull into the template. Is it possible to use the block ID to get the content of a block in a template?

If this is not possible in Twig, how could I achieve this otherwise?

# Answer
Yes take a look at this module :

> Twig Blocks

https://www.drupal.org/project/twig\_blocks

After module install just call the block like this in the template :

```
{{ render_block('machine_name_of_your_block') }}

```

Or in a hook :

```
function hook_preprocess_page(&$variables)
{

    $block = \Drupal\block\Entity\Block::load('id_block');

    $variables['myBlock'] = \Drupal::entityTypeManager()
        ->getViewBuilder('block')
        ->view($block);

}

```

Then in your twig template :

```
  {{ myBlock }}

```
> 0 votes

# Answer
Yes by using twig tweaks. See the cheat sheet for blocks and more.

> The greater issue is here is that I am using a plugin that lets the user choose whatever views block they want so I won't know what the machine name of the block is

Pass the ID in as a variable and use

```
{# Print block using default configuration. #}
{{ drupal_block( block_id ) }}

```
> 0 votes

---
Tags: views, theming, blocks
---


# Question
Title: uninstall module that depends on relation module, which is disabled
I am a maintainer of the crm\_core module. The Drupal7 version depends on the relation module to provide relationships between contacts. The depend module can not be uninstalled while the relation module is disabled.

Is there a solution? Or, is this one of the limitations of disabling modules, which might be why disable was dropped in Drupal8.

2273255 - Can't uninstall crm\_core\_relationship when relation module has been disabled

# Answer
> 0 votes
The issue described in Can't uninstall crm\_core\_relationship when relation module has been disabled is that `crm_core_relationship_uninstall()` is calling functions defined in a disabled module. When a module is disabled, Drupal won't load it, and all the module functions won't be available.

Either `crm_core_relationship_uninstall()` first loads that module file with `drupal_load('module', 'relation')`, before calling its functions, or the code in `relation_delete()` and `relation_type_delete()` is duplicated in functions accessible from `crm_core_relationship_uninstall()`.

That issue isn't present in Drupal 8, as in Drupal 8 modules can only installed or not installed; they cannot be anymore disabled as in Drupal 7.

---
Tags: 7
---


# Question
Title: Creating a category page when using the Search API module
I’m trying to build a Drupal Commerce store which is going to be my first timer with Drupal 8+. However, the approach described in the Drupal Commerce documentation regarding the creation of a filterable product catalog really doesn’t seem to be what you usually see on a good e-commerce site.

Having only a page to display products from all categories seems to be SEO counter-intuitive.

How can I create a product catalog with categories that list the products in that particular category but, for example, also list the sub-terms of the currently selected term as well?

There isn't really a showcase where I could look at different shops using Drupal Commerce 2 as if nobody was event using it. All the ones I found on Drupal Commerce official pages are either not working or use Commerce 1.

# Answer
> 1 votes
I finally found a solution... You can use the https://www.drupal.org/project/tvi module on the vocabulary for product categories. You then set up a Product Index view with a url of taxonomy/term/% and enable a context filter to search in product categories. Works like a charm!

# Answer
> -1 votes
I found the tutorials at https://www.acromedia.com/article/creating-a-product-catalogue-with-search-api-solr-facets (with video) as well as the official documentation at https://docs.drupalcommerce.org/commerce2/developer-guide/products/marketing-products/product-catalog-facets pretty straightforward to follow.

To summarize: you assign a category to each product, then create a view that lets the customer choose which category to view. I can't explain the details better than those tutorials though.

---
Tags: views, commerce, taxonomy-terms, search
---


# Question
Title: entity_autocomplete attached via #ajax callback doesn't work
I'm serving an entity\_autocomplete field via #ajax callback when a checkbox in the form is unchecked.

The entity\_autocomplete field shows but there is no autocomplete attached to it.

Here is how I attached it from within ajax callback:

```
$form['url_301'] = [
  '#type' => 'entity_autocomplete',
  '#target_type' => 'node',
  '#required' => TRUE,
  '#prefix' => '<div id="edit-output">',
  '#suffix' => '</div>',
];
$form['url_301'] = EntityAutocomplete::processEntityAutocomplete($form['url_301'], $form_state, $form);

return $form['url_301'];

```

How can I resolve this?

# Answer
Found a solution.

The `entity_autocomplete` field should be prepared/set within `hook_form_alter()`, not within `ajax_callback()`

And it should be returned within `ajax_callback()`.

Here is an example:

```
function hook_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  $status = $form_state->getValue('status')['value'];

  if ($status === 0) {

    $form['url'] = [
      '#type' => 'entity_autocomplete',
      '#target_type' => 'node',
      '#title' => t('My autocomplete field'),
      '#required' => TRUE,
      '#prefix' => '<div id="edit-output">',
      '#suffix' => '</div>',
    ];

  }

  $form['output'] = [
    '#markup' => 'Output',
    '#prefix' => '<div id="edit-output">',
    '#suffix' => '</div>',
    '#weight' => 100,
  ];

  $form['status']['widget']['value']['#ajax'] = [
    'callback' => '_my_ajax_callback',
    'event' => 'change',
    'wrapper' => 'edit-output',
    'progress' => [
      'type' => 'throbber',
      'message' => 'Processing...',
    ],
  ];
}

function _my_ajax_callback(array &$form, FormStateInterface $form_state) {

  $status = $form_state->getValue('status')['value'];

  if ($status == 0) {
    return $form['url'];
  }
  else {
    return [
      '#prefix' => '<div id="edit-output">',
      '#suffix' => '</div>',
    ];
  }
}

```
> 0 votes

---
Tags: 9
---


# Question
Title: How to unpublish content that is under moderation
I am using the Content Moderation module in Drupal 8.2 and I have noticed there is no way to re-unpublish a node once it has been moderated into a published state. I'm able to create a new draft of the content and moderate that through to published state but I can't find a way to actually unpublish the node.

There is a bug issue on DO that seems related, but looking at the patch it only adds a message informing you that you can't unpublish content directly once under moderation. Which makes sense as having content moderation enabled means you are handing over control of publish/unpublish to that module. But that leaves the question of how to actually unpublish a node that is under moderation?

I understand this module is currently experimental but am fairly sure I am missing something here.

# Answer
You can enable the default revision for all the states. If there is any transition in any state from publish to draft or any state.
> 7 votes

# Answer
Although Sumit Madan solution explains what is the reason and how you can have unpublished/published content with moderation state still you are not able to update bulky.

This is a solution I found for my cause, it may be helpful for others,

first, install https://www.drupal.org/project/moderated\_content\_bulk\_publish module.

second, if you don't have `archived` state, create it. you can label it to whatever you want but machine name should be `archived` ( because moderated\_content\_bulk\_publish acts based on that).

then go to your `admin/content` page and bulky **Publish/unpublish current revision**.

That's it. there will be no **"One or more entities were skipped as they are under moderation and may not be directly published or unpublished"** warning anymore
> 1 votes

# Answer
I invit you to have a look to my comment (link below) on the default behaviour of this module "Workflow" and how you can create a "Draft unpublish" state to unpublish your content after it has been published.

Workflow: how unpublish a published content by changing the state to "Draft"
> 0 votes

---
Tags: nodes, 8
---


title: Check the active language

text:
# Question
Title: Check the active language
I'm sorry for my bad English. In my node.html.twig I have two layouts for two groups of languages.

1. English, Ukrainian and Bulgarian
2. Arabic, Farsi, Urdu I can't check with twig which is the active language to load one of the two layouts. I tried this but it didn't work. Thanks a lot if anyone can help me

```
{% if language.getId() == 'en' or 'uk' or 'bg' or 'ru' %}

        {{ content.field_mt_srv_body }}
        {{ content.field_sp_working_hours }}
        {{ content.field_sp_additional_information }}
        {{ content.field_mt_srv_video }}

         {{ content.field_sp_street_view }}

       - {{ content.field_sp_city }}

       - {{ content.field_sp_address }}

       - {{ content.field_sp_email }}

       - {{ content.field_field_sp_phone }}

       - {{ content.field_sp_languages }}

       - {{ content.field_mt_srv_tags }}

       - {{ content.field_sp_website }}

       - {{ content.field_sp_facebook }}

{% else %}

        {{ content.field_mt_srv_body }}
        {{ content.field_sp_working_hours }}
        {{ content.field_sp_additional_information }}
        {{ content.field_mt_srv_video }}

         {{ content.field_sp_street_view }}

       {{ content.field_sp_city }}
       {{ content.field_sp_address }}
       {{ content.field_sp_email }}
       {{ content.field_field_sp_phone }}
       {{ content.field_sp_languages }}
       {{ content.field_mt_srv_tags }}
       {{ content.field_sp_website }}
       {{ content.field_sp_facebook }}

{% endif %}

```

# Answer
To get this working in Twig

```
{% if language.getId() == 'en' or 'uk' or 'bg' or 'ru' %}

```

you have to define the variable `language` in a preprocess hook:

*mytheme.theme* or *mymodule.module*

```
/**
 * Implements hook_preprocess_HOOK() for node templates.
 */
function mytheme/mymodule_preprocess_node(&$variables) {
  $variables['language'] = \Drupal::languageManager()->getCurrentLanguage();
}

```

The only template where this variable is predefined is the page template, so that you don't need the preprocess hook. See this core preprocess hook: https://api.drupal.org/api/drupal/core%21includes%21theme.inc/function/template\_preprocess\_page/
> 1 votes

# Answer
In Drupal 8.5.7 and upwards a global variable 'language' exists that can be called directly in twig like example below.

```
{% if language == 'en' %}

```

See this resource here
> -1 votes

---
Tags: nodes, 9
---


# Question
Title: Impossible to use custom fields in twig linked to form
I have a form in which I have two date fields and a filter button. This form is included in a custom view in which I have a table that displays data from the database. The date fields are here to filter the data that I display in the table. I use AJAX in my form with a callback function.

What I want to do is adding the data to my form with the callback function, and displaying it in my twig.

My problem is that the twig is not updated so I cannot display the data from my form after filtering.

Here is my form :

```
class StatistiqueForm extends FormBase {
    /**
    * {@inheritdoc}
    */
    public function getFormId()
    {
        return 'statistique_form';
    }

    /**
     * {@inheritdoc}
     */
    public function buildForm(array $form, FormStateInterface $form_state) {
        $form['date_from'] = array (
            '#type' => 'date',
            '#title' => 'From',
            '#required' => FALSE,
        );

        $form['date_to'] = array (
            '#type' => 'date',
            '#title' => 'To',
            '#required' => FALSE,
        );

        $form['filter_button'] = array(
            '#type' => 'submit',
            '#value' => 'Filter',
            '#ajax' => [
                'callback' => [$this, 'submitDateFilter'],
                'event' => 'click',
            ],
        );

        $form['reset_button'] = array(
            '#type' => 'submit',
            '#value' => 'Reset',
            '#attributes' => array(
                'onclick' => 'this.form.reset(); return false;',
            )
        );

        $form['#theme'] = 'form_statistique_form';
        $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
        return $form;
    }

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

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

    public function submitDateFilter(array $form, FormStateInterface $form_state) {
        $form['#statistique_query_data'] = array(
            '#test' => 'test'
        );
    }
}

```

And in the twig, when using `{{ form['#statistique_query_data']['#test'] }}`, nothing is displayed.

I also tried to add `$form_state->setRebuild()` and `\Drupal::service("router.builder")->rebuild()` in *buildForm* and AJAX callback *submitDateFilter* function, but it's not working better.

EDIT : here is a screen of the view :

What I want to do is when clicking on the "Filter" button, add fields to my form in the *submitDateFilter* function and be able to use these fields in the view. For example, with the above code, be able to display in my twig the field `form['#statistique_query_data']['#test']` in one of the tables. But actually, when I click on the "Filter" button, nothing appears when using `{{ form['#statistique_query_data']['#test'] }}` in the twig.

# Answer
> 0 votes
Found the solution :

In my twig, I added a selector on the element I want to modify :

```
<td><p id='element_to_modify'></p></td>

```

In my form, with the AJAX callback function linked to my "Filter" button, I used the AJAX ReplaceCommand to modify my element with any value, using id selector :

```
public function submitDateFilter(array $form, FormStateInterface $form_state) {
        $response = new AjaxResponse();
        $Selector = '#element_to_modify';
        $content = '<p id=\'element_to_modify\'>new value !</p>';
        $response->addCommand(new ReplaceCommand($Selector, $content, array()));
        return $response;
    }

```

---
Tags: views, forms, ajax, 9
---


# Question
Title: How do I get the value of the Taxonomy Term Description after loading Taxonomy Vocabulary term by Term ID?
What would be the best way to render the Taxonomy Vocabulary Term description value? I can render the term id and label/title, but the description seems to need something else that I'm not quite getting.

```
  // Render ID - working
  $termID = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load(419)->id();

  // Render Label/Title - working
  $termLabel = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load(419)->label();

  // Not sure how to get the description of the taxonomy term - not working
  $termDescription = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load(419)->description();

```

# Answer
> 1 votes
The correct method is getDescription.

---
Tags: taxonomy-terms
---


# Question
Title: Impact of not doing these updates on the CMS
\[

Hello, I am a new hired and tasked to manage a vendor who is supposed to update our website. They have not been doing so, I am not technical enough to know whether these Drupal updates will have a huge impact on us when they are not attended to. I attacked 2 screenshots here and really hope you can shed some lights....very much appreciated.

# Answer
Any updates marked as a **Security update** should be applied as soon as possible.

Security updates by the Drupal Security Team are announced here and, since Drupal is open source, failing to patch your site leaves you open to attacks because people can look at the content of the security announcements and find the vulnerabilities in your site's code. This is why it is important to patch immediately.

Now, not every announcement requires immediate action; to find out how soon you need to act, you have to actually read the security announcements for core/the relevant contrib module. In many cases, there may only be a security problem if users have certain permissions, and if you only have admins and anonymous users (a common setup), you may not have to do anything in that specific case.

In your case, based on the list of modules shown, Entity Print has a security update, which was fixed in version 2.5, which was released on April 11, 2022.

This means that your vendor has ignored an important security patch for over half a year-- pretty terrible performance for which there is not really an excuse. So as @Kevin said, I would find a new vendor.
> 1 votes

---
Tags: updating
---


# Question
Title: How to temporarily override configuration?
I want to be able to contextually modify configuration variables, i.e. within a page controller.

**Example**

I have a custom ad module which besides other settings has an option to globally disable or enable ads. In general the ads are enabled (`\Drupal::configFactory()->get('custom_ads.settings')->get('active') === true`).

On some pages (provided by custom page controller) I want to disable ads. Therefore I was thinking that the easiest way without modifying the custom ad module would be to set custom\_ads.settings.active to false for that specific pages.

I will provide my working solution as answer to this question and would like to have some review comments, especially regarding caching, to be sure to not miss anything that may result in poor performance or worse in disabling ads in general.

# Answer
> 1 votes
Answering my question and looking forward to review: I just had to implement a new class that implements ConfigFactoryOverrideInterface, following the d.o. documentation on Configuration override system \> Providing overrides from modules:

```
namespace Drupal\custom\Config;

use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Config\ConfigFactoryOverrideInterface;

class CustomConfigOverriderDisableAds implements ConfigFactoryOverrideInterface {

  /**
   * {@inheritdoc}
   */
  public function loadOverrides($names) {
    $overrides = [];
    if (in_array('custom_ads.settings', $names)) {
      // Disables ads from custom_ads module.
      $overrides['custom_ads.settings'] = ['active' => false];
    }
    return $overrides;
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheSuffix() {
    return 'CustomConfigOverriderDisableAds';
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheableMetadata($name) {
    return new CacheableMetadata();
  }

  /**
   * {@inheritdoc}
   */
  public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION) {
    return NULL;
  }
}

```

In my custom controller I just had to conditionally add the override:

```
namespace Drupal\custom\Controller;

use Drupal\custom\Config\CustomConfigOverriderDisableAds;
use Drupal\Core\Controller\ControllerBase;

class CustomPathController extends ControllerBase {

  /**
   * Display custom page.
   */
  public function content() {
    // Add the config override to disable ads for this route.
    \Drupal::configFactory()->addOverride(new CustomConfigOverriderDisableAds());
    return [
      '#type' => 'inline_template',
      '#template' => 'Custom content',
    ];
  }

}

```

Do not add the custom overrider to custom.services.yml, otherwise it will always get called!

---
Tags: 9, configuration
---


title: Access Control for Entity List Builder

text:
# Question
Title: Access Control for Entity List Builder
This maybe a very obvious and basic question, but I can't seem to find it asked anywhere else.
I have a custom entity which has its list builder defined in the annotation and not is `routing.yml`. The list builder class extends `Drupal\Core\Entity\EntityListBuilder`.

What I need to do is to implement some custom logic around who can access that page, however there is no `access()` method on that class as I would expect there to be, and there doens't seem to be a method in the defined access handler class (extends `EntityAccessControlHandler`) either.

Am I missing something very obvious?

# Answer
The entity list builder doesn't provide routes. For this you have another annotation entry:

```
*     "route_provider" = {
*       "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",

```

Which by default points at `DefaultHtmlRouteProvider`or in this case at a subclass changing some routes to admin routes.

You can do the same, extend DefaultHtmlRouteProvider and override getCollectionRoute():

```
  protected function getCollectionRoute(EntityTypeInterface $entity_type) {
    // If the entity type does not provide an admin permission, there is no way
    // to control access, so we cannot provide a route in a sensible way.
    if ($entity_type->hasLinkTemplate('collection') && $entity_type->hasListBuilderClass() && ($admin_permission = $entity_type->getAdminPermission())) {
      /** @var \Drupal\Core\StringTranslation\TranslatableMarkup $label */
      $label = $entity_type->getCollectionLabel();

      $route = new Route($entity_type->getLinkTemplate('collection'));
      $route
        ->addDefaults([
          '_entity_list' => $entity_type->id(),
          '_title' => $label->getUntranslatedString(),
          '_title_arguments' => $label->getArguments(),
          '_title_context' => $label->getOption('context'),
        ])
        ->setRequirement('_permission', $admin_permission);

      return $route;
    }
  }

```

For details how to add a custom access() method to a route see https://www.drupal.org/docs/8/api/routing-system/access-checking-on-routes
> 0 votes

---
Tags: entities, 9
---


title: Testing Drush Commands

text:
# Question
Title: Testing Drush Commands
How to test custom implemented Drush Commands ? Are there any Open Source Examples for Drush Commands with Unit Tests or something like that ?

# Answer
There are a few test traits from drush package, that you can re-use.

As an example check the migration\_tools module. It contains a few PHPUnit tests for drush commands:

In addition you can have a look at tests inside the drush package.

**Update:**

As @cilefen mentioned in the comment, there is a documentation section about unit tests at drush github page.
> 3 votes

---
Tags: drush, testing
---


# Question
Title: How do I set a path alias for each forum?
I created a forum on a site using the core Forum module. When we create a new forum, Drupal creates it as a taxonomy term. When we create the new forum, if we associate a path alias, that URL alias is only associated to the taxonomy term and not to the forum. If we click on a specific forum from the index page (example.com/forum) we are sent to example.com/forum/nn.

How can I associate a path alias? I'm not being able to do it via the Pathauto module. Can someone tell me how to do it with that module or using any other solution?

# Answer
> 4 votes
It is possible to add a path alias to a forum, without installing any third-party modules.
You could install the Pathauto module, but that is more for automatically assigning the path aliases when creating/editing an entity, or for bulk-assigning path aliases to existing entities. If you install the Pathauto module to create path aliases for the forums, notice that under *Enabled entity types* on /admin/config/search/path/settings, you don't see an entry like *Forum*. Use the default values for that form field (which include *Content* and *Taxonomy term* that you cannot deselect), and you will be able to set path aliases for the forums.

>

It is a quite confusing, since in /admin/config/search/path/patterns/add you need to select *Forum* for *Pattern type*.

>

Maybe it would be less confusing if *Forum* would be an option for *Enabled entity types* too.

In this case, anyway, the path aliases that the Pathauto module says to assign to forums are really assigned to the taxonomy terms associated with the forums. The effect of this is that the /forum page would not use any path alias for the forum links.

I created a sandbox site on simplytest.me, and I just enabled the Forum module. I created two forums (*Module development* and *Theme development*), and created a forum topic (*Porting the "User activity" module to Drupal 8*). I went to /admin/config/search/path, and created the following path aliases.

* /forums/1/general-discussion pointing to /forum/1
* /forums/2/module-development pointing to /forum/2
* /forums/3/theme-development pointing to /forum/3

Doing so, the /forum page used the path aliases I set, in the links to the forums, but the forum topic pages used links like https://dsze.ply.st/taxonomy/term/2 under *Forums*.

So, or you set a path alias that is used from the /forum page (but not from the forum topic pages), or you set a path alias that is used from the forum topics page (but not from the /forum page), or you set two different sets of path aliases (a set used from the /forum page, and a set used in the forum topic pages).

# Answer
> 0 votes
I have just tested this feature on **Drupal 10** and forum URL aliases worked fine.

1. First install Pathauto if you don't yet have it: https://www.drupal.org/project/pathauto
2. Then, from **Extend** in the administration panel, install Pathauto, Chaos tools, and Token. If you used Composer to install Pathauto, the other modules were also downloaded automatically.

Once Pathauto is installed, assuming the Forum module is also authorized, create a forum post for testing (if you don’t have any yet).

Now, let's create a URL *pattern* via Pathauto for your forum posts.

1. Go to "Configuration", "**Search and Metadata**", then "**URL Aliases**".
2. Do **not** click on Add alias.
3. Instead, **switch** from *List* to **Patterns** (top tabs).
4. From Patterns, click on **Add Pathauto pattern**.
5. Once there, select **Content** from Pattern type (do **not** select forum).
6. On Path pattern, write ***forum\[node:title\]*** as the pattern.
7. On Content type, select **Forum Topic**.
8. Write label title on the next window. You can type anything to remind you what this pattern represents (I typed "URL Patter Forums").
9. **SAVE**.

The next thing to do is to convert your existing URLs.

1. From the **Search and Metadata** page (you should be there now), select the "**Bulk Generate** tab".
2. Select the type of paths for which to generate URL aliases. You can select all, since it will only do the ones that are authorized, but at least **Content** and **Forum** should be selected.
3. Keep the "**General URL alias for un-aliased paths only**" checked. However, if you already had some aliases that you would like to override, check, instead, one of the other options.
4. Press **Update**.

Lastly, you may have to **clean the cache**.

1. Go Configuration.
2. Performance.
3. Clear all caches.

I hope it helps.

---

Note: As for **general-discussions** (this is the forum name). Since it is not user generated, you can use the core alias functionality.

There are two entities that point to general-discussions: node/x and term/x. (By x I mean the node number you have in your Drupal).

Here, you click on **Configuration**/**Search and metada**

Then, from the List tab, click on **Add Alias**.

then, you could enter /node/x as /general-discussion/, then save it.

And then add another alias for term/x using the same general-discussion label or something else, then save it.

Clear the cache.

# Answer
> -1 votes
We can set forum patterns using the following trick. First create a forum pattern:

Then we can use the following code in custom module:

```
function my_custom_pathauto_alias_alter(&$alias, array &$context) {

  if (!empty($context['data']['term']) && $context['data']['term']->bundle() == 'forums') {

    $alias_bk = $alias;
    $alias = preg_replace('~^/forum/~', '/forum_term/', $alias);

    $tid = $context['data']['term']->id();

    $pids = \Drupal::entityQuery('path_alias')
        ->condition('path', '/forum/' . $tid)
        ->accessCheck(FALSE)
        ->execute();

    if ($pids) {
      $pids = array_values($pids);
      $pid_main = $pids[0];

      unset($pids[0]);

      foreach ($pids as $pid) {
        $alias_to_del = \Drupal\path_alias\Entity\PathAlias::load($pid);
        if ($alias_to_del) {
          $alias_to_del->delete();
        }
      }

      $alias_to_change = \Drupal\path_alias\Entity\PathAlias::load($pid_main);
      if ($alias_to_change) {
        $alias_to_change->set('alias', $alias_bk)->save();
      }
    }
    else {
      $path_alias = \Drupal\path_alias\Entity\PathAlias::create([
            'path'  => '/forum/' . $tid,
            'alias' => $alias_bk,
      ]);

      $path_alias->save();
    }
  }
}

```

So the generated pattern will be used for forums, but forum terms aliases will be changed to something else we want.

---
Tags: path-aliases, nodes
---


# Question
Title: How to remove exactly normalize.css that comes from core (not anything else)?
I tired

```
libraries-override:
  core/normalize:
    css:
      base:
        assets/vendor/normalize-css/normalize.css: false
        misc/normalize-fixes.css: false

```

or

```
libraries-override:
  system/base:
    css:
      component:
        assets/vendor/normalize-css/normalize.css: false
        misc/normalize-fixes.css: false

```

These lines don't work

This is not a duplicate question because I am asking about a particular library, I did try the way mentioned in that answer and it did not work.

# Answer
> 2 votes
Add to your\_theme\_name.info.yml

```
stylesheets-remove:
  - '@stable/css/core/assets/vendor/normalize-css/normalize.css'
  - '@stable/css/core/normalize-fixes.css'

```

or

```
libraries-override:
  core/normalize: false

```

---
Tags: 9
---