# Question
Title: Wrong user page loaded after user_login_finalize()/user_logout()
I have a third party login custom module that calls user\_login\_finalize() after authentication, and user\_logout() upon logout. Both of these functionalities work except if the user logs in/out from the /user path in Drupal, the page loads the version of the /user page that should have rendered prior to login/logout. So when logging in, the page shows the unauthorized warning that was there at first, until the page is reloaded. When logging out, the page shows the user profile information that was there when the user was logged in.

This code runs in an event subscriber for KernelEvents::REQUEST (my organization's authentication works in a way that the status of whether a user is authenticated can change outside my Drupal site at any time and needs to be checked for before content is loaded).

I'm not sure if the problem has to do with the third party login redirecting, or Drupal's cache, but is there something else that needs to be cleared or reset after using these functions? I used them intentionally to avoid writing duplicate code from what's already in Drupal.

# Answer
> 1 votes
> This code runs in an event subscriber for KernelEvents::REQUEST (my organization's authentication works in a way that the status of whether a user is authenticated can change outside my Drupal site at any time and needs to be checked for before content is loaded).

If the authentication status has changed then set a redirect response to built the new page after you have created a new session or destroyed the existing session via the user module functions you have mentioned:

```
$response = new RedirectResponse(Url::fromRoute('<current>')->toString());
$event->setResponse($response);

```

---
Tags: caching, 9, authentication-authorization
---


title: Migration: Core fields - one missing

text:
# Question
Title: Migration: Core fields - one missing
I'm writing my first D7 to D9 migration by taking the migrate-upgrade configure files and bring them over one-by-one, and tweaking as needed to pull only over a small subset of my data. Things are going fairly well, and I have a few content types, fields, and content coming over as expected.

I tweaked the source plugin "d7\_field" so I only pull a few fields from the old site, all of them field types offered with core. I have one D7 "text\_long" field that just isn't coming over with the rest, and I can't figure out why. Migrate is adding it to migrate\_map\_flagship\_migrate\_field as follows:

```
source_ids_hash: 70ef5e18a834e45c197557fff5812a7b7a0ddeec0cd8198c6ea521f2f0e38083
sourceid1: field_short_description
sourceid2: node
destid1: NULL
destid2: NULL
source_row_status: 2
rollback_action: 0
last_imported: 0
hash:

```

Which I think is wrong, but I don't know why. All the other text fields have a destid1, destid2, and source\_row\_status like this:

```
source_ids_hash: 25b9a8f1f502fe0dc79ab1d42ff7397efaef85aed6a45d893235a0b2994ff298
sourceid1: field_includes
sourceid2: node
destid1: node
destid2: field_includes
source_row_status: 0
rollback_action: 0
last_imported: 0
hash:

```

Anyone have any ideas on where i can start digging into why this field is stubbornly not migrating properly?

# Answer
> 0 votes
FOUND! It's a known issue.

In Drupal 7, the text processing settings are defined on Field instance settings. In other words, the same field can be used on two (or more) content types and the text processing settings can be Plain text on one content type and Filtered text on another.

Drupal 8 or higher has separate field storage types Text (plain) and Text (formatted). There's also Text (plain, long) and Text (formatted, long). The important part here is that this selection is done on field storage level. In other words, the plain/formatted selection can't be changed per content type.

https://www.drupal.org/docs/upgrading-drupal/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-9-or-higher#plain-text

---
Tags: migrations
---


# Question
Title: Migrate PHP version - The "" plugin does not exist
I'm using Drupal 9.3.11 on PHP 7.3. Site is running perfectly. I need upgrade to PHP 8, but I am getting this error.

> Drupal\Component\Plugin\Exception\PluginNotFoundException: The "" plugin does not exist. Valid plugin IDs for Drupal\Core\ImageToolkit\ImageToolkitManager are: gd in Drupal\Core\Plugin\DefaultPluginManager-\>doGetDefinition() (line 53 of core\lib\Drupal\Component\Plugin\Discovery\DiscoveryTrait.php).
>
> Drupal\Core\Plugin\DefaultPluginManager-\>getDefinition(NULL) (Line: 102)
> Drupal\Core\Image\ImageFactory-\>getSupportedExtensions() (Line: 386)
> Drupal\image\Entity\ImageStyle-\>supportsUri('public://slider-front/slider\_novo\_site.jpg') (Line: 274)
> template\_preprocess\_image\_style(Array, 'image\_style', Array) (Line: 287)
> Drupal\Core\Theme\ThemeManager-\>render('image\_style', Array) (Line: 422)
> Drupal\Core\Render\Renderer-\>doRender(Array, ) (Line: 201)
> Drupal\Core\Render\Renderer-\>render(Array) (Line: 479)
> Drupal\Core\Template\TwigExtension-\>escapeFilter(Object, Array, 'html', NULL, 1) (Line: 50)
> \__TwigTemplate\_ff68c0131a8924feadb3a658b99a0e39b60fe7e6871ff9c20fd45f0a1c6eddd2-\>doDisplay(Array, Array) (Line: 405)
> Twig\Template-\>displayWithErrorHandling(Array, Array) (Line: 378)
> Twig\Template-\>display(Array) (Line: 390)
> Twig\Template-\>render(Array) (Line: 55)
> twig\_render\_template('themes/bootstrap\_barrio/templates/field/image-formatter.html.twig', Array) (Line: 384)
> Drupal\Core\Theme\ThemeManager-\>render('image\_formatter', Array) (Line: 422)
> Drupal\Core\Render\Renderer-\>doRender(Array, ) (Line: 201)
> Drupal\Core\Render\Renderer-\>render(Array) (Line: 934)
> Drupal\views\Plugin\views\field\EntityField-\>render\_item(0, Array) (Line: 1168)
> Drupal\views\Plugin\views\field\FieldPluginBase-\>advancedRender(Object) (Line: 238)
> template\_preprocess\_views\_view\_field(Array, 'views\_view\_field', Array) (Line: 287)
> Drupal\Core\Theme\ThemeManager-\>render('views\_view\_field', Array) (Line: 422)
> Drupal\Core\Render\Renderer-\>doRender(Array, ) (Line: 201)
> Drupal\Core\Render\Renderer-\>render(Array) (Line: 1745)
> Drupal\views\Plugin\views\field\FieldPluginBase-\>theme(Object) (Line: 779)
> Drupal\views\Plugin\views\style\StylePluginBase-\>elementPreRenderRow(Array) call\_user\_func\_array(Array, Array) (Line: 101)
> Drupal\Core\Render\Renderer-\>doTrustedCallback(Array, Array, 'Render #pre\_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 772)
> Drupal\Core\Render\Renderer-\>doCallback('#pre\_render', Array, Array) (Line: 363)
> Drupal\Core\Render\Renderer-\>doRender(Array, ) (Line: 201)
> Drupal\Core\Render\Renderer-\>render(Array) (Line: 718)
> Drupal\views\Plugin\views\style\StylePluginBase-\>renderFields(Array) (Line: 584)
> Drupal\views\Plugin\views\style\StylePluginBase-\>renderGrouping(Array, Array) (Line: 38)
> Drupal\slick\_views\Plugin\views\style\SlickViews-\>render(Array) (Line: 2170)
> Drupal\views\Plugin\views\display\DisplayPluginBase-\>render() (Line: 1533)
> Drupal\views\ViewExecutable-\>render() (Line: 131)
> Drupal\views\Plugin\views\display\Block-\>execute() (Line: 1630)
> Drupal\views\ViewExecutable-\>executeDisplay('block\_1', Array) (Line: 81)
> Drupal\views\Element\View::preRenderViewElement(Array) (Line: 59)
> Drupal\views\Plugin\Block\ViewsBlock-\>build() (Line: 171)
> Drupal\block\BlockViewBuilder::preRender(Array)
> call\_user\_func\_array(Array, Array) (Line: 101)
> Drupal\Core\Render\Renderer-\>doTrustedCallback(Array, Array, 'Render #pre\_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 772)
> Drupal\Core\Render\Renderer-\>doCallback('#pre\_render', Array, Array) (Line: 363)
> Drupal\Core\Render\Renderer-\>doRender(Array) (Line: 435)
> Drupal\Core\Render\Renderer-\>doRender(Array, ) (Line: 201)
> Drupal\Core\Render\Renderer-\>render(Array) (Line: 479)
> Drupal\Core\Template\TwigExtension-\>escapeFilter(Object, Array, 'html', NULL, 1) (Line: 65)
> \__TwigTemplate\_7a1eb4fdd27d5860cb55c9b00c20aed750382ae62ea6694627bee55885014fbc-\>doDisplay(Array, Array) (Line: 405)
> Twig\Template-\>displayWithErrorHandling(Array, Array) (Line: 378)
> Twig\Template-\>display(Array) (Line: 390)
> Twig\Template-\>render(Array) (Line: 55)
> twig\_render\_template('themes/bootstrap\_barrio/templates/layout/page.html.twig', Array) (Line: 384)
> Drupal\Core\Theme\ThemeManager-\>render('page', Array) (Line: 422)
> Drupal\Core\Render\Renderer-\>doRender(Array, ) (Line: 201)
> Drupal\Core\Render\Renderer-\>render(Array) (Line: 479)
> Drupal\Core\Template\TwigExtension-\>escapeFilter(Object, Array, 'html', NULL, 1) (Line: 84)
> \__TwigTemplate\_31a2a24787fe3ae65266581f36c28768a486bdf9651fc0c4f5454cf5c1711248-\>doDisplay(Array, Array) (Line: 405)
> Twig\Template-\>displayWithErrorHandling(Array, Array) (Line: 378)
> Twig\Template-\>display(Array) (Line: 390)
> Twig\Template-\>render(Array) (Line: 55)
> twig\_render\_template('themes/bootstrap\_barrio/templates/layout/html.html.twig', Array) (Line: 384)
> Drupal\Core\Theme\ThemeManager-\>render('html', Array) (Line: 422)
> Drupal\Core\Render\Renderer-\>doRender(Array, ) (Line: 201)
> Drupal\Core\Render\Renderer-\>render(Array) (Line: 162)
> Drupal\Core\Render\MainContent\HtmlRenderer-\>Drupal\Core\Render\MainContent{closure}() (Line: 564)
> Drupal\Core\Render\Renderer-\>executeInRenderContext(Object, Object) (Line: 163)
> Drupal\Core\Render\MainContent\HtmlRenderer-\>renderResponse(Array, Object, Object) (Line: 90)
> Drupal\Core\EventSubscriber\MainContentViewSubscriber-\>onViewRenderArray(Object, 'kernel.view', Object) call\_user\_func(Array, Object, 'kernel.view', Object) (Line: 142)
> Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher-\>dispatch(Object, 'kernel.view') (Line: 163)
> Symfony\Component\HttpKernel\HttpKernel-\>handleRaw(Object, 1) (Line: 80)
> Symfony\Component\HttpKernel\HttpKernel-\>handle(Object, 1, 1) (Line: 58)
> Drupal\Core\StackMiddleware\Session-\>handle(Object, 1, 1) (Line: 48)
> Drupal\Core\StackMiddleware\KernelPreHandle-\>handle(Object, 1, 1) (Line: 191)
> Drupal\page\_cache\StackMiddleware\PageCache-\>fetch(Object, 1, 1) (Line: 128)
> Drupal\page\_cache\StackMiddleware\PageCache-\>lookup(Object, 1, 1) (Line: 82)
> Drupal\page\_cache\StackMiddleware\PageCache-\>handle(Object, 1, 1) (Line: 48)
> Drupal\Core\StackMiddleware\ReverseProxyMiddleware-\>handle(Object, 1, 1) (Line: 51)
> Drupal\Core\StackMiddleware\NegotiationMiddleware-\>handle(Object, 1, 1) (Line: 23)
> Stack\StackedHttpKernel-\>handle(Object, 1, 1) (Line: 708)
> Drupal\Core\DrupalKernel-\>handle(Object) (Line: 19)

Although version 7.3 works perfectly, the status report contains the following:

# Answer
In php.ini (version 7), gd extension is enable with following code:

```
extension=gd2

```

But, in php.ini of PHP 8 version, command extension=gd2 not working. Correct command is:

```
extension=gd

```

I was trying to use version 7 command in version 8. I remove "2" character and problem solved.
> 2 votes

---
Tags: 9, configuration, updating, plugins
---


# Question
Title: Dealing with tens of thousands of 404's when migrating from MediaWiki to Drupal
I have a MediaWiki 1.36.1 website with nearly **2,500** content webpages (generally all of these are either `article` or `Category:`) which I consider to migrate to Drupal.

Moving each piece of content from MediaWiki to Drupal isn't feasible due to heavy usage of MediaWiki syntax inside the source code of each article and I either can't or don't want to translate it to Drupal CKEditor syntax.

I might backup and delete the MediaWiki website, run it locally on a local server environment and then manually migrate about **500** relevant articles to my online Drupal installment (on the same web domain).
The problem with that is that I would have nearly **30,000** 404 webpages because MediaWiki creates at least 10 webpages per each webpage (1+15, if not 1+ 150 if not double than that) such as:

* Talk webpage
* History webpage
* Revision webpages
* History diff webpages
* What-links-here webpage
* Recent-changes-in-webpages-linked-from-here
* Printable version webpage
* Permalink version
* Information about this webpage — webpage
* Source code webpage / Edit webpage
* Statistics webpages
* And probably more

I can of course buy a new domain but I want to stay with the same domain.
I thus probably need to automatically redirect all **30,000** 404 webpages *to the homepage*.

How to migrate all 404 webpages to to the homepage by Drupal itself and is there another, better approach to solve my problem?

# Answer
*I thus probably need to automatically redirect all 30,000 404 webpages to the homepage.*

No, you just need to configure the front page as default 404 page at `admin/config/system/site-information`.

Then use the module Block In Page Not Found to create a block explaining that the front page is shown because the visitor did request a URL no longer available.

---

*But I seek an automatic brutal way for all 404s....* There is a module for that Redirect 404 to Home Page. Including a warning on the module's page:

> **Warning**
>
> Redirecting all 404 pages to the home page is not preferable for SEO. Please use this module if you have less number of 404 pages.
> 1 votes

---
Tags: redirection
---


# Question
Title: How do I show a block with a unique QR for each node?
There is requirement where I need to Place a Block on node where each block will be having the Unique QR code.

I created an hard-coded QR code block with the following code.

```
public function build() {
  $path = '';
  $directory = "public://Images/QrCodes/";
  \Drupal::service('file_system')->prepareDirectory($directory, \Drupal\Core\File\FileSystemInterface::CREATE_DIRECTORY);
  $qrName = 'myQrcode';
  $uri = $directory . 'QR'. '.png'; // Generates a png image.

  $path =  \Drupal::service('file_system')->realpath($uri);

  \PHPQRCode\QRcode::png("www.google.com", $path, 'L', 4, 2);

  $relative_file_url =  \Drupal::service('file_url_generator')
    ->generateAbsoluteString($uri);

  $qr_image = "<img src='{$relative_file_url}'/>";

  return [
    '#markup' => $qr_image,
  ];
}

```

The only issue is that I am not able to add the block to nodes nor to make the QR code dynamic.

It means that Each node will have a unique QR Code Block.

How to create a dynamic block inside hook\_preprocess\_node ?

Please Help

# Answer
> 5 votes
This is the original description of the task (now removed from the question):

> Build the following:
>
> * A Drupal content type to hold all their products
> * A Drupal block that can be placed on any product page. The block, when placed on any product page, automatically shows the currently displayed product's App Purchase Link as a QR code, that the site visitors can scan using their mobile.

You can use the current route to get the node and add a unique block for each node:

*/src/Plugin/Block/ExampleBlock.php:*

```
<?php

namespace Drupal\mymodule\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
 * Provides an example block.
 *
 * @Block(
 *   id = "mymodule_example",
 *   admin_label = @Translation("Example"),
 *   category = @Translation("mymodule")
 * )
 */
class ExampleBlock extends BlockBase {

  public function build() {

    $build = [];

    $node = \Drupal::routeMatch()->getParameter('node');
    if ($node instanceof \Drupal\node\NodeInterface) {
      // calculate $qr_image with $node
      $build = [
        '#markup' => $qr_image,
        '#cache' => ['tags' => $node->getCacheTags()],
      ];
    }

    $build['#cache']['contexts'] = ['route'];
    return $build;
  }
}

```

---

**2. Version**

Implementing the same block with a node context, as @leymann suggested:

*/src/Plugin/Block/ExampleBlock.php:*

```
<?php

namespace Drupal\mymodule\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
 * Provides an example block.
 *
 * @Block(
 *   id = "mymodule_example",
 *   admin_label = @Translation("Example"),
 *   category = @Translation("mymodule"),
 *   context_definitions = {
 *     "node" = @ContextDefinition("entity:node")
 *   }
 * )
 */
class ExampleBlock extends BlockBase {

  public function build() {
    $node = $this->getContextValue('node');
    // calculate $qr_image with $node
    return [
      '#markup' => $qr_image,
    ];
  }

}

```

The advantage, you don't need to take care about caching, the context does this automatically. The disadvantage, you need to make the block dependent on a context when placing it in the block layout. Drupal is not yet able to map a block context automatically. You could, for example, add a visibility for the content type, which is probably a good idea anyway.

# Answer
> 2 votes
1. The simple answer is: if you don't want/can't use the https://www.drupal.org/project/twig\_tweak \- then just copy the code of the `drupal_block` Twig extension from that module to your own module.
2. If that is not the case - just simply implement `hook_preprocess_node` and put your block build code there or load the block and send it to a node template via `$variables`.
3. Use the layout builder module (in core) to place the blocks on the node pages.

# Answer
> 1 votes
The Barcodes module https://www.drupal.org/project/barcodes provides a block displaying a barcode of any type, including QR code. This task is as simple as enabling the module then configuring the block to display what you want. No coding necessary. Barcodes supports tokens so you can dynamically encode and display a product ID, a node ID, or any other information in your barcode block.

---
Tags: nodes, blocks, 9
---


# Question
Title: How do I automatically generate documentation for my site?
I am working on a complex Drupal site with a lot of custom modules, custom entities, custom classes, custom views, custom events, custom event subscribers, custom forms, custom controllers. In short, a lot of custom code.

It is a big challenge trying to keep the technical documentation for the system updated when we keep making changes to the application on an ongoing basis.

Is there some way to generate technical documentation for the site automatically? For example.

A module is used for x, y, z V view is used for such things, the view blocks are being used in such and such pages. C content type is used for l, m, n and is used in V1, V2, V3 views.

If not fully automatically, partially at least and have some mechanism to add remaining items manually?

**Edit**: Thanks for the tip on the API module @cilefen. That seems to be a good way to generate documentation about the custom code. However there are pieces that are part of configuration as well - like views, layouts, blocks etc. That would not get documented with the API module.

# Answer
> 1 votes
Use the API module to generate documentation from code. Doxygen or phpDocumentor may work for you too, depending on your needs.

---
Tags: 9
---


# Question
Title: How get webform translations programmatically?
I'm on Drupal 9. I need to load the options labels of a Webform's option programmatically.

So far, I've managed to load the labels:

```
  $element = $webform_submission->getWebform()
      ->getElement($element_key, TRUE);

  $option_text = WebformOptionsHelper::getOptionText($element_value, $element['#options']);

```

However, I also need to get those labels for both the language of the site - `en` and `it`.

The webform object hasn't a `getTranslation()` method, so I've tried:

* relying on `$webform_submission->getTranslation($langcode)`, but that doesn't work, as it exists only for the language the webform was submitted
* trying to use:

```
$test = \Drupal::service('entity.repository')
      ->getTranslationFromContext($webform, $langcode);
// get the options values

```

but that doesn't work either, the labels are always in `it` if the webform has been submitted in `it` and similarly for `en`.

How can get the options for both languages?

# Answer
You need the translation manager that Webform provides (alternatively you could approach this as standard config entity translation management).

The following code demonstrates how you can display the translated labels for a Select element added to a Webform.

```
<?php

use Drupal\webform\Entity\Webform;

// We need the translation manager.
$wftm = \Drupal::service('webform.translation_manager');
// Get the standard contact webform, with added translated options element.
$wf = Webform::load('contact');

// Get all the system languages.
$langcodes = \Drupal::languageManager()->getLanguages();
$langcodesList = array_keys($langcodes);

foreach ($langcodesList as $langcode) {
  $elements = $wftm->getElements($wf, $langcode);
  if (isset($elements['custom_options']['#options'])) {
    var_dump($elements['custom_options']['#options']);
  }
}

```

The output looks sth like this:

```
root@b91117fbf40f:/app# drush scr webform_test.php
array(3) {
  ["lala"]=>
  string(4) "Lala"
  ["koko"]=>
  string(4) "Koko"
  ["mimi"]=>
  string(4) "Mimi"
}
array(3) {
  ["lala"]=>
  string(9) "Lala (it)"
  ["koko"]=>
  string(9) "Koko (it)"
  ["mimi"]=>
  string(9) "Mimi (it)"
}

```
> 3 votes

# Answer
Just sligthly different from Stefanos Petrakis's answer (using `getTranslationElements()` instead of `getElements()`:

```
$webform_translation_manager = \Drupal::service('webform.translation_manager');
$webform_translated_elements = $webform_translation_manager->getTranslationElements($booking_form, $langcode);
$options = $webform_translated_elements['element_machinename']['#options'];

```
> 0 votes

---
Tags: entities, webforms, i18n-l10n
---


# Question
Title: What is the best practice for handling abandoned packages required by the drupal core?
When I run `composer update` on a Drupal 9 website, I get this warning:

> Package doctrine/reflection is abandoned, you should avoid using it. Use roave/better-reflection instead.

A similar question has alreday been asked, answered and accepted on StackOverflow.

To summarise the accepted answer:

* edit your `composer.json` and replace the abandoned package with the recommended replacement
* then run `composer update` again

I seriously doubt that manually altering `composer.json` is the best practice, but that is moot, because it does not apply in the case of "doctrine/reflection". When looking into my `composer.json`, there is no mention of it, so there is nothing to edit.

So I am checking *why* it is required:

```
$ composer why doctrine/reflection
doctrine/common          2.13.3  requires  doctrine/reflection (^1.0)
doctrine/persistence     1.3.8   requires  doctrine/reflection (^1.2)
drupal/core              9.1.7   requires  doctrine/reflection (^1.1)
drupal/core-recommended  9.1.7   requires  doctrine/reflection (1.2.2)

```

So this abandoned package is required by `drupal/core` (and others).

In an upvoted commnent, user Kay V writes:

> People needing more generic composer usage instructions should consider $ composer remove {{old package}} and then $ composer require {{new package}}.

This doesn't work either, it produces the following messages:

> doctrine/reflection is not required in your composer.json and has not been removed \[...\]
> Removal failed, doctrine/reflection is still present, it may be required by another package. See `composer why doctrine/reflection`.

Two questions:

1. Why is the most recent version of `drupal/core` requiring an abandoned package (instead of its recommended replacement `roave/better-reflection`)?
2. What is the best practice for handling abandoned packages required by the drupal core?

# Answer
> 0 votes
This is not *really* an answer since you asked for 'best practice', but it does work. Considering

> The code from doctrine/reflection has been copied to drupal/components.
> The code from doctrine/reflection is no longer been used in core.

(#39 in the official thread https://www.drupal.org/project/drupal/issues/3180351), I would say that the package can just be ignored with composers `replace` top-level keyword:

```
"replace": {
    "doctrine/reflection": "*"
}

```

This only works since the package is not only abandoned, but completely unnecessary for Drupal to function, so we can safely skip the download.

There is a thread on the composer GitHub with an interesting solution proposal to add a new top-level keyword `suppress` that would behave more elegantly: https://github.com/composer/composer/issues/6133#issuecomment-1040176900

---
Tags: updating, composer
---


title: Open a paragraph programmatically

text:
# Question
Title: Open a paragraph programmatically
I have a paragraph `contact` nested inside another paragraph `occurrence`.

In the widget settings the paragraph `contact` is defined to be collapsed by default (`edit_mode` = `closed`).

I want the `contact` paragraph only to be open when creating the content and only on the first `occurrence`.

How can this be achieved?

Thanks in advance.

# Answer
> 0 votes
I achieved what I wanted to to by letting the contact field open by default (edit\_mode = open) and then in an `hook_form_node_form_alter` remove the contact form with this code

```
// Collapse contact field except for the first occurence.
foreach ($form['field_occurence']['widget'] as $delta => $field) {
  if (is_int($delta) && $delta != 0 && isset($field['subform']['field_contact']['widget']['0']['subform']['#type'])) {
    unset($form['field_occurence']['widget'][$delta]['subform']['field_contact']['widget']['0']);
  }
}

```

I guess there is a cleaner way but form the moment that does the trick.

---
Tags: 9, paragraphs
---


title: Installer can't create sqlite database

text:
# Question
Title: Installer can't create sqlite database
I have a drupal page, hosted with azure webapps, on nginx. However, when i start the site, the installer wants to have a database. I am aware that it's bad, but sqlite is an intentional choice because of company reasons.

However, when i try to use sqlite it says it locked.

I have no direct access to the files, once they are deployed. All changes have to be made locally, and then commited and pushed for azure to redeploy it.

Does anybody know how to fix this?

# Answer
First, ensure PHP meeets the requirements. Then, read more carefully the instructions on the install screen, which read:

> The **absolute path** to the file where Drupal data will be stored. This **must be writable by the web server** and should exist outside of the web root.

The screenshot you provided does not show an absolute path.
> 2 votes

---
Tags: database, installation
---


# Question
Title: Persistent anonymous user session with headless D9
In short: a new php session is started upon every request made through nextjs, I somehow must keep the anonymous user session alive.

For my anonymous users I need keep track of data submitted through nextjs. I Initially developed my app with Drupal 8.9, and many months later upgraded to 9.4-dev.

Before the upgrade to 9.4-dev, I was sure the sessions worked properly across several browsers and anonymous users at the same time; I could use the app, store and re-use unique data per anonymous user etc. Sadly its hard to verify this, downgrading to 8.9 will cause additional pain..

After the upgrade, the anonymous users suddenly share the same session. This might be related to https://www.drupal.org/project/session\_based\_temp\_store/issues/3257214 and https://www.drupal.org/node/3006306 but not sure. Using session\_based\_temp\_store:1.1 results in a shared session and session\_based\_temp\_store:1.2 results in a non-persistent session.

The code below used to work:

```
 if ($this->currentUser->isAuthenticated()) {
  $user_preferences = unserialize($this->currentUser->get('field_preferences')->value);
  foreach ($values as $key => $value) {
    $user_preferences[$key] = $value;
  }
  $this->currentUser->set('field_preferences', serialize($user_preferences))->save();
}
else {
  $session = \Drupal::service('session_based_temp_store')->get('mymodule_user');
  $user_preferences = $session->get('d_user');
  foreach ($values as $key => $value) {
    $user_preferences[$key] = $value;
  }

  $session->set('d_user', $user_preferences);
}

```

Trying to fix the problem, I tried to use tempstore.private which resulted in the same problem (new session every request).

After this I tried to use the code below, which also resulted in the same problem:

```
$_SESSION['my_module']['data'] = 'My Data';
$request = $this->requestStack->getCurrentRequest();
$session = $request->getSession();

```

Even test var $\_SESSION\['my\_module'\]\['data'\] is "reset" every time. So it doesn't really matter what kind of storage approach I try to use; the problem is clearly a non persistent session.

All of my rest resources are called with POST requests and authenticated with oauth2. Everything works nicely for authenticated users. Anonymous users can also successfully make requests.

Searching Google I can't really find anything useful, which makes me think i'm missing something obvious..

The main goal is: anonymous users must keep a persistent session in a headless drupal, also when the user closes the browser and comes back a week later, the same session must still be alive..

I do not want to store any user entered data in the frontend.

The problem is kind of logical I think..: how can Drupal know who is making the anonymous request? Should I have some sort of anonymous user cookie in the frontend, connected to an anonymous user session in the backend, passed with every request?

Can someone point me into the right direction please? Any help is much appreciated.

# Answer
> 0 votes
> The main goal is: anonymous users must keep a persistent session in a headless drupal, also when the user closes the browser and comes back a week later, the same session must still be alive.

This is what cookies are for. I don't know about nextjs, but in my headless React app, I store all anonymous user preferences as a JSON object which I dump into the cookie.

Relying solely on Drupal's session handling to reliably track user preferences for anonymous users sounds like a recipe for disaster.

> I do not want to store any user entered data in the frontend.

You're going to need to store the cookie. However, cookies that exclusively store user preferences and are not used to track users will not run afoul of the GDPR, etc.

---
Tags: sessions
---


# Question
Title: How to hide / modifiy ['operations']['#links'] edit / delete under structure -> menus in D8
I am trying to hide the edit and eelete links in the operations menu under structure -\> menu for specific roles.

I was just trying to hide the operations dialog at all by this code but it returns an:
Error: Cannot unset string offsets in my\_menu\_form\_menu\_edit\_form\_alter()

```
/**
 * @Implements hook_form_FORM_ID_alter().
 */
function my_menu_form_menu_edit_form_alter(&$form, FormStateInterface $form_state) {

  dpm($form);

  foreach ($form['links']['links'] as $index => $link) {
if (strpos($index, 'menu_link') !== false){
  dpm($form['links']['links'][$index]['operations']['#links']);
    unset($form['links']['links'][$index]['operations']);

  }
}

```

I too tried to change just the title of a link but that didn't work either and resulted with the same error.

In D7 you just could do something like `$form[$key]['operations']['edit']['#access'] = FALSE;`

Help :-)

# Answer
Sorry! The code above is actually working. Just have some trouble since a couple of days with code caching in our DEV Environment where changes in code are only whipped from cache by logging in and logging out again. Already disabled all Drupal Caching, drush cr doesn't help - guess this some kind of docker, ddev, opcode mystic stuff.
> 0 votes

---
Tags: 8, hooks, navigation
---


# Question
Title: How to display the current year in the template of a block?
I'm trying to rewrite the "Powered by Drupal" block. I want to display the current year in my code but cale does not work. The website displays a blank page with the message "The website encountered an unexpected error. Please try again later."

This error appears when I add `{{ 'now' | date('Y') }}` in the code.

Here is the block template :

```
{% block content %}
  {{ attach_library('olivero/powered-by-block') }}
  <span>
    {% trans %}Copyright © {{ 'now' | date('Y') }} example.fr - Tous droits réservés{% endtrans %}
    <a href="https://www.example.fr">{% trans %}example.fr{% endtrans %}</a>
    <span class="example-logo" aria-label="{{ 'Example Logo'|t }}">
      <svg width="14" height="19" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 42.15 55.08" fill="none" aria-label="{{ 'Drupal Logo'|t }}" role="img">
        <path d="M29.75 11.73C25.87 7.86 22.18 4.16 21.08 0 20 4.16 16.28 7.86 12.4 11.73 6.59 17.54 0 24.12 0 34a21.08 21.08 0 1042.15 0c0-9.88-6.59-16.46-12.4-22.27zM10.84 35.92a14.13 14.13 0 00-1.65 2.62.54.54 0 01-.36.3h-.18c-.47 0-1-.92-1-.92-.14-.22-.27-.45-.4-.69l-.09-.19C5.94 34.25 7 30.28 7 30.28a17.42 17.42 0 012.52-5.41 31.53 31.53 0 012.28-3l1 1 4.72 4.82a.54.54 0 010 .72l-4.93 5.47zm10.48 13.81a7.29 7.29 0 01-5.4-12.14c1.54-1.83 3.42-3.63 5.46-6 2.42 2.58 4 4.35 5.55 6.29a3.08 3.08 0 01.32.48 7.15 7.15 0 011.3 4.12 7.23 7.23 0 01-7.23 7.25zM35 38.14a.84.84 0 01-.67.58h-.14a1.22 1.22 0 01-.68-.55 37.77 37.77 0 00-4.28-5.31l-1.93-2-6.41-6.65a54 54 0 01-3.84-3.94 1.3 1.3 0 00-.1-.15 3.84 3.84 0 01-.51-1v-.19a3.4 3.4 0 011-3c1.24-1.24 2.49-2.49 3.67-3.79 1.3 1.44 2.69 2.82 4.06 4.19a57.6 57.6 0 017.55 8.58A16 16 0 0135.65 34a14.55 14.55 0 01-.65 4.14z"/>
      </svg>
    </span>
  </span>
{% endblock %}

```

Log :

```
Error : Class "Drupal\Core\Utility\Error" not found dans _drupal_error_handler_real() (/home/clients/bj764fgg66/sites/www.example.fr/core/includes/errors.inc ligne 63)

```

# Answer
Without the full error it is difficult to say, however, I think it is not possible to print expressions inside of `{% trans %}`. I think that you may be getting a Twig SyntaxError exception that reads:

> The text to be translated with "trans" can only contain references to simple variables.

So, surround only the text that needs translation with `{% trans %}`.
> 2 votes

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


# Question
Title: String substitution in Views Contextual filter parameter?
In Drupal 9, I have a View called **News**.

The View is displayed at the following path:

`/news`

I can edit it at the following path:

`/admin/structure/views/view/news/edit`

It has the following Contextual filter:

`Content datasource: Content type`

The contextual filter values are provided by the URL.

**When the filter value is *NOT* in the URL:** `Provide default value`

**Type:** `Fixed`

**Fixed value:** `all`

**Exception value:** `all`

If this value is received, the filter will be ignored; i.e, "all values"

This works well for content types like `article` and `blog_post`.

When the View is displayed for the path `/news/article`, the contextual filter shows only Content type `article`.

When the View is displayed for the path `/news/blog_post`, the contextual filter shows only Content type `blog_post`.

So far, so good.

Now, the client has a custom content type called "Youtube Video" with machine name `youtube_video`.

When this View is displayed for the path `/news/youtube_video`. the contextual filter shows only Content type `youtube_video`.

But the client wants the path to be `/news/video`.

What are my options?

Some constraints:

* The client *definitely* wants the path to be `/news/video`, and not something like `/news?type=video`.
* I don't think that it's trivial to match `/news/foo` and substitute `bar` for `foo` as the input for a contextual filter.
* I know how to use positional parameters in a route, but I don't think I can easily override the route for just `/news/foo` while preserving the contextual filter as it is for the other content types.

Some flexibility:

* The Drupal 9 site is brand new, and I'm about to migrate the content from Drupal 7 via Migrate API, so it's *possible* to change the machine name of the `youtube_video` content type to `video` during the migration. Then this View would work without modification. (The problem would be figuring out everything else that references the machine name `youtube_video` and changing that to `video` also -- potentially a lot of effort.)
* It may be possible to alter the query parameters conditionally using `hook_views_pre_view()` or `hook_views_query_alter()`, but I only want to do this if a specific parameter is matched.

# Answer
> 3 votes
Would `hook_views_pre_view()` do the trick?

```
function hook_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
  if ($view->id() == 'my_view' &&
    $display_id == 'my_display' &&
    $args[0] == 'news' &&
    $args[1] == 'video') {
    $args[1] = 'youtube_video';
  }
}

```

Replace `my_view` and `my_display` with the appropriate values.

# Answer
> 1 votes
Here's my first working proof-of-concept based on the answer above:

```
/**
 * Implements hook_view_pre_view().
 */
function my_module_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
  if ($view->id() == 'news' && isset($args[0])) {
    if ($args[0] == 'video') {
      $args[0] = 'youtube_video';
    }
  }
}

```

The first arg in the path `/news/video` actually just calls the View with `$view_id = 'news'`, so the contextual filter parameters don't start until the second segment in that path, which is `$arg[0]`.

And it's important to check that `$arg[0]` is set before checking its value; otherwise, the `/news` path will throw errors when no filters are passed.

Finally, in my case there's no need to check for a specific `$display_id`, since I want the string substitution to occur for all displays of this particular View.

Other than that, the answer above got it just right.

---
Tags: views, entities, hooks, routes, 9
---


# Question
Title: How to make users stay logged in across devices?
https://api.drupal.org/api/drupal/core!modules!user!user.module/function/user\_login\_finalize/9.2.x regenerates the sessions each time the user logs in. This can become a little hassle if user for instance switch between working between different deices (e.g. mobile + laptop). Is there any way to make the user stay logged in across devices?

# Answer
No, not really. There is no *practical* way to share the same session between devices or between different browsers on the same device.

If you wish to ease transition between devices, a single sign on (SSO) integration that uses popular account sources (like for example, Google) *may* improve the user experience. There are various options for SSO.
> 2 votes

---
Tags: 9, authentication-authorization
---


title: Aegir Drupal 7 Website migration

text:
# Question
Title: Aegir Drupal 7 Website migration
I need desperately help. I clarify that I am not a developer but I have just basic knowledge of Drupal and Aegir. Few years ago a developer guy installed Aegir on VPS (Hostwind) and Drupal. Now Hostwind decided to interrupt this service and I have to migrate.

My question is: what is best option to migrate?

Should I migrate Drupal and Aegir or just Drupal (without Aegir)? Is it possible to migrate only Drupal?

As test can install Aegir locally on Mac using MAMP to test if I am doing correctly?

Thank you

# Answer
You can always run a Drupal site somewhere without Aegir. However, as an application life-cycle manager (ALM) platform as a service (PaaS), Aegir adds extra value (e.g. monitoring, backups, rollback on upgrades, etc.)

The value of Aegir increases with the number of sites hosted. The selling point for me is that you can upgrade 200 sites at once with a single button click. But if you only have one site, it may not be worth it. You have to weigh the benefits that Aegir provides (see the docs) vs. the added maintenance of maintaining Aegir itself.

That is, if you really want to run your own platform as a service (PaaS). Other options are hosted Aegir (if you really like it) or finding a Drupal hosting company which offers their own proprietary PaaS for running Drupal. (I'll leave this search as an exercise to the reader. Ask good questions like: Does your Drupal hosting company lack native Composer support?)

Obviously, you can forget about the PaaS, and just run the Drupal site yourself if you want to self host.

If you'd like to try Aegir locally, have a look at the Aegir Development VM.
> 1 votes

---
Tags: migrations, aegir
---


# Question
Title: Problem with auto-generated url alias when attempting to make a third-level menu item
Using \[node:menu-link:parents\]/\[node:title\] as the pattern for nodes in Url Aliases works fine for a menu that is only two levels, but if I attempt to assign a node to a third level under a menu, instead of getting top-level-node/2nd-level-node/third-level-node as the url alias, I get top-level-node-2nd-level-node/third-level-node as the alias. Is this the expected behavior? Is there a way to auto-generate top-level-node/2nd-level-node/third-level-node when creating a menu item at the third level?

# Answer
Try:

`/[node:menu-link:parent:url:path]/[node:menu-link:title]`
> 3 votes

---
Tags: navigation, path-aliases
---


# Question
Title: Shouldn't hook_update to add a new field to an entity use the field definition from the entity class?
I was writing an update hook to add a new field to a custom entity and was following the pattern shown here

https://www.drupal.org/node/2554097

```
/**
 * Add 'revision_translation_affected' field to 'node' entities.
 */
function node_update_8001() {
  // Install the definition that this field had in
  // \Drupal\node\Entity\Node::baseFieldDefinitions()
  // at the time that this update function was written. If/when code is
  // deployed that changes that definition, the corresponding module must
  // implement an update function that invokes
  // \Drupal::entityDefinitionUpdateManager()->updateFieldStorageDefinition()
  // with the new definition.
  $storage_definition = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Revision translation affected'))
      ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
      ->setReadOnly(TRUE)
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('revision_translation_affected', 'node', 'node', $storage_definition);
}

```

I felt I was duplicating the BaseFieldDefinition in both the custom entity class as well as in the install file. Shouldn't I be able to use the static function

```
public static function baseFieldDefinitions(EntityTypeInterface $entity_type)

```

from the entity class to load the field definition and install it?

# Answer
> 3 votes
Using the object returned by `Drupal::entityDefinitionUpdateManager()` is the right way to update an entity fields, for the same reason an `hook_update_N()` implementation won't call any `hook_schema()` implementation to update a database field.

Imagine that you later change the entity and rename that field from *revision\_translation\_affected* to *translation\_affected*. If the update hook you wrote now uses the array returned from `baseFieldDefinitions()` and stores it in `$fields`, it won't find any value for `fields['revision_translation_affected']`, since `baseFieldDefinitions()` has been already updated to return the renamed field.

Update hook implementations must work independently from being the last update hook added or not.
Furthermore, the code used from an update hook cannot be changed, once that hook has been added. If an update hook creates an entity field that is later removed (for example), a new update hook must be added to remove that entity field; the existing update hook cannot be changed not to add that entity field anymore, or the sites that already run that update hook won't see the entity field removed. (Drupal runs an update hook only once.)

---
Tags: updating, entities
---


# Question
Title: How do you programmatically delete a field?
I found this page: https://www.drupal.org/node/2012896 which lists this:

```
// Deleting field storage.
FieldStorageConfig::loadByName('entity_type', 'field_name')->delete();

// Deleting field.
FieldConfig::loadByName('entity_type', 'bundle', 'field_name')->delete();

```

but, of course, I get: Fatal error: Class 'FieldStorageConfig' not found.

Any hints as to how this gets used?

# Answer
Drupal 8 is using object-oriented programming (except for some procedural bootstrapping files and the `*.module` and `*.theme` files).

When trying to access static methods of a class without a namespace, the class is expected to reside within the same namespace of the file you use the class name with.

This is not true for classes provided by Drupal core or other modules, when you use them within your own module.

So you have to properly use namespaces. When checking the API docs for example for FieldStorageConfig and scroll a little down, you will find the correct namespace of this class. The same goes for the FieldConfig class.

So you could use both classes by altering your source code to:

```
// Deleting field storage.
\Drupal\field\Entity\FieldStorageConfig::loadByName('entity_type', 'field_name')->delete();

// Deleting field.
\Drupal\field\Entity\FieldConfig::loadByName('entity_type', 'bundle', 'field_name')->delete();

```

However, it is best-practice to not prefix the class names by their full namespace, but use `use` directives at the top of your source code (after a possibly existing `namespace` declaration, if you are within the context of an own class).

This sums up to the following correct and working example:

```
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;

// Deleting field storage.
FieldStorageConfig::loadByName('entity_type', 'field_name')->delete();

// Deleting field.
FieldConfig::loadByName('entity_type', 'bundle', 'field_name')->delete();

```

PS.: When learning Drupal 8, it is always a good idea to check how other modules/core are doing it. You can search the code base for the class in question or use the API reference, which has a search function, and you may find plenty useful examples.
> 17 votes

# Answer
Thank you @MarioSteinitz for your post. I just tried to enhance the snippet by check if the field exists before trying to delete it.

```
use Drupal\field\Entity\FieldStorageConfig;
$field = FieldStorageConfig::loadByName('entity_type', 'field_name');
if ($field) {
  // Delete this field.
  $field->delete();
}
else {
  // The field can not be loaded or maybe it does not exists.
}

```
> 3 votes

# Answer
In case you want to remove the field from all bundles, without specifying bundle name:

```
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;

function remove_field(string $entity_type, string $field_id): void {
  $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo($entity_type);
  foreach ($bundles as $bundle) {
    if ($field_instance = FieldConfig::loadByName($entity_type, $bundle, $field_id)) {
      $field_instance->delete();
    }
  }

  if ($field_storage = FieldStorageConfig::loadByName($entity_type, $field_id)) {
    $field_storage->delete();
  }
}

```
> 0 votes

---
Tags: 8, entities
---


# Question
Title: How do I programmatically create an entity type from the install yml file?
I'm currently writing a module. In an update, I need to programmatically create a new entity type.

I have already created a suitable yml for installation. Like this one, except it is not a Node Type entity, but a custom entity type entity.

For the sake of consistency, I'd like to use the yml directly in my updateN hook. Is there anyway I can simply use the config yml to create this new entity type?

# Answer
The linked file

*core/profiles/standard/config/install/node.type.article.yml*

```
langcode: en
status: true
dependencies: {  }
name: Article
type: article
description: 'Use <em>articles</em> for time-sensitive content like news, press releases or blog posts.'
help: ''
new_revision: true
preview_mode: 1
display_submitted: true

```

is a content type and you can create it in code:

```
use Symfony\Component\Yaml\Yaml;
use Drupal\node\Entity\NodeType;

  $values = Yaml::parseFile('core/profiles/standard/config/install/node.type.article.yml');
  $bundle = NodeType::create($values);
  $bundle->save();

```

For a custom entity you find the label and the machine name of the bundle config entity in the entity class (Node.php in your example):

```
* @ContentEntityType(
*   id = "node",
*   bundle_label = @Translation("Content type"),
*   bundle_entity_type = "node_type",

```

The machine name is also the first part of the yml file name, replacing `_` with `.`
> 3 votes

---
Tags: entities, 9
---


title: Main page content block doesn't move

text:
# Question
Title: Main page content block doesn't move
I'm currently building a Drupal 9 site. I've built some custom blocks, which I display on a specific 'basic page'. I want the 'Main Page Content' block to be above my custom blocks. So I moved the 'Main Page Content' block upwards. For some reason it didn't update, and my custom blocks are still on top.

Does anyone know why?

# Answer
I managed to fix the issue. I only had main page content shown on a couple of specific pages. Added the needed page to it, and it directly got placed on the right direction. Although that page wasn't in the list of pages before, I'm guessing that whenever 'Main page content' is enabled, that it automatically gets placed under all other blocks
> 0 votes

---
Tags: blocks, layout-builder
---


# Question
Title: I am getting temporary file could not be copied because the destination directory is not properly configured error
> The specified file temporary://fileDTbhYD could not be copied, because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.

I have set read and write permissions for `sites/default/files/ folders`. I am getting permission error for `profile/site/theme/themename/assets/css` folder in error log. I have set the permission for this as well. Can't get through the error. Any solution??

# Answer
> 0 votes
For those landing here from a web search, I ran into this exact problem when setting up a test server (in my case for `backdrop cms`, a fork of Drupal).

What it required on my end was to edit `/etc/php-fpm.d/www.conf` to change the entries for:

```
 user = your-webserver-user
 group = your-webserver-group

```

add then add the user to the list

```
listen.acl_users = apache,nginx,your-webserver-user

```

then running

```
systemctl restart php-fpm

```

You can get your webserver user by checking `/etc/httpd/conf/httpd.conf`

```
User your-webserver-user
Group your-webserver-group

```

Hope that is useful to someone else out there. No amount of chmod/chown fixed it for me, this is what did.

---
Tags: caching, files
---


# Question
Title: I can't debug a functional test for a custom module
I am trying to debug the functional tests for my custom module.
When I run the debugger, it doesn't hit the breakpoint I've set on the first line of the test method. However, when I debug a functional test from the Node module, it works.

# Answer
Open PHPStorm and go to file \> Invalidate Caches...
> 0 votes

---
Tags: testing
---


# Question
Title: How do I override the admin theme in my own theme?
I created my own Drupal 8 theme:

mytheme.info.yml:

```
name: My Theme
description: 'Drupal 8 Theme'
type: theme
base theme: bartik
core: '8.x'

```

mytheme.libraries.yml

```
global-styling:
  version: 1.x
  css:
    theme:
      css/layout.css: {}
      css/style.css: {}
      css/colors.css: {}
      css/print.css: { media: print }

```

I am using "Seven" as admin theme.

When I edit a page (/node/x/edit) Seven theme is used.

Now I have to add some CSS the the edit form. How can I do this? style.css is only loaded on front end pages. Edit pages use seven theme and my theme CSS is ignored.

How can I add some CSS to admin pages or edit forms in Drupal 8?

# Answer
You can add admin CSS from a module hook. Replace XXX with the module name.

1 Put your CSS in css/extra.admin.css

2 Declare a library by creating XXX.libraries.yml

```
extra.admin:
  css:
    theme:
      css/extra.admin.css: {}

```

3 Create a hook to load the library.

```
/**
 * Implements hook_page_attachments().
 */
function XXX_page_attachments(array &$attachments) {
  $theme = \Drupal::theme()->getActiveTheme()->getName();
  if ($theme == 'seven') {
    $attachments['#attached']['library'][] = 'XXX/extra.admin';
  }
}

```
> 24 votes

# Answer
You cannot control one theme from within another theme. And even if some smart developer could find a hackish way to do it: please don't. Trust me, you don't want it. The concept of separation of concerns is important in programming. Basically it means that the different moving parts (ie. your theme) of your system should take care of their own task, without interfering with the tasks of other parts (ie your admin theme).

To achieve your goal, the cleanest way is to create a new theme, make it a subtheme of Seven (so it inherits everything you like about Seven) and add your custom CSS into the mix. Now you can select that theme as your admin theme instead of Seven.
> 18 votes

# Answer
If you create a subtheme for Seven, and use that as your admin theme, you can add your own css overrides in the seven\_subtheme.info.yml file, without messing with the core theme, or confusing theme responsibilities. The subtheme need only have the info.yml file and the css, and will inherit everything else.

From the sounds of it though, you are mainly concerned with altering the css used by the wysiwyg editor (ckeditor), so you might instead want to look at adding `ckeditor_stylesheets` to your info.yml file. Note that, as explained in this issue, the *ckeditor* css can indeed be added from **your** theme, as the wysiwyg editor should use the non-admin theme css by default (remember to clear caches after adding this).
> 5 votes

# Answer
The module you're looking for is now called Asset Injector. With it you'll be able to add CSS through the UI as @Whatwatt mentioned.
> 5 votes

# Answer
Install CSS Injector module (currently there is only a working development version for Drupal 8).

Then go to the administration page of CSS Injector (*/admin/config/development/css-injector*). Create a new CSS rule. For example, to change a field background color:

```
.node-form .field--name-title input {
    background-color: red;
}

```

Choose to apply this rule on *Seven* theme (or any admin theme in use).

Save and enjoy!
> 3 votes

# Answer
To work with any admin theme I used AdamS answer and changed the hook to.

```
$config = \Drupal::config('system.theme');

$theme = \Drupal::theme()->getActiveTheme()->getName();

if ($theme == $config->get('admin')) {

  $attachments['#attached']['library'][] = 'XXXX/extra.admin';

}

```
> 1 votes

# Answer
Why not create a block calling the css and insert it into the header of your admin pages?

@import url("/themes/XYZ/css/admin\_overrides.css")
> 1 votes

# Answer
You can add admin CSS from a module hook. Replace XXX with the module name.

1 Put your CSS in css/extra.admin.css

2 Declare a library by creating XXX.libraries.yml

```
extra.admin:
  css:
  theme:
  css/extra.admin.css: {}

```

3 Create a hook to load the library.

/\**
* Implements hook\_page\_attachments().
\*/

```
function XXX_page_attachments(array &$attachments) {
  $config = \Drupal::config('system.theme');
  $theme = \Drupal::theme()->getActiveTheme()->getName();
    if ($theme == $config->get('admin')) {
       $attachments['#attached']['library'][] = 'XXXX/extra.admin';
    }
 }

```
> 1 votes

# Answer
i would create a separate child theme for both front and back office
> 0 votes

# Answer
There's the smartest way and the easiest way. Easiest: At /admin/appearance, uncheck the box that says "Use the administration theme when editing or creating content" then apply custom CSS the same way you do for your main theme.

Alternatively, if you want your main theme to be used everywhere, set the Admin Theme dropdown to your main theme.

There are pros and cons to this, of course, but this is the easiest way to apply custom CSS to your admin theme--make it the same theme as your front end theme.

Smartest way: subtheme Seven per answers above.

If not committed to Seven, a combination easiest and smartest option: Install Adminimal theme. In the theme settings check the box for creation of a CSS overrides file. Use that file to style to your heart's content.
> 0 votes

---
Tags: 8, theming
---


# Question
Title: Why are cookies being caches in hook_prepress_node() and how can I prevent or work around this issue?
In Drupal 9 we have a \_preprocess\_node() hook that loads a users cookies like:

```
function THEME_preprocess_node(&$variables) {

  $parameters = [];
  if (isset($_COOKIE['utm_source'])){
    $parameters[] = 'utm_source=' . $_COOKIE['utm_source'];
    $parameters['#cache']['contexts'][] = 'cookies:utm_source';
  }
  if (isset($_COOKIE['utm_medium'])){
    $parameters[] = 'utm_medium=' . $_COOKIE['utm_medium'];
    $parameters['#cache']['contexts'][] = 'cookies:utm_medium';
  }
  if (isset($_COOKIE['utm_campaign'])){
    $parameters[] = 'utm_campaign=' . $_COOKIE['utm_campaign'];
    $parameters['#cache']['contexts'][] = 'cookies:utm_campaign';
  }
  $parameters = implode('&', $parameters);

  $variables['parameters'] = '&' . $parameters;
}

```

In my Node template:

```
{{ parameters }}

```

But it will load the cached cookies, even from other visitors until the cache is cleared.

We're trying to load the cookie parameters into a node template but it appears that preprocess hooks are caching the data. Even with all caching modules turned off.

So, is there another way we should be checking and passing cookie data to a node template?

# Answer
You must take into consideration render caching. In this case you must add a cache context that references the cookie. There are other questions in this forum with examples, and the big pipe module has another:

```
$has_big_pipe_nojs_cookie = $request->cookies->has(BigPipeStrategy::NOJS_COOKIE);
$page['#cache']['contexts'][] = 'cookies:' . BigPipeStrategy::NOJS_COOKIE;

```

You haven't shown all your code, but what I think you need here is something like:

```
$variables['#cache']['contexts'][] = 'cookies:utm_source';

```
> 4 votes

---
Tags: caching
---


# Question
Title: Check for block type in THEME_preprocess_menu_local_task
I want to make changes to local task tabs of a certain custom block type (`mini_layout`).

I can do this for certain node types in my theme with `THEME_preprocess_menu_local_task()`, and there I can use the following to check the node and node type first.

```
$node = \Drupal::routeMatch()->getParameter('node');
if ($node && $node->getType() == 'content_type') {
  // my code
}

```

But how do I check for something like `$block` and `$block->getType() == 'mini_layout'`? (Which is definitely not right.)

Should I do this in the module, or is it better to stay in the theme?

# Answer
I rather use **hook\_menu\_local\_tasks\_alter** just because they made a dedicated hook for it. So might as well use it.

```
/**
 * Implements hook_menu_local_tasks_alter().
 */
function MY_MODULE_menu_local_tasks_alter(&$data, $route_name) {
  $is_a_block = !empty(\Drupal::routeMatch()->getParameters()->get('block_content'));
  if ($is_a_block) {
    $is_a_mini_layout_block = \Drupal::routeMatch()->getParameters()->get('block_content')->bundle() == 'mini_layout';
    if ($is_a_mini_layout_block) {
      // my code
    }
  }
}

```

> Should I do this in the module, or is it better to stay in the theme?

Better to use a module since these pages use the Admin theme and you should never touch the core admin theme. So unless you're using a custom admin theme, then, and only then, you can consider using theme.
> 1 votes

---
Tags: theming, 9
---


# Question
Title: Checkboxes in Webform Custom Composite Table
I've been testing Drupal 9 and Webform 6.2.0-beta2. After researching a few hours, my understanding is that the current Webform doesn't support checkboxes in custom composite fields tables. Is that correct?

For instance, a field type "checkbox" with multiple options like "red, yellow, blue, and black". Once the form processes, these options don't appear on the page.

# Answer
@see Issue #3216923: Radios or Checkboxes inside Composite not saved
> 1 votes

---
Tags: webforms
---


title: Return AccessDenied for custom page

text:
# Question
Title: Return AccessDenied for custom page
I've setup a custom page in my system which is expecting 2 parameters that will be used to generate part of the content on that page, I'm able to retrieve the information from my page, but I'm wondering what is the best method of returning an access denied when my criteria fail

I found this page which shows how you can setup a custom access controller, but this example is passing the user entity, when what I'm more interested in is the 'slugs' of the URL they've hit

routing.yml

```
my_module.user_subscribe:
  path: /my-module/subscribe/{entity_type}/{entity_id}
  defaults:
    _controller: \Drupal\my-module\Controller\SubscriptionPages::subscribe
    _title: Email Subscription Sucessful
    type: node
    entity: 1
  requirements:
    _permission: 'access content'
    _entity_check: 'TRUE'

```

Services.yml

```
services:
  my_module.entity_check:
    class: Drupal\my-module\Access\EntityCheck
    tags:
      - { name: access_check, applies_to: _entity_check }

```

Then I have my `src/Controller/SubscriptionPages` file, and one for `src/Access/EntityCheck` etc, all that part seems to be working, I can manually enforce the code in my EntityCheck to return an access denied and it does, but what I want to know is how can I pull the `{entity_type}` and `{entity_id}` from the URL they've hit so I can check they aren't trying to access something they shouldn't

eg

mywebsite.com/my-module/subscribe/node/15 - would be fine

mywebsite.com/my-module/subscribe/foo/bar - would return access denied, because I want to run the check inside my EntityCheck code

Inside the link above it has  `arguments: ['@current_user']` inside the services.yml file, is there an equivalent one for current URL, or ones where I can more specifically retrieve each of the items individually?

# Answer
> 3 votes
In your route, instead of `_permission`, you can use a custom access callback:

`_custom_access: Drupal\[MODULE]\Controller::accessCallback()`

Then you can return an AccessResult from the access callback:

```
public function accessCallback($entity_type, $entity_id) {
  if (!in_array($entity_type, $allowed_types)) {
    return \Drupal\Core\Access\AccessResult::forbidden();
  }

  ...

  return \Drupal\Core\Access\AAccessResult::neutral();
}

```

Or, you can use a `_permission` on the route, and instead throw a `Symfony\Component\HttpKernel\Exception\NotFoundHttpException` exception from the controller if the values are incorrect:

```
public function someRouteCallback($entity_type, $entity_id) {
  if (!$entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id)) {
    throw new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException();
  }
}

```

---
Tags: 8, services, page-controller
---


title: Get current language in template

text:
# Question
Title: Get current language in template
In Drupal 7 the current language is a global variable we can access with

```
global $language;
$langcode = $language->language;

```

I want to know how can we access the current language in a Twig file in Drupal 8 (in `page--front.html.twig` for example)?

# Answer
> 29 votes
I found my answer and post it here so maybe it helps others later.

First, in `MYTHEME.theme`:

**In Drupal 8.2 language got added to page the variables in template\_preprocess\_page. But in my current version 8.1 it didn't exist so I added it with:**

```
function MYTHEME_preprocess_page(&$vars) {

  $language = \Drupal::languageManager()->getCurrentLanguage()->getId();
  $vars['language'] = $language;
}

```

Then in my Twig file I use `{{ language }}`. Also I can get the language name with `{{ language.getName() }}`.

**Update**

After Drupal 8.2 a global variable `language` exists and now there's no more need to add it first.

```
{% if language.getId() == 'en' %}
  Do something
{% else %}
  Do something else
{% endif %}

```

*Update* Thanks @Lucas for his comment

on Drupal \> *8.7.5*

```
{% if language.getId() == 'en' %} should be {% if language == 'en' %}

```

# Answer
> 13 votes
On Drupal version 8.2.3 the `language` variable is already available in Twig templates. A usage example is this:

```
{% if language.getId() == 'en' %}
  Do something
{% else %}
  Do something else
{% endif %}

```

# Answer
> 9 votes
`{{ language }}` works but **only in `page` context**.

The example of this question(`page--front.html.twig`) happens to be a working one.

I tried in 8.7.6 with Xdebug. When called from somewhere other than `page.html.twig` it will returns a `null` instead of `{Drupal\Core\Language\Language}`

I think that's why some people report it working but others not. You might use it under `node.html.twig` or something. In this case you still need to provide that under preprocess() function of your theme.

# Answer
> 6 votes
In page.html.twig and Drupal 8.7.6, I had to use:

`{% if language.id == 'en' %}` or `{{ language.id == 'en' ? 'active' : 'not-active' }}`

Other suggestions did not work.

# Answer
> 0 votes
I was trying to display the language to the user in the user native language, so I was trying to display "Français" instead of "French" and this was the answer if it might help someone:

Inside a preprocess function:

```
    // Get the current content language in native form.
    $language_id = \Drupal::languageManager->getCurrentLanguage('language_content')->getId();
    $native_language = \Drupal::languageManager()->getNativeLanguages()[$language_id];
    $variables['current_language_name'] = $native_language->getName();

```

Inside a twig template:

```
{{ current_language_name }}

```

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


# Question
Title: Retrieve translated taxonomy term in current language programatically
How do I retrieve a specified taxonomy term translated (if translation exists for this term) from the current language context programmatically with D8?

# Answer
> 26 votes
Use the following code:

```
$curr_langcode = \Drupal::languageManager()->getCurrentLanguage(\Drupal\Core\Language\LanguageInterface::TYPE_CONTENT)->getId();

// retrieve term
$taxonomy_term = \Drupal\taxonomy\Entity\Term::load($tid);

// retrieve the translated taxonomy term in specified language ($curr_langcode) with fallback to default language if translation not exists
$taxonomy_term_trans = \Drupal::service('entity.repository')->getTranslationFromContext($taxonomy_term, $curr_langcode);

// get the value of the field "myfield"
$myfield_translated = $taxonomy_term_trans->myfield->value;

```

# Answer
> 10 votes
You should (must) use service instead at the first line for language\_manager. Also I would shorten the code by using use tags.

Somewhere in the beginning of file:

```
use Drupal\taxonomy\Entity\Term;
use Drupal\Core\Language\LanguageInterface;

```

and later in the code in some function

```
$curr_langcode = \Drupal::service('language_manager')->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)->getId();
// Retrieve term.
$taxonomy_term = Term::load($tid);
// Retrieve the translated taxonomy term in specified language
// ($curr_langcode) with fallback to default language if translation not
// exists.
$taxonomy_term_trans = \Drupal::service('entity.repository')->getTranslationFromContext($taxonomy_term, $curr_langcode);
// Get the value of the field "myfield".
$myfield_translated = $taxonomy_term_trans->myfield->value;

```

# Answer
> 5 votes
The snippets above will return untranslated terms also. You must check if a term is translated with the hasTranslation function:

```
$vocabulary = 'MY_VOCABULARY_NAME';
$language =  \Drupal::languageManager()->getCurrentLanguage()->getId();
$query = \Drupal::entityQuery('taxonomy_term');
$query->condition('vid', $vocabulary);
$query->sort('weight');
$tids = $query->execute();
$terms = \Drupal\taxonomy\Entity\Term::loadMultiple($tids);
$termList = array();

foreach($terms as $term) {
    if($term->hasTranslation($language)){
        $translated_term = \Drupal::service('entity.repository')->getTranslationFromContext($term, $language);
        $tid = $term->id();
        $termList[$tid] = $translated_term->getName();
    }
}

// To print a list of translated terms.
foreach($termList as $tid => $name) {
 print $name;
}

```

To link the tags to their term page: See: Get taxonomy terms

# Answer
> 2 votes
An approach in preprocess node (handles multiple term references):

```
function HOOK_preprocess_node(&$variables) {

  $node = $variables['node'];
  $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
  $pathAliasManager = \Drupal::service('path_alias.manager');

  if ($node->hasField("field_name") && !$node->get("field_name")->isEmpty()) {

    $terms = $node->get("field_name")->referencedEntities();

    foreach ($terms as $term) {

      $name = $term->name->value;
      if ($term->hasTranslation($langcode)) {
        $name = $term->getTranslation($langcode)->name->value;
      }

      $variables['termValues'][] = [
        'pathAlias' => $pathAliasManager->getAliasByPath('/taxonomy/term/' . $term->id()),
        'name' => $name,
      ];
    }
  }
}

```

Then in Twig:

```
{% for items in termValues %}
  <a href="{{ items.pathAlias }}">
    {{ items.name }}
  </a>
{% endfor %}

```

---
Tags: taxonomy-terms, 8, i18n-l10n
---


# Question
Title: How do I create sell product samples on the fly?
Our site sells fabric by the roll, not by the yard. Each roll is a unique one-off. Due to inconsistencies with color, we offer samples. It's unfeasible create sample Products for each roll Product we post. What I envision is adding a "Get A Sample" link or button to each product's page that would, when clicked, capture the product's ID, then add a sample with that ID to the Cart.

I've been playing around with Field Tokens, Commerce Add To Cart Link, and Direct Checkout by URL but have yet to get anything to work.

# Answer
I don't know of any module configuration that would do what you need without creating product variations for the samples. Now, just creating a variation and letting the custom select that on the Add to Cart form would be one way to make this work. I'm not sure what constraints you have that make this untenable, but you wouldn't even need to use product attributes if you didn't want to - just title the variations "\[Unique Fabric\] Roll" and "\[Unique Fabric\] Sample" and the Add to Cart form will present a select list for the variation to be selected by title.

That said, to do this via a generic product, I'd create a product + variation type called "Fabric Sample" that uses a new order item type to add the product to the cart. This order item type would have a reference field on it that I'd populate from the custom purchase link / form. You then would need to populate that reference field value based on the product the customer is requesting a sample for. The reason Commerce Add to Cart Link won't work is that the module doesn't have any way for you to provide values for custom fields on the order items it creates. That would be a fine feature request for the module, though. Otherwise, you're just going to need a custom form.
> 0 votes

---
Tags: commerce
---


# Question
Title: How can I get the machine name of a taxonomy term knowing its tid?
Is there any table in the database that shows the relationship between vocabulary and taxonomy, or is there any way to find out the vocabulary name of a particular taxonomy from its tid?

# Answer
> 3 votes
The table `taxonomy_term_data` lists the terms, and `taxonomy_vocabulary` lists the vocabularies.

In the table `taxonomy_term_data`, the term string is found in the `name` field. The field `vid` identifies the vocabulary assocaiated with the term. And the field `tid` is the numeric taxonomy id.

So you can look up the relationship between the term `name`, `tid` and `vid` directly from the this table.

Then, to determine the vocabulary name string associated with the term, you need to left join the `taxonomy_vocabulary.name` field, where `taxonomy_vocabulary.vid` = `taxonomy_term_data.vid`.

# Answer
> 3 votes
Using the API would be preferable to going into the database directly as you can take advantage of caching properly, and keep a more structured code base at the same time:

```
$term = taxonomy_term_load($tid);
$vocab = taxonomy_vocabulary_load($term->vid);
$machine_name = $vocab->machine_name;

```

# Answer
> 3 votes
If you have the taxonomy term ID, it is enough you call taxonomy\_term\_load().

```
$term = taxonomy_term_load($tid);
$vocabulary_name = $term->vocabulary_machine_name;

```

Using the Devel module, you can notice the object returned from `taxonomy_term_load()` contains the following fields.

With Drupal 8, each entity has its own PHP class, contrary to previous Drupal versions where each entity instance is a `stdClass` object.

In Drupal 7, if you don't have a taxonomy term ID, and you want to load all the taxonomy terms, you should use the EntityFieldQuery class; see How to use EntityFieldQuery. In Drupal 8, entity\_load\_multiple\_by\_properties() is the function you should use.

# Answer
> 0 votes
With D8 something like this.

```
$parameters = \Drupal::routeMatch()->getParameters()->all();
if (isset($parameters['taxonomy_term'])) {
  $term = $parameters['taxonomy_term'];
  $vid = $term->bundle();
  $vocabulary = \Drupal::entityTypeManager()->getStorage('taxonomy_vocabulary')->load($vid);
  $vocabulary_label = $vocabulary->label();
}

```

---
Tags: taxonomy-terms, database
---


# Question
Title: Render link in twig with 'entity:node/n' as uri in array
With the module "config pages" I've set some variables global to render in templates. In mytheme.theme I've added a function:

```
function mytheme_preprocess(array &$variables, $hook)
{
    $myConfigPage = \Drupal\config_pages\Entity\ConfigPages::config('config_name');
    $variables['my_settings'] = $myConfigPage->toArray();
}

```

In the config\_pages I've created a link field. I would like to render them, but I get below output. How can I render the link in Twig?

```
  ^ array:3 [▼
      0 => array:3 [▼
        "uri" => "entity:node/186"
        "title" => "Title 3"
        "options" => []
      ]
      1 => array:3 [▼
        "uri" => "entity:node/189"
        "title" => "Title 1"
        "options" => []
      ]
      2 => array:3 [▼
        "uri" => "entity:node/195"
        "title" => "Title 2"
        "options" => []
      ]
    ]

```

Twig:

```
  {{ dd(my_settings.field_links) }}
  {% for link in my_settings.field_links %}
    <div class="field__item">
      {{ dd(link) }}
      {{ link.uri|render }}
      {{ link.title }}
    </div>
  {% endfor %}

```

None of above are working.

# Answer
> 4 votes
You can render a link with core's link function:

> This helper function accepts as first parameter the text and as second parameter the uri
>
> Examples:
>
> `{{ link(item.title, item.uri, { 'class':['foo', 'bar', 'baz']} ) }}`

In your case, this might look like:

```
{% for link_item in my_settings.field_links %}
  <div class="field__item">
    {{ link(link_item['title'], link_item['uri']) }}
    // or
    {{ link("My link text", "entity:node/123") }}
    // or
    {{ link("My link text", "internal:/some/internal/path") }}
    // or
    {{ link("My link text", "route:my.module.route_name") }}
    // or
    {{ link("My link text", "https://drupal.stackexchange.com/") }}
  </div>
{% endfor %}

```

Alternatively, and preferably imo, you can just render the field from the config\_page entity (as with any content entity).

For example, in your preprocess:

```
// Load your config page.
$my_config_page = \Drupal::entityTypeManager()
  ->getStorage('config_pages')
  ->load('my_config_page_identifier');
// Build the render array for my links per the config page's `default` view mode.
$vars['my_links'] = $my_config_page->field_links->view('default');

```

Then, in twig:

```
{{ my_links }}

```

# Answer
> 0 votes
```
{% for link in my_settings.field_links %}
    <div class="field__item">
      {{ link.uri|render }} => {{ link.url|render }} or {{ link.0.url|render }}
      {{ link.title }}
    </div>
  {% endfor %}

```

use **url** instead **uri** as mentioned above

---
Tags: theming, 9
---


# Question
Title: How to display a Paragraph field with a condition
Hello here is my problem, I have a paragrah type with an illimited value image field in which I store image(s) to display them in 200\*200 but also a single Json file with mapping data linked to the image(s) in the paragraph.

But in the drupal conf I can not hide the json file name since it's stored in the same field, they would both be invisible (json and image).

However I'd like to display in the Frontpage view and so (/node/xxx) only the image(s) and not the json file name even though they are in the same paragraph field, is that possible directly in drupal configuration or do I have to make a template ?

# Answer
> 0 votes
Depending on how complex your logic is, you can either write it inside the paragraph preprocess function, as in:

```
function THEME-NAME_preprocess_paragraph_PARAGRAPH-TYPE($variables, $paragraph) {
  if(some_condition) {
    $variables['field_name'] = $paragraph->get('field_name')->value;
  }
  // ...
  return $variables;
}

```

or write the same logic inside twig template if its simpler, as in:

```
{# paragraph--PARAGRAPH-TYPE.html.twig #}

{% if condition %}
  {{ content.custom_var }}
{% endif %}

```

I can elaborate and edit this answer if you are more specific.

# Answer
> 0 votes
This works:

```
function THEME_NAME_preprocess_paragraph(&$variables) {
  $paragraph = $variables['elements']['#paragraph'];
  $variables['image_position'] = $paragraph->get('field_image_position')->value;
}

```

---
Tags: theming, 8, paragraphs
---


# Question
Title: Roles and Permission creation programatically inside module
I am trying to create drupal 8 roles and permissions programatically. My current approach is to have a module that when install it will generate those set of roles and permissions defined by the module. It would be more like a background Module, where no form is needed or anything. My problem lies that I really don't know where to start the the roles creations since no form is needed, I mean should I create them inside a hook?, if so which hook?, any other place?

I really don't know if this is the best approach, still a newby on drupal 8. Any suggestions will be greatly appreciate it.

Thanks in advance

# Answer
Create the roles on your development site and grab the configuration for them and place them in:

```
<modulename>/config/install

```

When the module is installed it will import that configuration. hook\_install is deprecated for installing configuration with a module.

Remove any uuid information from the export as it won't be applicable in most sites.

If you are unaware how to export/import configuration in drupal 8, you should read: D8 Configuration Management

edit: Just as an aside fact, you can in theory write your own config.yml files however until you are very familiar it's easier to just create the role, and export it.
> 2 votes

# Answer
If it's during install, I would say you put it in the install hook. When the module gets uninstalled, you can remove the roles again with hook\_uninstall().
> 2 votes

# Answer
I prefer the programatically way instead of config way:

put into the **YOUR\_MODULE.install**

```
/**
* Implements hook_install().
*/
function YOUR_MODULE_install() {
  $role = \Drupal\user\Entity\Role::create([
  'id' => 'your_role_name',
  'label' => 'YOUR Role Name',
  ]);
  $role->save();
}

/**
* Implements hook_uninstall().
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
function YOUR_MODULE_uninstall() {
  $role = \Drupal\user\Entity\Role::load('your_role_name')->delete();
}

```
> 0 votes

---
Tags: 8, hooks, users, installation
---


# Question
Title: How to tell if a menu link is route:<nolink> or not?
Trying to theme a menu in Drupal 8, running into a case where we need to add classes on certain links.

In the case of a menu link that is `route:<nolink>` we need to not add any class at all.

Example:

```
{% if item.below and item.url %}
 {{ link(item.title, item.url, { 'class':['link', 'link--arrow']} ) }}
{% else %}
 // not a link
{% endif %}

```

How can we tell at this level that `item.url` is `route:<nolink>`?

Update:

Current solution so far, is there a better way?

```
{% if not item.url.isExternal() and item.url.getRouteName() is same as('<nolink>') %}
  {{ link(item.title, item.url) }}
{% else %}
  {{ link(item.title, item.url, { 'class':['link', 'link--arrow']} ) }}
{% endif %}

```

# Answer
> 1 votes
Might be able to do a toString and if it's not actually a link that will come back empty

```
{% if item.below and item.url and item.url.toString|length > 0 %}

```

# Answer
> 0 votes
Or try this:

```
{% if item.below and item.url and item.url.getRouteName() != "<nolink>" %}

```

---
Tags: 8, theming, navigation
---


# Question
Title: Composer\Downloader\TransportException: The "drupal.org/packages.json" file could not be downloaded (HTTP/1.1 404 Not Found)
In Drupal 8.9.x, After composer cache-clear. I am getting this error \[Composer\Downloader\TransportException\] The "drupal.org/packages.json" file could not be downloaded (HTTP/1.1 404 Not Found) .

I can't run the composer install or composer update.

I tried to remove the vendor folder & composer.lock files too.

Even i tried,

But no luck.

is something wrong? before the composer cache clear it was working fine. it happens only on after composer cache clear. Any help appreciated.

```
    "repositories": [
            {
                "type": "composer",
                "url": "https://packages.drupal.org/8"
            },
            .....

```

# Answer
> 0 votes
The drupal package repository is https://packages.drupal.org/8, none other. it should appear, in most cases, alone as the only added repo in composer.json:

```
    "repositories": [
        {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        }

```

But as you have done it, with a named key, it will be as follows, which should be fine:

```
    "repositories": {
        "drupal": {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        },

```

I think the problem you are experiencing is that by passing the `-g` flag to `composer`, you are setting the value globally (for all projects) but the project's own `composer.json` may have a differing, or a wrong, configuration.

# Answer
> -1 votes
I ran this composer config command, then it works.

```
"composer config -g repo.packages composer https://packages.drupal.org/8"

```

---
Tags: 8, composer
---


title: Customizing the Access Denied Page

text:
# Question
Title: Customizing the Access Denied Page
I'm trying to modify the text that shows on the standard Access Denied page. I created a module and tried to extend the core class but while module installs fine the page does not get modified. My first question is can Access denied be customized?

# Answer
Access Denied is an exception and if you want to have control over any aspect how this is handled the best place is an exception event subscriber, see How can we catch the acces denied exception in drupal 8 for the general aspects or Returning alternate HTTP codes for unpublished content in Drupal 8 for an example how to change a 403 to a 404 exception.

> I'm trying to modify the text that shows on the standard Access Denied page?

This question is specific for the text, see this answer for a 404 message, How to change page not found page error message in drupal 8?, replace it with 403 for an access denied message.

> My first question is can Access denied be customized?

The standard way is of course in the basic site settings *admin/config/system/site-information*.
> 3 votes

# Answer
You can customize the Access Denied Page at the theme level. Use the following file name suggestion `page--403.html.twig`, while `page--4xx.html.twig` my be used for any 400-level status code.

Docs: https://www.drupal.org/docs/theming-drupal/twig-in-drupal/twig-template-naming-conventions
> 0 votes

---
Tags: 8
---


title: What does #markup mean?

text:
# Question
Title: What does #markup mean?
I meet this array key all the time in Drupal (for example in Symphony's `dpm()`) yet I am not able to find any documentation about it, what it does, how can I use it? How do I display something that is given as `#markup` value in Twig?

# Answer
By using `#markup` in render arrays you can output raw HTML (passed through XSS filter to ensure security).

Here's an advanced example, with optional `#allowed_tags` and `placeholders`.

```
/**
 * Implements hook_preprocess_HOOK().
 */
function mymodule_preprocess_foobar(&$variables) {
  $variables['video'] = [
    '#markup' => '<span>@video_label:</span> <video><source src="v.webm" type="video/webm"></video>',
    '#allowed_tags' => [
      'video',
      'source',
    ],
    '#attached' => [
      'placeholders' => [
        '@video_label' => t('Sample label'),
      ],
    ],
  ];
}

```

In Twig you just do:

```
{{ video }}

```

And in your browser you get the HTML with replaced placeholder and stripped `<span>`:

```
Translated label: <video><source src="v.webm" type="video/webm"></video>

```
> 4 votes

# Answer
Just by using the regular print twig syntax: {{ variable }}

The #markup is the html that will be on the final page sent from the server.

You can use a preprocess function to intercept and change the #markup if you need to.
> 1 votes

---
Tags: theming, 9
---


# Question
Title: Add a new contextual link to custom block type to edit layout
I have a custom block type using Layout Builder.

How do I add an *Edit Layout* item in the contextual link menu?

The link should go to /block/{nid}/layout; after saving, the layout returns to where you started.

# Answer
> 1 votes
You do this by implementing \*.links.contextual.yml in a module. For example, to add a contextual link on Nodes to node layout builder, you would implement the following: `[MODULE].links.contextual.yml`

```
node_layout:
  title: 'Edit Layout'
  route_name: 'layout_builder.overrides.node.view'
  group: 'node'

```

You can find out the route\_name for various entities by enabling the Devel module, and going to `/devel/routes`.

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


# Question
Title: Best practice for getting field values of entity chains
I really would like to make this if/else field value check just a little bit more sexy.

What's Best Practice for dealing with nested functions chains to get entity field values (check if they exist / check if they are not empty)

```
 if($entity->hasField('field_intro_teaser_image_media_')){
      $media_field = $entity->field_intro_teaser_image_media_;

      if($media_field->entity){
        $media_field_entity = $media_field->entity;

        if($media_field_entity->hasField('field_media_image')){
          $media_field_entity_image = $media_field_entity->field_media_image;

          if($media_field_entity_image){
            $media_field_entity_image_entity = $media_field_entity_image->entity;

            if($media_field_entity_image_entity){
              $media_field_entity_image_entity_uri = $media_field_entity_image->entity->getFileUri();

              if($media_field_entity_image_entity_uri){

                // ... yay we got the damn uri!

              }

            }
          }
        }
      }
    }

```

The one liner would be:

```
$media_field = $entity->field_intro_teaser_image_media_->entity->field_media_image->entity->getFileUri();

```

# Answer
> 2 votes
When you access fields by magic methods, you don't actually have to check for their existence by using `hasField()` method.:

```
$entity->field_that_does_not_exist->entity; // NULL.
$entity->get('field_that_does_not_exist'); // Exception.
$entity->get('field_that_does_not_exist')->entity; // Exception.

```

Using `$entity->field_intro_teaser_image_media_->entity` is sufficient in this case, if the field does not exist, the expression will be simply `NULL`, without any errors.

But of course you still have to check if referenced `->entity` is not `NULL`. PHP 8.0 Null-safe operator may be a way to do it, as suggested by Clive.

```
$media_field = $entity
  ->field_intro_teaser_image_media_
  ->entity
  ?->field_media_image
  ->entity
  ?->getFileUri();

```

In case of using Null-safe operator, it will be probably faster to access entity fields by `->get()`, to avoid additional logic.

```
$media_field = $entity
  ->get('field_intro_teaser_image_media_')
  ?->entity
  ?->get('field_media_image')
  ?->entity
  ?->getFileUri();

```

# Answer
> 1 votes
Assuming you've built the chain correctly, you can do it as follows:

```
$media_field = NULL;
try {
  $media_field = $entity->field_intro_teaser_image_media_->entity->field_media_image->entity->getFileUri();
}
catch (\Exception $e) {
  watchdog_exception('Media retrieval');
}

if (!is_null($media_field)) {
  // Do stuff.
}

```

---
Tags: entities
---


title: How do I set a field value?

text:
# Question
Title: How do I set a field value?
I am using the following code, but it doesn't set the field value as I would expect.

```
use Drupal\Core\Entity\EntityInterface;

/**
 * Implements hook_ENTITY_TYPE_update().
 */
function mymodule_node_update(EntityInterface $entity) {
  if ($entity->getType() == "article") {
    $entity->set('field_set_color', ["red","green"]);
  }
}

```

Why doesn't this code set the field value?

# Answer
> 3 votes
You can use `hook_ENTITY_TYPE_presave()` `hook_ENTITY_TYPE_update()` gives the following warning.

> When saving existing entities, the entity is assumed to be complete, partial updates of entities are not supported.

```
use Drupal\node\NodeInterface;

function mymodule_node_presave(NodeInterface $node) {
  if ($node->getType() == "article") {
    $node->set('field_set_color', ["red","green"]);
  }
}

```

# Answer
> 0 votes
`hook_ENTITY_TYPE_update()` isn't the hook to change entity data. It's invoked after the entity has been updated and saved in the database. The documentation itself makes that clear. (Emphasis is mine.)

> This hook runs **once the entity storage has been updated**. Note that hook implementations **may not alter the stored entity data**.

The only hook that is invoked right before the entity is saved in the database is `hook_ENTITY_TYPE_presave()`. Contrary to `hook_ENTITY_TYPE_update()`, this hook is invoked either when an entity is created or when an entity is updated. If you only want to change a field value when an entity is updated, your code should be similar to the following one.

```
use Drupal\node\NodeInterface;

function mymodule_node_presave(NodeInterface $node) {
  if (!$node->isNew() && $node->getType() == "article") {
    $node->set('field_set_color', ["red","green"]);
  }
}

```

The code is using `NodeInterface` as type-hinting because that is the interface that defines `getType()`. Alternatively, you can use the following code, which works since `EntityInterface` defines `bundle()`.

```
use Drupal\Core\Entity\EntityInterface;

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function mymodule_node_presave(EntityInterface $entity) {
  if (!$entity->isNew() && $entity->bundle() == "article") {
    $entity->set('field_set_color', ["red","green"]);
  }
}

```

Since the code you need is for the Node entity, I would use the first snippet. I would use the second snippet when the code needs to run for any content entity, not just nodes.

---
Tags: 8, entities
---


# Question
Title: 'Aggregate and compress CSS files' and 'Aggregate JavaScript files' don't work
Recently selecting *Aggregate and compress CSS files* or *Aggregate JavaScript files* in the Performance page stopped working on a Drupal 7 site: When they are selected, the CSS/JavaScript file won't load.

I have cloned the site on another server and the problem doesn't occur there. The PHP version and the Drupal version (7.89) is the same.

How can I debug what is going on here?

**Edit: Additional info**

As I mentioned in the comments, the aggregated CSS files are not viewable in the browser. However, If I change the filename to e.g. test.css, it then *is* viewable.

**Further:**

Each aggregate file has a corresponding .gz of the same name. When I delete this the .css file is then viewable via the browser. So it looks like the issue has something to with these .gz files.

# Answer
Well it turns out that mod\_headers wasn't enabled on my server, which therefore meant that the *'# Rules to correctly serve gzip compressed CSS and JS files'* section within .htaccess didn't work.

It used to be fine, so it looks like the hosting company changed the Apache config recently
> 2 votes

---
Tags: 7, css-js-aggregation
---


# Question
Title: How can I inject services into my entity bundle class?
I have an entity with a JSON field, and I do some complicated processing when the entity is saved.

Right now, I do this processing in `hook_ENTITY_presave()`, which calls a service I have created in a custom module.

However, since Drupal 9.3, we can create bundle classes to extend entities cleanly.

So I made one for my entity, and I wrote some new getters and setters so I can do `$entity->getMyValue()` instead of `$entity->field_abc->value`.

Now, I want to take the next step and inject my service into the entity and move the processing directly into the entity on save. How can I do that?

# Answer
> 2 votes
Alas, this is not yet possible. There is a discussion in the Core issue queue on how to proceed with this.

As noted in the discussion linked above, an alternative to do this now is to use the Typed Entity module, which wraps entities into objects and allows you to do dependency injection.

---
Tags: entities
---


# Question
Title: Is there a way to not include the {{ content }} variable in a node template and still have the node cache clear when the node is updated?
We have nodes that have dozens of fields and have elected to not include the {{ content }} variable as it is tedious and looks messy having something like the following just to **not** print the fields. We're manually outputting each field as needed like {{ content.myfield }}.

The problem is that when the {{ content }} variable is not in a template then that node's cache does not get cleared when a user modifies the node's content and they have to contact and admin to clear the Drupal caches.

Surely there must be a way to have a node's cache cleared when it is updated and its theme template does not have the {{ content }} variable. Please help.

```
{{ content|without('field_blog_posts','field_breadcumb_t','field_call_to_action','field_call_to_actions_title','field_customer_support_body','field_customer_support_button_te','field_customer_support_image','field_customer_support_title','field_hero_body','field_solutions_hero_image','field_hero_link_1','field_hero_link_2','field_hero_title','field_learn_more_text','field_meta_tags','field_newsletter_signup_banner','field_newsletter_signup_banner_m','field_product_spotlight_title','field_read_more_link_text','field_section_one_category_1','field_section_one_category_2','field_section_one_sub_title','field_section_one_title','field_section_one_video','field_section_two_category_1','field_section_two_category_2','field_section_two_sub_title','field_section_two_title','field_section_twovideo','field_section_two_view_all_link','field_spotlighted_product') }}

```

# Answer
You can simply render it into a variable and just do nothing with it:

```
{# rendering the content into a variable doesn't visibly render anything, but forces the cache to bubble up #}
{% set dummy = content|render %}

```
> 4 votes

# Answer
Install the twig tweak module (v3.x) and then use `cache_metadata` filter.

> When using raw values from entities or render arrays it is essential to ensure that cache metadata are bubbled up.

```
{# Ensure content cache metadata is rendered for the display as a whole. #}
{{ content|cache_metadata }}

```
> 6 votes

---
Tags: caching
---