# Question
Title: How to use dependency injection to load node data?
In a basic Controller class, I tried to load node data using the code from this accepted answer. I.e:

```
$nid = 1;
$node_storage = $this->entityTypeManager()->getStorage('node');
$node = $node_storage->load($nid);

```

However, this answer does not have sufficient detail to help me. Just putting it inside my very simple controller class, I get a WSOD with this error:

> Error: Call to undefined method Drupal\mymodule\Controller\MyModuleController::entityTypeManager() in …

Following the suggestions below the answer by @apaderno, I understood that I I need to declare `ControllerBase` as the parent of my Controller class.

It now looks like this:

```
namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;

class MyController extends ControllerBase {

  public function mymodule() {
      $nid = 1;
      $node_storage = $this->entityTypeManager()->getStorage('node');
      $entity = $node_storage->load($nid);
      dpm($entity, 'entity');
  }
}

```

This is still not a working controller. It still produces a WSOD with this error:

> Symfony\Component\HttpKernel\Exception\ControllerDoesNotReturnResponseException: The controller must return a "Symfony\Component\HttpFoundation\Response" object but it returned null. Did you forget to add a return statement somewhere in your controller?

But the entity now gets loaded , and the exception is something I know how to fix.

I guess my problem is that I am a fairly inexperienced Drupal 10 developer, and don't know all the things about the Drupal 10 programming environment that it seems that most other Drupal developers take for granted that one already knows.

# Answer
`entityTypeManager()` is a method defined from the `ControllerBase` class, even in Drupal 10. `ControllerBase::$entityTypeManager` is one of its properties, but I would use `ControllerBase::entityTypeManager()` because it initializes that property, if it was not already initialized.

```
protected function entityTypeManager() {
  if (!isset($this->entityTypeManager)) {
    $this->entityTypeManager = $this->container()->get('entity_type.manager');
  }
  return $this->entityTypeManager;
}

```

If that is not one of the parent classes for the controller, I would do as the documentation for that class says (if the controller class does not contain trivial code) and use the `ContainerInjectionInterface` to implement the `create()` method necessary to inject the required dependencies.

For reference, this is the suggestion given in the `ControllerBase` documentation. (Emphasis is mine.)

> Controllers that use this base class have access to a number of utility methods and to the Container, which can greatly reduce boilerplate dependency handling code. However, it also makes the class considerably more difficult to unit test. Therefore this base class should only be used by controller classes that contain only trivial glue code. Controllers that contain sufficiently complex logic that it's worth testing **should not use this base class but use `ContainerInjectionInterface` instead**, or even better be refactored to be trivial glue code.

If you want to have available a `entityTypeManager()` method without extending that class, I would use code similar to the following one.

```
use Drupal\Core\Entity\EntityTypeManager;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;

class Controller implements ContainerInjectionInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManager
   */
  protected $entityTypeManager;

  /**
   * Constructs a new Controller object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager
   *   The entity type manager.
   */
  public function __construct(EntityTypeManager $entityTypeManager) {
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container->get('entity_type.manager');
  }

  /**
   * Retrieves the entity type manager.
   *
   * @return \Drupal\Core\Entity\EntityTypeManager
   *   The entity type manager.
   */
  public function entityTypeManager() {
    return $this->entityTypeManager;
  }

}

```

Otherwise, to simply use the `ControllerBase` class, I would take the `BookController` code as example.

```
use Drupal\book\BookExport;
use Drupal\book\BookManagerInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Link;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Controller routines for book routes.
 */
class BookController extends ControllerBase {

  /**
   * Constructs a BookController object.
   *
   * @param \Drupal\book\BookManagerInterface $bookManager
   *   The book manager.
   * @param \Drupal\book\BookExport $bookExport
   *   The book export service.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer.
   */
  public function __construct(BookManagerInterface $bookManager, BookExport $bookExport, RendererInterface $renderer) {
    $this->bookManager = $bookManager;
    $this->bookExport = $bookExport;
    $this->renderer = $renderer;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('book.manager'),
      $container->get('book.export'),
      $container->get('renderer'));
  }

  /**
   * Prints a listing of all books.
   *
   * @return array
   *   A render array representing the listing of all books content.
   */
  public function bookRender() {
    $book_list = [];
    foreach ($this->bookManager->getAllBooks() as $book) {
      $book_list[] = Link::fromTextAndUrl($book['title'], $book['url']);
    }
    return [
      '#theme' => 'item_list',
      '#items' => $book_list,
      '#cache' => [
        'tags' => $this->entityTypeManager()->getDefinition('node')->getListCacheTags(),
      ],
    ];
  }

}

```

`BookController` adds its own dependencies, but it can still use `$this->entityTypeManager()` to get the entity type manager.

As for the exception thrown in line 135, this is the code that causes that exception.

```
$entity_types = $this->getEntityTypes();
$parameter_definitions = $route->getOption('parameters') ?: [];

$result = FALSE;

if (is_array($controller)) {
  [$instance, $method] = $controller;
  $reflection = new \ReflectionMethod($instance, $method); // Line 135
}
else {
  $reflection = new \ReflectionFunction($controller);
}

```

For some reason, PHP does not found the `\Drupal\mymodule\Controller\MyController` class, for example because the class namespace is wrong. (There could be other reasons for which PHP autoload cannot load that class, but I could not recall them at the moment.)
> 2 votes

---
Tags: entities, dependency-injection, 10
---


# Question
Title: How to learn the context for using methods provided by the Drupal API
I am trying to use the code example provided by this accepted answer – and failing. In this particular case it seems that it is necessary to know two things in order to successfully use this code, that is not included in the answer:

* The *parent* class to declare for my class in order to make the method provided by Drupal available.
* The "use" statement(s) required that make my class load this parent class.

I see a lot of these "partial" answers in this forum and elsewhere. The assumption seems to be that developers just "know" what missing bits to add to make the code examples code work correctly.

However, due to my inexperience, I am unable to figure this out by myself. Can someone capable of doing this tell me how you do it?

# Answer
I was very lost in the transition from D7 to 8+. I was one of those people who "learned Drupal" (from 5 to 7), and so when version 8 switched to OOP, a lot of my Drupal knowledge no longer applied, and I didn't have a deep background in PHP to help me out.

If you're in a similar situation, the book Drupal 8/9/10 Module Development by Daniel Sipos helped me to see both at a high and low level how things are done now. I would consider myself a hobbyist programmer and I own every book Amazon sells with Drupal in the title, and this is the one that has helped me the most in just understanding what the heck Drupal is doing, particularly all the "new" (as of D8) classes and services stuff.

The Drupalize.me screencasts are also very good, although they cost significantly more than a dev book.

Another thing that can help a lot is having an IDE set up properly (code completion for Drupal classes, automatic checks for Drupal coding standards, maybe PHPStan). I use PHPStorm which costs a little money but prevents a huge number of mistakes. For example, if you paste a code example from this site in there without using the class, the Problems pane will warn you that the class is unknown, and you can right-click the class name to import it automatically.

VSCode is also good and free but maybe a bit harder to configure (it was harder for me anyway, although that could be because I'm used to PHPStorm). Of course, if you're like me, setting up the IDE is also a learning experience, but there are docs on Drupal.org and if you choose PHPStorm you get support from real engineers with your subscription.

Also, using a local dev environment like ddev or lando with the IDE will really raise your skill level. Specifically, you need to have xdebug available in your dev environment and know how to use it. With Drupal 7, most of them I was able to get by without a debugger because I could follow the code as the steps occurred more or less in order. With D8+'s OOP, that's impossible; you have to have a debugger.
> 2 votes

---
Tags: dependency-injection
---


# Question
Title: Using REST API services to create content with field entity references that do not yet exist
I'm using Drupal 9.4 and trying to create content via the REST API web services where one of the field's in this content is a reference to a taxonomy term that doesn't exists until the current node is created.

My goal is to import content that looks like a multi paged forum thread with the 1st page being the "parent" of the group. This special field I call: "Parent Page" which is a entity reference. The way this works when done manually I first would create the content then edit it again and input the current node into this "Parent Page". This actually creates a taxonomy term which is how it links all the other sub-pages.

I currently have it working where I'm able to create all the pages in a loop. But missing the "parent page" field.

# Answer
Using node.js, you'll need to make sure you have your code setup in async await to be able to create your first parent node and then edit it again after you create the term to itself. From there creating the other sub pages, you'll just be able to add in this entity reference easily.

Below is the code broken up into 3 functions:

**postNode** \- To create nodes

**postTerm** \- To create the taxonomy term

**editParent** \- To "patch" update the parent node with the term

Be aware of the multiple async and and promise functions to account for the term creation that needs to happen after the first parent node is created.

```
const https = require('https');

async function fetchData() {
  try {
    const data = await postNode('Part 1 -- This is my title', 'body text here', '356', '1');
    const parsedData = JSON.parse(data);
    return parsedData;
  } catch (error) {
    throw error;
  }
}

fetchData()
  .then(async (data) => {
    console.log(data);
    const myterm = await postTerm(data.title[0].value,'chats');
    const parsedMyterm = JSON.parse(myterm);

    const tidParent = parsedMyterm.tid[0].value;
    editParent(data.nid[0].value, tidParent);
    postNode('part 2', 'body text here', tidParent, '2');
    postNode('part 3', 'body text here', tidParent, '3');
    postNode('part 4', 'body text here', tidParent, '4');
  })
  .catch((error) => {
    console.error(error);
  });

function postNode (title, body, par, page) {
return new Promise((resolve, reject) => {
  const postData = JSON.stringify({
    type: [{ target_id: 'chats' }],
    title: [{ value: title }],
    body: [{ value: body, format: 'full_html' }],
    field_chat_parent: [{ target_id: par }],
    field_page: [{ value: page }],
  });

  const options = {
    hostname: 'mydomain.com',
    path: '/node?_format=json',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Basic ' + Buffer.from('myuser:password').toString('base64'),
      'Content-Length': Buffer.byteLength(postData),
    },
  };

  const request = https.request(options, (response) => {
    let data = '';

    response.on('data', (chunk) => {
      data += chunk;
    });

    response.on('end', () => {
      resolve(data);
    });
  });

  request.on('error', (error) => {
    reject(error);
  });

  request.write(postData);
  request.end();

});
}

function postTerm(termName, vocab) {
return new Promise((resolve, reject) => {
  const postData = JSON.stringify({
    vid: [{ target_id: vocab, target_type: 'taxonomy_vocabulary' }],
    name: [{ value: termName }],
  });

  const options = {
    hostname: 'mydomain.com',
    path: '/taxonomy/term?_format=json',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Basic ' + Buffer.from('myuser:password').toString('base64'),
      'Content-Length': Buffer.byteLength(postData),
    },
  };

  const request = https.request(options, (response) => {
    let data = '';

    response.on('data', (chunk) => {
      data += chunk;
    });

    response.on('end', () => {
      resolve(data);
    });
  });

  request.on('error', (error) => {
    reject(error);
  });

  request.write(postData);
  request.end();
});
}

function editParent (nid, par) {
  const postData = JSON.stringify({
    type: [{ target_id: 'chats' }],
    field_chat_parent: [{ target_id: par }]
  });

  const options = {
    hostname: 'xxxx.yyyy',
    path: '/node/'+nid+'?_format=json',
    method: 'PATCH',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Basic ' + Buffer.from('myuser:password').toString('base64'),
      'Content-Length': Buffer.byteLength(postData),
    },
  };

  const request = https.request(options, (response) => {
    let data = '';

    response.on('data', (chunk) => {
      data += chunk;
    });

    response.on('end', () => {
      console.log(data);
    });
  });

  request.on('error', (error) => {
    console.log(error);
  });

  request.write(postData);
  request.end();

}

```
> 1 votes

---
Tags: 9, services
---


# Question
Title: How to know what installed modules are contrib modules from the GUI?
I wish to remove all contrib modules so I could upgrade my core from version 9 to version 10.

I have installed several contrib modules, some time has passed and my problem is that for some modules, I may not recall if they are contrib or core, when looking at `example.com/admin/modules/uninstall`.

How to know what installed modules are contrib modules from the GUI?
If this can't be done from GUI so I guess I have to navigate to `WEB_APPLICATION_ROOT/modules`.

# Answer
You do not need to remove contrib modules to upgrade core. Instead, you should upgrade the contrib modules to Drupal 10-compatible versions and then upgrade core from 9 to 10.

To check if all of your contrib modules are ready for Drupal 10, you can use the Upgrade Status module. Install the module and go to Reports as an administrator, and then choose Upgrade Status. You can then check which contrib modules are ready for D10.

You only need to uninstall a module to upgrade if it is not D10-compatible.
> 2 votes

---
Tags: installation
---


title: Using Drupal's Core classes as services

text:
# Question
Title: Using Drupal's Core classes as services
I have rather a general question that would help me to undestand using services in Drupal 8+ and when it is worth to do so.

I have found a useful method createFromRoute which is part of

> namespace Drupal\Core;

It is defined in Link.php file.

I have found plethora of examples in code when it is just called like this

```
Link::createFromRoute(... parameters here)

```

But, is calling this method like that a good practice? Should't this be somehow used as a service?

Why yes/no?

# Answer
The `\Drupal\Core\Link` class is not used to implement a service and its `createFromRoute()` method is static. The only way to call it is like `CommentBreadcrumbBuilder::build()` does, for example.

```
$breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));

```

You could also directly create an instance of the `Link` class, as that same method does.

```
$breadcrumb->addLink(new Link($entity->label(), $entity->toUrl()));

```

`Link::__construct()` requires the text to show in the link and the URL, differently from `Link::createFromRoute()` which requires the text to show in the link and the route name.
(This means that, when you are creating the link from a route, `Link::createFromRoute()` is the method you want to use.)
> 1 votes

---
Tags: 9, services
---


# Question
Title: phpcs: How to ignore Drupal's 80 char line length limit
I want to use PHP CodeSniffer with the default `Drupal` and `DrupalPractice` rulesets to check my custom modules. But I definitly don't want the 80 char line length limit, and phpcs is spamming the report with those warnings. I've created a phpcs.xml in my project root (taken from this blog)

```
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="my_drupal10_phpcs_configuration">

  <rule ref="Drupal"/>
  <rule ref="DrupalPractice"/>

  <arg name="extensions" value="php,module,inc,install,test,profile,theme,css,info,txt,md,yml"/>

  <exclude-pattern>*/.git/*</exclude-pattern>
  <exclude-pattern>*/.vscode/*</exclude-pattern>
  <exclude-pattern>*/.idea/*</exclude-pattern>
  <exclude-pattern>*/bower_components/*</exclude-pattern>
  <exclude-pattern>*/node_modules/*</exclude-pattern>
  <!--Exclude third party code.-->
  <exclude-pattern>*/vendor/*</exclude-pattern>

  <file>./web/modules/custom</file>
  <file>./web/themes/custom</file>

  <!-- MY CHANGE: Ignore the 80char line length limit. -->
  <rule ref="Generic.Files.LineLength">
    <properties>
      <property name="lineLimit" value="120"/>
      <property name="absoluteLineLimit" value="0"/>
    </properties>
  </rule>
</ruleset>

```

but I still get spammed by messages like

```
 180 | WARNING | Line exceeds 120 characters; contains 141 characters
 187 | WARNING | Line exceeds 80 characters; contains 105 characters

```

How can I override Drupal's 80 chars with a soft limit of 120 chars?

# Answer
My problem was copy&pasting the rule into the root tag. To override the Drupal ruleset, all those overrides have to be nested. My working phpcs.xml:

```
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="drupal10_phpcs_configuration">

  <!-- Use Drupal and DrupalPractice standards. -->
  <!-- CUSTOM OVERRIDES NEED TO GO INSIDE THIS TAG -->
  <rule ref="Drupal">
    <!-- Ignore "Missing file doc comment" errors. -->
    <exclude name="Drupal.Commenting.FileComment.Missing"/>

    <!-- Don't check line length in text files at all. -->
    <exclude name="Drupal.Files.TxtFileLineLength.TooLong"/>

    <!-- Change the line length limit to 120 chars. -->
    <properties>
      <property name="lineLimit" value="120"/>
      <property name="absoluteLineLimit" value="0"/>
    </properties>
  </rule>
  <rule ref="DrupalPractice"/>

  <!-- Inluce the extensions of the files we want to test. -->
  <arg name="extensions" value="php,module,inc,install,test,profile,theme,css,info,txt,yml,md"/>

  <!--Exclude folders used by common frontend tools. These folders match the file_scan_ignore_directories setting in default.settings.php-->
  <exclude-pattern>*/.git/*</exclude-pattern>
  <exclude-pattern>*/.vscode/*</exclude-pattern>
  <exclude-pattern>*/.idea/*</exclude-pattern>
  <exclude-pattern>*/bower_components/*</exclude-pattern>
  <exclude-pattern>*/node_modules/*</exclude-pattern>
  <!--Exclude third party code.-->
  <exclude-pattern>*/vendor/*</exclude-pattern>

  <!-- Inspect the following directories. -->
  <file>./web/modules/custom</file>
  <file>./web/themes/custom</file>
</ruleset>

```
> 2 votes

---
Tags: coding-standards
---


# Question
Title: How do you get the current directory in a command method?
In a standard Drupal 8 environment, the current working directory is override and becomes the document root of the site. This is a bit troublesome for Drupal Console command implementations that wants to know where the command is running (e.g. import command need that to resolve the given relative path of the target file).

For example:

```
namespace Drupal\foobar\Command;

use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Drupal\Console\Core\Command\ContainerAwareCommand;

/**
 * Class ImportCommand.
 *
 * Drupal\Console\Annotations\DrupalCommand (
 *     extension="foobar",
 *     extensionType="module"
 * )
 */
class ImportCommand extends ContainerAwareCommand {

  /**
   * {@inheritdoc}
   */
  protected function configure() {
    $this
      ->setName('foobar:import')
      ->setDescription($this->trans('Import something'))
      ->addArgument('file', InputArgument::REQUIRED, 'The file to import');
  }

  /**
   * {@inheritdoc}
   */
  protected function execute(InputInterface $input, OutputInterface $output) {
    $this->getIo()->info('execute');

    // **** here ****
    $file = $input->getArgument('file');

    // ...
    // ...
  }

}

```

Now, consider a user running this command:

```
drupal --root=/var/www/html foobar:import ./foobar.json

```

You can virtually run this command anywhere in your system.

The relative path provided to argument `$file` (i.e. `./foobar.json`) is expected to be resolved relative to the runner's current working directory. Normal PHP script can get the information from getcwd(). But in a Drupal Console environment, the function `getcwd()` returns the document root of the site.

The normal function `getcwd()` obviously don't work. Is there a way?

# Answer
For Drush you use `$this->getConfig()->cwd()`

As I found here https://www.drupal.org/project/drush/issues/297611

They may share enough for this to work.

Edit with a warning: If you are using Drush directly then this will work. If you are using Drush launcher then it may mess up this context. Generally `/usr/local/drush` or whatever is a launcher. if you call `./vendor/bin/drush` it is not.
> 1 votes

---
Tags: 8, console
---


# Question
Title: Why does core create RSS feeds for taxonomy terms?
Drupal 9.5.8 standard installation; I never did anything about RSS feeds in that website.

In Google Search Console, under ***Crawled - currently not indexed*** section, I was surprised to come across this webpage:

```
example.com/taxonomy/term/NUMBER/feed

```

In `/admin/modules` I read that the (deprecated) module **Aggregator** isn't on, and I don't recall ever turning it on.

What may cause the RSS feed webpage to be created and how to prevent the creation of such webpages?

# Answer
The Drupal 9 standard profile creates RSS feeds for taxonomy terms by default.

If you don't want the feeds, you can remove (delete or disable) them from the taxonomy term view in Admin -\> Structure -\> Views.
> 3 votes

---
Tags: 9, feeds
---


title: Can I use the Devel Generate module?

text:
# Question
Title: Can I use the Devel Generate module?
I have content type with the *Product ID*, *Name*, *Image*, *Description*, *Category*, and *Price* fields.

Will the Devel Generate module create sample products?

I have tried using it, but it generates some data which is not related to this, some random images, and data that is not in English.

# Answer
> 2 votes
You can use Devel Generate Commerce to generate Commerce Products.

Basic example: `drush devel-generate:commerce`

Advanced example: `drush devel-generate:commerce --products_num=10 --kill`

---
Tags: commerce
---


# Question
Title: Embedded images are not working in CKEditor 5
While migrating CKEditor 4 to 5, images added through entity embed ( E ) option in CKEditor 4 is not appearing after switching to CKEditor 5. Any idea how to make it work in CKEditor 5?

in CKEditor 4

in CKEditor 5

The image added in CKEditor 4 is disappearing after swithing to CKEditor 5 as in ckeditor 5 entity embed is not there and using drupal media.

# Answer
Entity Embed does not yet support CKEditor5. Work is ongoing here, and you can help move the process forward by testing the latest patch.

Otherwise, you can wait for a release of the Entity Embed plugin that supports CKEditor 5.

Alternately, you could write your own code to replicate what the Entity Embed module does... but why do that when you can help the community and save time yourself by working on the Entity Embed module directly?
> 1 votes

# Answer
Entity embed does not have an official release for D10 yet, it is still in development. There is an issue you can follow for patches and updates.
> 0 votes

---
Tags: media, wysiwyg, 10
---


# Question
Title: Altering paragraph field within revision using preprocess hook
I'm using a hook\_preprocess function (`hook_preprocess_entity_print`) to alter the content within a paragraph field prior to rendering (replacing some strings based on a regex). This works great when I'm working on the node, but not when I'm trying to do the same on a revision of the node.

This works for the node:

```
/**
 * Implements hook_preprocess_entity_print().
 */
function mymodule_preprocess_entity_print(&$variables) {
  $route = \Drupal::routeMatch();
  $entity_id = $route->getParameter('entity_id');
  $node = \Drupal::entityTypeManager()->getStorage('node')->load($entity_id);
  $type = $node->getType();
  if ($type === 'product_child') {
    foreach ($node->get('field_submittal_wysiwyg') as $paragraph) {
      $type = $paragraph->entity->getType();
      switch ($type) {
        case 'submittal_2_col':
          $field_submittal_text = $paragraph->entity->field_submittal_text_1->value;
          $field_submittal_text = mymodule_token_replace($field_submittal_text, $variables);
          $paragraph->entity->field_submittal_text_1->value = $field_submittal_text;
          break;
      }
    }
  }
}

```

When I decided to make these same replacements work when rendering a revision of the node, I tried this first:

```
/**
 * Implements hook_preprocess_entity_print().
 */
function mymodule_preprocess_entity_print(&$variables) {
  $route = \Drupal::routeMatch();
  $entity_id = $route->getParameter('entity_id');
  $revision_id = $route->getParameter('revision_id');
  $node_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($revision_id);
  $type = $node_revision->getType();
  if ($type === 'product_child') {
    foreach ($node_revision->get('field_submittal_wysiwyg') as $paragraph) {
      $type = $paragraph->entity->getType();
      switch ($type) {
        case 'submittal_2_col':
          $field_submittal_text = $paragraph->entity->field_submittal_text_1->value;
          $field_submittal_text = mymodule_token_replace($field_submittal_text, $variables);
          $paragraph->entity->field_submittal_text_1->value = $field_submittal_text;
          break;
      }
    }

  }
}

```

I can confirm that I'm getting the correct values for the draft revision in `$field_submittal_text`. But when I try to set the value of the paragraph, it works only for the published node.

I figured I must not be loading the paragraph revisions referenced within the node revisions. So I then tried to address that:

```
/**
 * Implements hook_preprocess_entity_print().
 */
function mymodule_preprocess_entity_print(&$variables) {
  $route = \Drupal::routeMatch();
  $entity_id = $route->getParameter('entity_id');
  $revision_id = $route->getParameter('revision_id');
  $node_revision = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($revision_id);
  $type = $node_revision->getType();
  if ($type === 'product_child') {
    $field_submittal_wysiwyg = $node_revision->field_submittal_wysiwyg->referencedEntities();
    foreach ($field_submittal_wysiwyg as $paragraph) {
      $paragraph_type = $paragraph->getType();
      switch ($paragraph_type) {
        case 'submittal_2_col':
          $field_submittal_text = $paragraph->field_submittal_text_1->value;
          $field_submittal_text = mymodule_token_replace($field_submittal_text, $variables);
          $paragraph->field_submittal_text_1->value = $field_submittal_text;
          break;
      }
    }
  }
}

```

Again, I can confirm that I'm getting the correct values for `$field_submittal_text` based on the revision that I'm trying to load. But the last line before the break isn't changing what is rendered.

What do I need to do to set the value of the paragraph field for a revision before rendering?

ETA: I'm attempting to replace some product attribute values in several paragraph WYSIWYG fields with values from another field, based on a product\_id sent in through the route parameters. So I need access to multiple fields in order to do these replacements.

# Answer
> 1 votes
The purpose of a preprocess hook is to prepare the variables printed in the template. Check the `{{...}}` statements in the Twig template.

Some other options:

* Look for a different template that prints the variable you want to change.
* Create a custom text filter and add it to the text format.
* Add a #post\_render callback, see How to alter page content?

---
Tags: hooks
---


# Question
Title: How to enable Font Family, Font Size, Font Colour, and Justification?
I have installed Drupal 10.0.08. on my Windows 10 PC .It is running on XAMPP framework locally.

When I want to create content (either a *Basic Page* or an *Article* node) using CKeditor 5 on Drupal 10.0.8, the menu looks like in the screenshot.

>

I **have enabled the full HTML option** at the bottom.

I am not able to find any options for:

* The text font
* Justification options (*right*, *left*, *center*, *justified*)
* Text size

How do I enable them?

Do I have to install other modules to activate those options?

# Answer
1. Browse to /admin/config/content/formats.
2. Click "configure" on the text format you wish to change.
3. Drag desired toolbar buttons into place.

Buttons not seen there require contributed modules.
> 3 votes

# Answer
"there is a plugin for that". but it's minimally supported and is not covered by the security police (as of 2023/05). It looks as if another plugin is moving to implement this, too - https://www.drupal.org/project/colorbutton/issues/3291717

However, you can achieve something similar with the 'styles' dropdown

* add it to the toolbar of your text format in the admin
* add classes there that reflect your style, like `span.arial|Arial`
* in your themes css, add `span.arial { font-family:arial }`

Optionally, in your theme's `ckeditor5-stylesheets` (google that), add the same
> 0 votes

---
Tags: wysiwyg
---


# Question
Title: How can I add drupalSettings values with the #attached array?
In D7, we have used drupal\_add\_js with DrupalSettings for accessing php variables to javascript files, for that we have used in D7 in my custom function like below

```
function custom_function($data)
{
   drupal_add_js(array('test_ajax_responders' => $data), 'setting');
}

```

But for D9, we need to use #attached property to replace this, but how i need to pass this $data related in to $attachments. Seems this is my custom\_function and $data is populating dynamically, so hard coding with page\_attachments is not a feasible and that is used for different logic

So for this custom point of view how we can attach the drupalSetting variables in to existing $attachements array to get in javascript files. I have tried below possibilities in D9 and nothing worked out.

```
function custom_function($data)
{
    return ['#attached' => ['drupalSettings' => [ 'test_ajax_responders' => $data, ],], ];
}

function custom_function($data) {
    $page['#attached']['drupalSettings']['test_ajax_responders'] = $data;
    \Drupal::moduleHandler()->alter('page_attachments', $page);
}

libraries.yml file example

dependencies:
- core/drupal
- core/jquery
- core/drupalSettings

```

Please help me to get my $data custom variable in to javascript files by using the above way.

# Answer
This depends on how dynamic the data is. Where do you get it from? Ideally you put it there. For example, attach the js data of a node in a preprocess hook. See https://drupal.stackexchange.com/a/288989/47547

If this is not possible attach it to $attachments\['#attached'\] via hook\_page\_attachments() and declare the dynamic cache metadata in $attachments\['#cache'\]. However, this makes the page less cacheable. Depending on how dynamic the data is, consider loading it lazily via Ajax when the client is already running Ajax like in your case.
> 0 votes

---
Tags: javascript, 9
---


# Question
Title: Errors Thrown by Composer and Drupal Core
I'm working as a part of a development team where my colleagues (team members) work in separate Git branches created out of and then merging their branches into a common development branch, `develop`.

After fetching, checking out and pulling the latest changes in one of their branches and clearing the cache using Drush, I get the below errors in Git bash. These errors also started appearing when I visited my site's homepage's URL in the browser.

```
PHP Warning:  require(C:\xampp\htdocs\drupal9\vendor\composer/../../web/core/includes/bootstrap.inc): failed to open stream: No such file or directory in C:\xampp\htdocs\drupal9\vendor\composer\autoload_real.php on line 45
PHP Fatal error:  require(): Failed opening required 'C:\xampp\htdocs\drupal9\vendor\composer/../../web/core/includes/bootstrap.inc' (include_path='C:\xampp\htdocs\drupal9\vendor/pear/archive_tar;C:\xampp\htdocs\drupal9\vendor/pear/console_getopt;C:\xampp\htdocs\drupal9\vendor/pear/pear-core-minimal/src;C:\xampp\htdocs\drupal9\vendor/pear/pear_exception;C:\xampp\php\PEAR') in C:\xampp\htdocs\drupal9\vendor\composer\autoload_real.php on line 45

Warning: require(C:\xampp\htdocs\drupal9\vendor\composer/../../web/core/includes/bootstrap.inc): failed to open stream: No such file or directory in C:\xampp\htdocs\drupal9\vendor\composer\autoload_real.php on line 45

Fatal error: require(): Failed opening required 'C:\xampp\htdocs\drupal9\vendor\composer/../../web/core/includes/bootstrap.inc' (include_path='C:\xampp\htdocs\drupal9\vendor/pear/archive_tar;C:\xampp\htdocs\drupal9\vendor/pear/console_getopt;C:\xampp\htdocs\drupal9\vendor/pear/pear-core-minimal/src;C:\xampp\htdocs\drupal9\vendor/pear/pear_exception;C:\xampp\php\PEAR') in C:\xampp\htdocs\drupal9\vendor\composer\autoload_real.php on line 45

```

Usually I can fix errors but I don't how to fix the above since PHP has pointed out files which are in the `vendor` folder, created by Composer for all project dependencies, and Drupal `core` folder. Trying to debug each error by modifying code in each dependency's and `core` folder's source code would not be a good idea because that is not the standard approach to fixing errors thrown by Composer and Drupal.

Can anyone please help me?

The Drupal core version is 9.1.0.

# Answer
Okay, I was able to fix all the errors in one go. I simply executed `composer update` and Composer pulled in all the missing dependencies in `composer.json` added by my colleagues and the errors went away. Cheers. :)
> 0 votes

---
Tags: composer
---


# Question
Title: How to add a custom row class or ID to type table render elements
I'm trying to add row ID's for a custom table I implemented via a custom module. But when I append an ID to the `'#attributes'` array it becomes the table ID, not the row ID. How can I define IDs for rows?

This is what I have so far:

```
$form['table'] = [
  '#type' => 'table',
  '#header' => $header_table,
  '#rows' => $rows,
  '#attributes'=> ['id' => 'IdforRow'],
  '#empty' => t('No Data found'),
  '#prefix' => '<b>Total Tenders : '.@$count.'</b><br>',
  '#suffix' => '',
];

```

# Answer
> 0 votes
The row should be prepared as given below, to have id and class for each rows.

```
$rows[] = [
  'id' => $row_id,
  'class' => 'row-class',
  'data' => [
    $cell1_data,
    $cell2_data,
  ]
]

```

# Answer
> -2 votes
Try to add the ID in an array format like below:

```
$form['table'] = [
    '#type' => 'table',
    '#header' =>  $header_table,
    '#rows' => $rows,
    '#attributes'=>[
      'id' => 'IdforRow'
    ],
    '#empty' => t('No Data found'),
    '#prefix' => '<b>Total Tenders : '.@$count.'</b><br>',
    '#suffix' => '',
];

```

---
Tags: 8, theming
---


# Question
Title: How can I prevent a custom node page template is used when editing a node?
I'm theming some specific Drupal 9 pages with custom templates (e.g. `page--node--17.html.twig`).

That said, the theme carries over when I go to https://example.com/node/17/edit.

I only want the template to appear on the front end, not when I go in to edit a node (I want that to remain the same basic `page.html.twig` that it usually is).

How can I fix this?

# Answer
> 4 votes
An easy solution would be visit /admin/appearance and at the bottom, check off:

> Use the administration theme when editing or creating content

---
Tags: theming
---


# Question
Title: Is there a place to find a list of good premium/paid drupal modules?
I have a client that has "deep pockets" and so higher ups are pushing for us to use premium modules so that "the user experience is better for the client". I haven't ever used a premium/paid drupal module and haven't been able to find a place where I can see a list of them to see if any would be beneficial (specifically higher ups are looking for premium calendar and hero banner modules).

Any one know of where to find options like those (assuming they are available)?

Thanks

# Answer
Maybe the higher-ups have confused Drupal with WordPress. Drupal has very few paid modules; most of the ones I know of are related to simplifying OAuth login (sign in with Apple/Google/Facebook, etc.), which is a site-specific need.

There are some paid themes, but these are generally less than $100 and often not a "premium" experience because the default Drupal theme of Olivero is far more extensively tested and has greater browser compatibility and accessibility support than the "premium" themes. If a company really wants theming done right, they will hire someone skilled to do a custom theme.

This is true for custom modules more generally-- it would be very difficult in Drupal to do a great "paid" module because it would have to compete with a free module that does the same thing, but is more widely used and thus gets more bug reports and is better tested. However, it may be that the current modules do not support a feature they want. Some module maintainers will accept sponsorship to add features.

So, if there is money to spend, consider suggesting investing in Drupal by sponsoring the development of a module or feature that provides whatever feature the company needs that doesn't already exist. This way, everyone using Drupal can benefit in the same way that the company benefits from using Drupal.
> 3 votes

---
Tags: 9
---


# Question
Title: can a module introduce paragraph types and templates?
I'm building a very complicated paragraph layout with multiple levels of interconnecting paragraph types. At the moment, configuration and template files are all over the place.

So, I was wondering if there is a way to do the same using a module so, it will have all packaged up in one place.

Is there a way that a module to introduce a paragraph type?

Only things I've found so far was a module creating from paragraph types.

# Answer
> 4 votes
Everything will be stored in Drupal's configuration management. So you could add the relevant configuration into your */config/install* folder of your module. When your module is first installed the configuration will be imported onto the site.

Anything else you might need to do in `hook_install()`, such as altering existing configuration, for example user permissions, which cannot be overridden this from your module.

Include default configuration in your Drupal module is relevant for you.

In terms of templates, that's fairly straight forward and a module can define its own templates using `hook_theme()`. There are plenty of examples and documentation.

---
Tags: 9, paragraphs
---


# Question
Title: Pathauto tokens for taxonomy terms except root
Thanks to the Pathauto module and tokens, it is very easy to generate URLs with *\[node:field\_product\_category:entity:parents:join-path\]/\[node:field\_product\_category:entity\]/\[node:title\]*, but I would like to start at the 2nd level.

Is it possible to exclude the root level from *\[node:field\_product\_category:entity:parents:join-path\]*?

Instead of `http://www.example.com/redundant_root_category/category_from_level_2/category_from_level_3/super_product`, I would like to get `http://www.example.com/category_from_level_2/category_from_level_3/super_product`.

# Answer
The default tokens won't allow you to do this, but the only thing you're missing I think is an array token that removes the first element, I'd call it "tail". See token\_token\_info(), which defines for example a 'reversed and other array tokens:

```
$info['tokens']['array']['reversed'] = array(
  'name' => t('Reversed'),
  'description' => t('The array reversed.'),
'type' => 'array',
);

```

And the implementation for that is in token\_tokens():

```
// [array:reversed:*] chained tokens.
if ($reversed_tokens = \Drupal::token()->findWithPrefix($tokens, 'reversed')) {
  $replacements += \Drupal::token()->generate('array', $reversed_tokens, array('array' => array_reverse($array, TRUE)), array('array sort' => FALSE) + $options, $bubbleable_metadata);
}

```

Instead of array\_reverse(), you'd call array\_shift() on the array first and then pass that along.

Might also be a useful standard token to have in the token.module, if someone wants to provide a patch.

Your token would then look like this:

```
[node:field_product_category:entity:parents:tail:join-path]

```
> 3 votes

# Answer
You have to create a custom module. I made this module for a Drupal 10 site I'm developing and my quick tests show it working. For this example we'll name our custom module *all\_but\_first\_token\_modifier*

1. Create dir `/web/modules/custom/all_but_first_token_modifier`. All subsequent steps are inside of this directory.
2. Create file `all_but_first_token_modifier.info.yml` with this content:
```
name: All But First Array Token Modifier
type: module
description: 'Token modifier to get the array of items without the first element'
package: All But First Array Token Modifier
core_version_requirement: ^8 || ^9 || ^10
dependencies:
  - token:token

```
3. Create file `all_but_first_token_modifier.module` with this content:
```
<?php
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Render\BubbleableMetadata;

function all_but_first_token_modifier_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    // Main module help for the custom_token module.
    case 'help.page.all_but_first_token_modifier':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Custom token module to get the array without the first element') . '</p>';
      return $output;

    default:
  }
}

function all_but_first_token_modifier_token_info() {

  $info['tokens']['array']['all_but_first'] = array(
    'name' => t('All But First'),
    'description' => t('The array without the first element.'),
    'type' => 'array',
  );

  return $info;
}

function all_but_first_token_modifier_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
  $replacements=[];
  // Array tokens.
  if ($type == 'array' && !empty($data['array']) && is_array($data['array'])) {
    $array = $data['array'];

    //$sort = isset($options['array sort']) ? $options['array sort'] : TRUE;
    //$keys = token_element_children($array, $sort);

    /** @var \Drupal\Core\Render\RendererInterface $renderer */
    $renderer = \Drupal::service('renderer');

    foreach ($tokens as $name => $original) {
      switch ($name) {
        case 'all_but_first':
          $all_but_first = array_slice($array,1);
          $replacements[$original] = token_render_array($all_but_first, $options);
          break;
      }
    }

    // [array:all_but_first:*] chained tokens.
    if ($all_but_first_tokens = \Drupal::token()->findWithPrefix($tokens, 'all_but_first')) {
      $replacements += \Drupal::token()->generate('array', $all_but_first_tokens, ['array' => array_slice($array,1)], ['array sort' => FALSE] + $options, $bubbleable_metadata);
    }

  }

  return $replacements;
}

```
4. Enable the module in your Drupal admin interface and you'll now have an additional option for array tokens. It can be used the same as the reverse token modifier. Example: `[term:parents:all_but_first:join-path]`
> 0 votes

---
Tags: 8, path-aliases, tokens
---


# Question
Title: Custom access for a web-based custom type
For my Drupal site, I made a custom type named MyCoolCustomType. I'd like to grant access to view this custom type only to certain condition on user role and properties of the custom content itself (for example, the ModerationState of the content).

I'm quite confused about how to process.

Thanks to a class that extends `RouteSubscriberBase`, I'm trying to modify the route entity.node.canonical to change the `requirements` part. In this part, I'm going to use a dedicated service for `_custom_access`.

Where is a good place to filter only MyCoolCustomType, a service or a subscriber?

# Answer
> 1 votes
Looking at the route subscribers implemented by a Drupal core module, the `Drupal\content_moderation\Routing\ContentModerationRouteSubscriber` class alters the routes in its `setLatestRevisionFlag()` method (called by `ContentModerationRouteSubscriber::alterRoutes()`.

```
// Only set the flag on entity types which are revisionable.
[$entity_type] = explode('.', $entity_form, 2);
if (!isset($this->getModeratedEntityTypes()[$entity_type]) || !$this->getModeratedEntityTypes()[$entity_type]->isRevisionable()) {
  return;
}

$parameters = $route->getOption('parameters') ?: [];

foreach ($parameters as &$parameter) {
  if (isset($parameter['type']) && $parameter['type'] === 'entity:' . $entity_type && !isset($parameter['load_latest_revision'])) {
    $parameter['load_latest_revision'] = TRUE;
  }
}

$route->setOption('parameters', $parameters);

```

Essentially, that code first verifies the entity type is one the module handles and then alters the route definition.
The same should be done from your code: The route subscriber verifies the route is for an handled entity, and then calls `$route->addRequirements()` to add its own `_custom_access`.

---
Tags: 9
---


# Question
Title: Creating your own Node Entity Normalizer
I am trying to create my own Node Entity Normalizer in Drupal 10 to get rid of the unnecessary JSON structure that comes out of the box. For example, instead of my API's returning

```
{
  "nid": [
    {
      "value": 7
    }
  ]
}

```

I want to make it return

```
{
  "nid": 7
}

```

So I've tried the following options in my custom module:

1. Typed Data Interface

example\_normalizer.services.yml

```
services:
  example_normalizer.typed_data:
    class: Drupal\example_normalizer\Normalizer\CustomTypedDataNormalizer
    tags:
    - { name: normalizer, priority: 2 }

```

src/Normalizer/CustomTypedDataNormalizer.php

```
<?php
namespace Drupal\example_normalizer\Normalizer;
use Drupal\serialization\Normalizer\NormalizerBase;
/**
 * Converts typed data objects to arrays.
 */
class CustomTypedDataNormalizer extends NormalizerBase {
  /**
 * The interface or class that this Normalizer supports.
 *
 * @var string
 */
  protected $supportedInterfaceOrClass = 'Drupal\Core\TypedData\TypedDataInterface';
  /**
 * {@inheritdoc}
 */
  public function normalize($object, $format = NULL, array $context = array()) {
    $value = $object->getValue();
    if (isset($value[0]) && isset($value[0]['value'])) {
      $value = $value[0]['value'];
    }
    return $value;
  }
}

```

and

2. Custom Node Entity Normalizer

example\_normalizer.services.yml

```
services:
  example_normalizer.node_entity:
    class: Drupal\example_normalizer\Normalizer\NodeEntityNormalizer
    arguments: ['@entity.manager']
    tags:
    - { name: normalizer, priority: 8 }

```

src/Normalizer/NodeEntityNormalizer.php

```
<?php
namespace Drupal\example_normalizer\Normalizer;
use Drupal\serialization\Normalizer\ContentEntityNormalizer;
use Drupal\Core\Datetime\DrupalDateTime;
/**
 * Converts the Drupal entity object structures to a normalized array.
 */
class NodeEntityNormalizer extends ContentEntityNormalizer {
  /**
 * The interface or class that this Normalizer supports.
 *
 * @var string
 */
  protected $supportedInterfaceOrClass = 'Drupal\node\NodeInterface';
  /**
 * {@inheritdoc}
 */
  public function normalize($entity, $format = NULL, array $context = array()) {
    // Similar logic as above
  }
}

```

However, in both cases, when I clear the cache I am getting the error

```
PHP Fatal error:  Uncaught Error: Class "Drupal\example_normalizer\Normalizer\NodeEntityNormalizer" not found in /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php:262

```

What am I missing in my module that this is not getting picked up?

I'd like to be able to make a call like

```
$serializer = \Drupal::service('serializer')
$custom_json = $serializer->serialize($entity, 'json', ['plugin_id' => 'my_custom_normalizer']

```

# Answer
JSON normalization is not declared in `services.yml`. Instead, you want to use `MyModuleServiceProvider.php` to override the core class.

This is an example from my site overriding FieldItemNormalizer:

```
<?php

namespace Drupal\my_module;

use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Drupal\Core\DependencyInjection\ServiceProviderInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class MyModuleServiceProvider extends ServiceProviderBase implements ServiceProviderInterface {

  /**
   * {@inheritDoc}
   */
  public function alter(ContainerBuilder $container): void {
    $jsonapi_definition = $container->getDefinition('serializer.normalizer.field_item.jsonapi');
    $jsonapi_definition->setClass('Drupal\my_module\Normalizer\MyModuleFieldItemNormalizer');
}

```

Here's a general guide to overriding core services.
> 1 votes

---
Tags: dependency-injection, 10
---


# Question
Title: Get total row count in views-view-fields.html.twig
How can I get the total rows number in **views-view-fields.html.twig** template file in Drupal 8? In Drupal 7, I can get it by the following code.

```
$view = views_get_current_view();
$view->total_rows;

```

Is there any variable to render the total number of rows in Drupal 8?

# Answer
> 8 votes
You can use simple code `{{ view.total_rows }}` in every file template views. Variable **view** is global.

# Answer
> 4 votes
In Drupal 8, views-view.html.twig contains few pre defined variables. Among them, there is a `{{ rows }}` variable that contains **"The results of the view query, if any."**

To get total number of row count, use `{{ rows | length }}`. It will print total number of rows count and if you want it in a variable, do as `{% set count = rows | length %}`

# Answer
> 2 votes
you can use {{ view.result | length }} in views-view-fields.html.twig

# Answer
> 0 votes
If you use an exposed filter and want to show the unfiltered number of total results (like "we are showing you 12 items out of total 345 items"), this gets slightly more complicated. In a `preprocess_views_view` or any other preprocess which gets the view as a variable, run

```
  // Pass original view row count to template
  $pager = \Drupal::service('pager_manager');
  $pager = $pager_manager->getPager();
  $request_stack = \Drupal::requestStack();
  $request = clone ($request_stack->getCurrentRequest());
  $request->query = new ParameterBag;
  $request_stack->push($request);
  $original_view = $variables['view'];
  $view = Views::getView($original_view->id());
  $view->setDisplay($original_view->current_display);
  $view->preExecute($original_view->args);
  $view->execute();
  $view->postExecute();
  $request_stack->pop();
  $pager_manager->createPager($pager->getTotalItems(), $pager->getLimit());
  $variables['total_rows'] = $view->total_rows;

```

# Answer
> 0 votes
One another way to get the total row counts is by directly querying the database for the results. You can use something like below:

```
$total_results = \Drupal::database()
  ->select('view_name')
  ->countQuery()
  ->execute()
  ->fetchField();

```

---
Tags: views, theming
---


# Question
Title: Is there a way to allow entering a value in a node's field if inserting a new node, but make the field disabled if updating that same node?
I'm using Drupal 7 and I have a standard text field in my Content Type. If the user with role "Standard User" is adding a new node then they should be able to set the Status field text value. However, if the node is already created and they are editing/updating that same node, it should be grayed-out (disabled). Is there a way to do this?

# Answer
```
function my_module_form_node_form_alter(&$form, &$form_state, $form_id) {
  $node = $form_state['node'];

  if ($form_id == "my_content_type_node_form") {

    global $user;

    if (isset($user)) {

      $user_has_standard_user_role = FALSE;

      // Get role information about the user.
      $user_roles = array();
      foreach ($user->roles as $key => $role) {
        $user_roles[$key] = $role;
      }

      foreach ($user_roles as $key => $user_role) {
        if ($user_role == "Standard User") {
          $user_has_standard_user_role = TRUE;
        }
      } // end iterate through user roles

      if ($user_has_standard_user_role) {

        // If this is a new node, let the user edit the field.
        if (!isset($node->nid) || isset($node->is_new)) {
          $form['field_status_field']['und']['#disabled'] = FALSE;
        }

        // If this is not a new node, then disable the field.
        else {
          $form['field_status_field']['und']['#disabled'] = TRUE;
        }
      } // end if user has Standard User role.

      // User is not Standard User, so disable the field.
      else {
        $form['field_status_field']['und']['#disabled'] = TRUE;
      }
    } // end if user is set
  } // end if correct form ID
 } // end function

```
> 0 votes

---
Tags: 7, nodes
---


# Question
Title: How to open an iframe with a different base URL for "Page Not Found" errors in Drupal?
I am working on a Drupal website and I need to implement a functionality where an iframe is opened with a different base URL whenever a "Page Not Found" error occurs. The goal is to display the content from a different website within the iframe.

I have tried implementing a custom module using the hook\_preprocess\_HOOK() and hook\_page\_attachments() hooks, but I'm encountering issues with the code not running when a "Page Not Found" error occurs.

Here is an example of the code I have tried:

```
<?php

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Implements hook_preprocess_HOOK() for page templates.
 */
function iframe_error_preprocess_page(&$variables) {
  // Check if the current page is a "Page Not Found" error.
  $exception = \Drupal::requestStack()->getCurrentRequest()->attributes->get('exception');
  echo"<h1>INSIDE FUNCTION</h1>";
  if (!($exception instanceof NotFoundHttpException)) {
       echo"<h1>INSIDE 404</h1>";
    // Get the base URL of the iframe.
    $iframe_base_url = 'https://usj2.edu.lb';

    // Get the current URL.
    $current_url = \Drupal::request()->getUri();

    // Replace the base URL in the current URL.
    $iframe_url = str_replace('https://usj-dev.usj.edu.lb', $iframe_base_url, $current_url);

    // Build the iframe markup.
    $iframe_markup = '<iframe src="' . $iframe_url . '" width="100%" height="100%"></iframe>';

    // Assign the iframe markup to a variable for use in the page template.
   // $variables['iframe_markup'] = $iframe_markup;
    echo $iframe_markup;
  }
}

```

Your help is appreciated.

# Answer
> 2 votes
You don't need to reinvent the wheel, core has already implemented 4xx status codes for the page template.

You can add the iframe to the main content region to show it in the default page template:

```
/**
 * Implements hook_preprocess_HOOK() for page templates.
 */
function mymodule_preprocess_page__404(&$variables) {
  $variables['page']['content']['iframe'] = [
    '#type' => 'inline_template',
    '#template' => '<iframe src="{{ url }}" width="100%" height="100%"></iframe>',
    '#context' => [
      'url' => 'http://www.example.com',
    ],
  ];
}

```

Or store the iframe URL in your own template variable and print the iframe tag in a custom `page--404.html.twig`.

See the change record https://www.drupal.org/node/2960810

---
Tags: uri
---


# Question
Title: hook_update_n($sandbox) batch getting executed only once
Following is the code where I'm willing to update the `description` of the `field_meta_tags` of all my products using the batch process.

It's getting executed & working as expected, but only for the first batch.

```
function mymodule_update_8001($sandbox) {
  if (!isset($sandbox['total'])) {
    $products = \Drupal::entityQuery('commerce_product')
      ->condition('type', 'default')
      ->execute();
    $sandbox['total'] = count($products);
    $sandbox['current'] = 0;
  }

  $products_per_batch = 25;

  $products = \Drupal::entityQuery('commerce_product')
    ->condition('type', 'default')
    ->range($sandbox['current'], $sandbox['current'] + $products_per_batch)
    ->execute();

  foreach ($products as $product_id) {
    $product = Drupal\commerce_product\Entity\Product::load($product_id);
    $product->set('field_meta_tags', serialize(['description' => '']));
    $product->save();
    $sandbox['current']++;
  }

  \Drupal::messenger()
    ->addMessage($sandbox['current'] . ' products processed.');

  $sandbox['#finished'] = empty($sandbox['total']) ? 1 : ($sandbox['current'] / $sandbox['total']);
}

```

Once the above `hook_update_n($sandbox)` is executed, getting the following output at the terminal:

```
 --------------- ----------- --------------- -------------
  Module          Update ID   Type            Description
 --------------- ----------- --------------- -------------
  mymodule        8001        hook_update_n   Updates.
 --------------- ----------- --------------- -------------

 // Do you wish to run the specified pending updates?: yes.

>  [notice] Update started: mymodule_update_8001
>  [notice] Update completed: mymodule_update_8001
>  [notice] Message: 25 products processed.
>
 [success] Finished performing updates.

```

Not sure how `$sandbox['#finished']` is getting the value as 1, since that's how I remember we ask the batch to stop processing.

# Answer
There is no need for batches if you intend to run all entries in one process.

This is something we had use to update around 30.000 entries i quickly adapted from your example :

```
/**
 * Query all commerce_product of type default
 *
 * *
 * @param array $sandbox
 *
 * @return string
 *  Number of updated rows
 */
function mymodule_post_update_0801(array $sandbox) {
  /** @var $connection Drupal\Core\Database\Connection */
  $connection = \Drupal::service('database');
  $query = $connection->select('commerce_product', 'p');
  $query->fields('p', ['id'])
    ->condition('type', 'default');
  $toUpdate = $query->execute()->fetchAll();

  $result = array_map( 'update_description_value', $toUpdate);

  return sprintf('Number of row updated: %s', count($result));
}

/**
 * Update a product description
 *
 * @param stdClass $defaultProduct
 *  ->id
 *
 * @return string
 *  product id
 */
function update_description_value($productQueried) {
  /** @var $connection Drupal\Core\Database\Connection */
  $connection = \Drupal::service('database');

  $updated = $connection->update('commerce_product')
    ->fields(['field_meta_tags' => serialize(['description' => ''])])
    ->condition('id', $productQueried->id, '=')
    ->execute();

  return $productQueried->id;
}

```

Let me know if there is typo somewhere.
> 0 votes

# Answer
The `drush updb` command will not continue the batch if the update hook does not return a message.

changes required:

* Add `return t("Updated @progress/@max products.", ['@progress' => $sandbox['current'], '@max' => $sandbox['total']]);`
* in function declaration pass $sandbox parameter by reference

changes optional:

* remove messenger()-\>addMessage() as progress is displayed with the return value. It is not good to use messages in update hooks, as messages will be displayed after the hook is finished (not during execution).
* fix range() second parameter as `->range($sandbox['current'], $products_per_batch)` The range parameters are not from-to, but start-length.
> 0 votes

# Answer
Have you considered creating a custom Drush command? If your module is custom, then maybe you don't need to execute the update in `hook_update_HOOK`. See https://www.drupal.org/project/drush9\_batch\_processing
> 0 votes

---
Tags: 8, batch-operations
---


title: Symfony Routing Error

text:
# Question
Title: Symfony Routing Error
My site has completely gone blank after updating modules with Composer. This is the error I get. I've found some similar errors in a topic from the past, but they are all about earlier version of php and don't help me any further.

Rolling back to earlier version doesn't do anything (php and core), and I have no clue where to look for the problem. Anyone has an idea?

```
The website encountered an unexpected error. Please try again later.
TypeError: Argument 2 passed to Symfony\Component\Routing\RouteCollection::add() must be an instance of Symfony\Component\Routing\Route, bool given, called in /home/dkvision/staging/website.com/www/core/lib/Drupal/Core/Routing/RouteProvider.php on line 380 in Symfony\Component\Routing\RouteCollection->add() (line 76 of /home/dkvision/staging/website.com/vendor/symfony/routing/RouteCollection.php).

Symfony\Component\Routing\RouteCollection->add('entity.block.edit_form', ) (Line: 380)
Drupal\Core\Routing\RouteProvider->getRoutesByPath('/admin/structure/block/manage/%') (Line: 332)
Drupal\Core\Routing\RouteProvider->getRoutesByPattern('/admin/structure/block/manage/{block}') (Line: 176)
Drupal\devel\Routing\RouteSubscriber->getRouteParameters(Object, 'edit-form') (Line: 87)
Drupal\devel\Routing\RouteSubscriber->getEntityLoadRoute(Object) (Line: 53)
Drupal\devel\Routing\RouteSubscriber->alterRoutes(Object) (Line: 37)
Drupal\Core\Routing\RouteSubscriberBase->onAlterRoutes(Object, 'routing.route_alter', Object)
call_user_func(Array, Object, 'routing.route_alter', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'routing.route_alter') (Line: 189)
Drupal\Core\Routing\RouteBuilder->rebuild() (Line: 83)
Drupal\Core\ProxyClass\Routing\RouteBuilder->rebuild() (Line: 120)
Drupal\Core\Routing\Router->matchRequest(Object) (Line: 93)
Drupal\Core\Routing\AccessAwareRouter->matchRequest(Object) (Line: 112)
Symfony\Component\HttpKernel\EventListener\RouterListener->onKernelRequest(Object, 'kernel.request', Object)
call_user_func(Array, Object, 'kernel.request', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.request') (Line: 135)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
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: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
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: 709)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

```

# Answer
> 1 votes
In Drupal 9, this is caused by route serialization incompatibilities between PHP 7.4 and 7.3.

Suggested steps is to:

---

If it's still happening, try below steps from this comment.

Truncate the following tables in your database (`drush sql-cli`):

```
TRUNCATE TABLE router;
TRUNCATE TABLE  cache_advagg                           ;
TRUNCATE TABLE  cache_bootstrap                        ;
TRUNCATE TABLE  cache_config                           ;
TRUNCATE TABLE  cache_container                        ;
TRUNCATE TABLE  cache_data                             ;
TRUNCATE TABLE  cache_default                          ;
TRUNCATE TABLE  cache_discovery                        ;
TRUNCATE TABLE  cache_dynamic_page_cache               ;
TRUNCATE TABLE  cache_entity                           ;
TRUNCATE TABLE  cache_jsonapi_normalizations           ;
TRUNCATE TABLE  cache_menu                             ;
TRUNCATE TABLE  cache_page                             ;
TRUNCATE TABLE  cache_render                           ;
TRUNCATE TABLE  cache_rest                             ;
TRUNCATE TABLE  cache_schema_metatag_cache             ;
TRUNCATE TABLE  cache_toolbar                          ;
TRUNCATE TABLE  cachetags ;

```

Rebuild router:

```
drush ev "\Drupal::service('router.builder')->rebuild()"

```

Clear cache:

```
drush cr

```

# Answer
> 0 votes
This error message indicates that there is an issue with a route definition in your Drupal site. The RouteCollection class in Symfony's routing component is expecting an instance of the Route class as the second argument to its add() method, but it is receiving a boolean value instead. This can happen if there is a problem with the route definition, such as a typo, a missing parameter, or an incorrect syntax.

To troubleshoot this error, here are some steps you can take:

Check the recent changes made to your site's code or configuration that may have affected the routing. This error message is usually caused by a code change, such as adding or modifying a route in a custom module, or updating Drupal or a module to a newer version.

Review the route definition that is causing the error. The error message provides a hint to the location of the problematic code in the RouteProvider.php file, which is part of Drupal's core routing system. This suggests that the issue is likely related to a route defined in your site's code or configuration.

Check the syntax of the route definition. Make sure that the route definition follows the correct syntax and that all required parameters are present. The Symfony routing component has specific requirements for defining routes, such as specifying the path, controller, and any additional requirements or defaults. Refer to the Drupal documentation or Symfony documentation for more information on defining routes.

Check for typos or errors in the code. Make sure that all variables and method calls are spelled correctly and that there are no syntax errors or missing code.

If you are unable to identify the issue, you can try disabling custom modules or themes one by one to isolate the problematic code. Alternatively, you can try rolling back recent changes or restoring a backup of your site to a previous working state.

Once you have identified and resolved the issue, the error message should disappear, and your site should function normally again.

---
Tags: 9
---


# Question
Title: Can I enable the Dynamic Page Cache module and the Internal Page Cache module?
In a Drupal 8 site, can I enable the Dynamic Page Cache module and the Internal Page Cache module? Could I have issues when both the modules are enabled, or is it fine to enable both the modules?

# Answer
> 4 votes
According to Wim Leers, who is one of the main architects of the caching system in D8.

> PUBLISHED on OCTOBER 12, 2015
>
> Drupal 8 now has a Dynamic Page Cache. The Page Cache module only works for anonymous users, the Dynamic Page Cache module takes that a step further: it works for any user.
>
> Since April 8, Drupal 8 had its Page Cache enabled by default. Exactly 5 months later, on September 8, the Dynamic Page Cache module was added to Drupal 8, and also enabled by default.
>
> source: Drupal 8's Dynamic Page Cache

Therefore, both of those caching modules come enabled by default out of the box, you don't have to do anything to enable them.

> will not cause any issue?

No issues at all, Drupal 8 was designed to use both.

> **The Page Cache module caches fully rendered HTML responses** — it assumes only one variant of each response exists, which is only true for anonymous users. The innovation in 8 on top of 7’s Page Cache is the addition of cache tags, which allow one to use the Page Cache but still have instantaneous updates: no more stale content.
>
> **The Dynamic Page Cache module caches mostly rendered HTML responses** — because it does not assume only a single variant exists: thanks to cache contexts, it knows the different variants that exist of each part of the page, and thus also of the final (fully assembled) page. During the rendering process, auto-placeholdering ensures that the parts of the page that are too dynamic to cache or are simply uncacheable are replaced with placeholders. These placeholders are only rendered at the very last moment. The Dynamic Page Cache module caches the page just before those placeholders are replaced.
>
> source: Drupal 8's Dynamic Page Cache

# Answer
> 0 votes
As far as I understand, Internal Page Cache serves the same content for all anonymous users. So if you want to serve different content per anon user (maybe a shopping cart, session or location related data etc.) you should disable Internal Page Cache.

# Answer
> 0 votes
Yes they work hand in hand together.

Internal page cache will handle anonymous users, while dynamic page cache will handle all user types.

The only difference is that internal page cache will return a full page with no further rendering needed, dynamic page cache on the other hand will return a "full" page, but some parts of it are just place holders that will still need rendering before the response is sent.

The place holdered content are mostly for varying user related content. The place holders make it possible to cache the content in spite of the variation.

https://bryanmanalo.com/how-drupal-caches-work-under-hood

---
Tags: 8, caching
---


# Question
Title: Enum class not found when trying to use it in settings.php
I defined an enum in a custom module:

```
namespace Drupal\my_module\Enum;

enum BuildType: string {
  case Apple = 'apple_build';
  case Orange = 'orange_build';
}

```

And I want to use it in settings.php to change the config directory of the site:

**settings.php**:

```
$build_type = BuildType::from(getenv('build_type'));

$settings['config_sync_directory'] = dirname(DRUPAL_ROOT) . '/config/base_' . $build_type->value;

$settings['custom_translations_directory'] = dirname(DRUPAL_ROOT) . '/translations/' . $build_type->value;

```

However, when I do this, I get a namespace error:

`Error: Class "Drupal\my_module\Enum\BuildType" not found in /var/www/html/web/sites/default/settings.custom.php on line 14 #0 /var/www/html/web/sites/default/settings.php(32): include()`

How can I correctly namespace my enum for use in settings.php?

# Answer
> 2 votes
The *settings.php* file is loaded from `DrupalKernel::initializeSettings()`, which is called from `DrupalKernel::handle()` before `DrupalKernel::boot()`.

See the code in `Settings::initialize()`, called by `DrupalKernel::initializeSettings()`.

```
if (is_readable($app_root . '/' . $site_path . '/settings.php')) {
  require $app_root . '/' . $site_path . '/settings.php';
}

```

This means that when the code in *settings.php* is executed, the dependency injection container hasn't yet initialized, the services aren't yet available, and modules are not loaded. Classes/interfaces/traits defined from contributed/custom modules are not yet available either.

Since the *settings.php* file does not have access to classes/interfaces a module defines, it should load the file containing the class/interface definition directly or define the class/interface itself. Since the *settings.php* file is loaded with `require`, the code to load the class file or declaring the class should be wrapped in an `if` statement.

```
if (!class_exists('BuildType')) {
  // Load the class file or declare the class.
}

```

# Answer
> 0 votes
Here's the final code based on apaderno's answer:

**settings.php**:

```
if (!class_exists('BuildType') {
  enum BuildType: string {
    case Apple = 'apple_build';
    case Orange = 'orange_build';
  }
}

$build_type = BuildType::from(getenv('build_type'));

$settings['config_sync_directory'] = dirname(DRUPAL_ROOT) . '/config/base_' . $build_type->value;

$settings['custom_translations_directory'] = dirname(DRUPAL_ROOT) . '/translations/' . $build_type->value;

```

---
Tags: configuration, 10
---


title: Report of coupon and users

text:
# Question
Title: Report of coupon and users
I have users who are partners and users who are clients. When clients submit an order, they use a custom coupon code associated with each partner. (Each partner has a *Mycodes* field set within their profile.)

Previously, at the end of the month, we would download the sales into an Excel sheet and calculate the commissions of each partner using the partner's coupon codes.

Now I want to do this on the website using a view. I created a view for the coupons but I cannot compare the coupon code against the partner's *Mycodes* field. I have written the sql query in phpMyAdmin (one line with two JOIN), but I can not put that into views and filter that based on current userID:

```
SELECT
  uc_order_line_items.order_id AS OrderID,
  uc_orders.order_status AS Currently,
  uc_orders.created AS ThisDate,
  uc_orders.delivery_first_name AS Name,
  uc_orders.delivery_last_name AS Surname,
  uc_orders.delivery_phone AS Phone,
  uc_orders.primary_email AS Email,
  field_data_field_mycodes.entity_id AS UserID,
  uc_orders.order_total AS Total
FROM
  uc_order_line_items
JOIN
  field_data_field_mycodes
ON
  uc_order_line_items.title = field_data_field_mycodes.field_mycodes_value
JOIN
  uc_orders
ON
  uc_orders.order_id = uc_order_line_items.order_id
WHERE
  field_data_field_mycodes.entity_id=

```

# Answer
> 0 votes
Thanks to Chris I tried that with 3 different base tables, but none worked. This might not be the answer but it is for the people who might read this article as an option. After spending more than 2 days, I decided to go with the craziest approach yet "doable": I created a login table in the database, wrote one login page and one report page in PHP (less than 650 lines of codes with all those sort and filter), and I was done in about 5 hours. Link to that login went into Drupal, and that was it. Drupal is a very great tool but I guess Views needs to add a free-hand SQL query, and, also a free-hand javascript insertion per page. these could really save programmers a lot saving hours of work...

---
Tags: 7, views, ubercart
---


# Question
Title: Theming webform element label template for entity checkboxes field
In the webform, I use the Entity checkboxes component, which allows me to display the options I need using Views, depending on the node to which the webform is linked. But I lack flexibility in terms of setting up the output theme of these fields. In debugging mode, I saw that the markup I needed was inserted in the template "form\_element\_label.html.twig". **How do I override this template for a webform with a specific name and only for a specific field?**

I asked this question to ChatGPT, but her solution doesn't work. However, the general logic is correct. Create a new function in theme's .theme file:

```
function MYTHEME_theme_suggestions_webform_element_label_alter(array &$suggestions, array $variables) {
  $element = $variables['element'];
  if (isset($element['#webform_id']) && isset($element['#key'])) {
    $suggestions[] = 'webform_element_label__' . $element['#webform_id'] . '__' . $element['#key'];
  }
}

```

Create a new template file in theme's templates folder: webform-element-label--WEBFORMID--ELEMENTKEY.html.twig

Drupal doesn't see this pattern. Where do I make a mistake?

I see the finished result like this: for the form I need, I redefine the label template of the field I need, in which I insert the HTML markup I need. Overriding the views template does not allow me to do this, but I was able to display the viewing mode of the type of material I needed. Now the only thing I need is to hide it in the accordion element so that I get information when I click on the link.

# Answer
> 1 votes
You should set twig.config: debug: true in your services.yml which will allow you to see the current suggestions.

You should see your suggestions, however with Drupal even if you do and you passed the suggestion with a '-' not '\_', it'll tell you it's there but it won't actually pick up the template.

So make sure you convert the - to \_.

```
$suggestion = 'webform_element_label__' . $element['#webform_id'] . '__' . $element['#key'];
$suggestion = str_replace('-', '_', $suggestion);
$suggestions[] = $suggestion;

```

With twig debug on, it'll actually tell you the theme hook you need.

e.g. `<!-- THEME HOOK: 'breadcrumb' -->`

function mytheme\_theme\_suggestions\_breadcrumb\_alter(array &$suggestions, array $variables) {

# Answer
> 0 votes
My mistake was that I inattentively studied the features of the work of this component of forms. It is impossible to insert your markup there, because it is filtered. My approach with the output of the teaser material is correct. You just need to take into account that links and other html tags will be deleted there, respectively, you can forget about the pop-up window.

---
Tags: webforms, 9
---


# Question
Title: Remove search form from search result page in Drupal 8
What's the best way to remove the search form from the search result page in Drupal 8?

# Answer
There is not much you can customize in core search. So you probably need to override Drupal\search\Controller\SearchController::view and remove this line:

```
  $build['search_form'] = $this->formBuilder()->getForm(SearchPageForm::class, $entity);

```

Put your extended class into the route `search.view_node_search` in a RouteSubscriber.

But I don't think it's worth the effort. You can either simply hide the form in CSS or if you want a fully customizable search solution use Search API.
> 0 votes

# Answer
I had the same question for Drupal 9 and first I hid it with css, then I found it can be disabled in /admin/config/search/pages/manage/node\_search

Uncheck: Display basic search Display advanced search
> 0 votes

# Answer
I'm not sure if is the best way, but you can remove it from your theme preprocess, just for that page: `/**
 * Implements hook_preprocess_search_api_page()
 */
function YOURTHEME_preprocess_search_api_page(&$vars) {
 unset($vars['form']);
}`
> -1 votes

---
Tags: theming, 8, search
---


# Question
Title: Why does this Twig code not perform math operations as expected?
I have a registration form set up for athletes; I'm a volunteer coach. The form contains 5 slots to register up to 5 children at a time. There's also a donation field. Everything works fine unless the donation value goes over 999. I tried to use `number_format` in every way possible to grab the donation value and format it properly, but it still keeps adding a 1 when the number is higher than 1000.

>

This is the Twig code I am using.

```
{% apply spaceless %}
  {% set dv = (data.donation_value)|number_format(2)%}
  {% set cart_total = (data.child_registration_01_add)|number_format(0) + (data.child_registration_02_add)|number_format(0) + (data.child_registration_03_add)|number_format(0) + (data.child_registration_04_add)|number_format(0) + (data.child_registration_05_add)|number_format(0) %}

  {% set cart_1 = (data.child_registration_01_one)|number_format(2) + (dv)|number_format(2) %}

  {% set cart_2 = (data.child_registration_01_one)|number_format(2) + (data.child_registration_02_one)|number_format(2) + (dv)|number_format(2) %}

  {% set cart_3 = (data.child_registration_01_one)|number_format(2) + (data.child_registration_02_one)|number_format(2) + (data.child_registration_03_one)|number_format(2) + (dv)|number_format(2) %}

  {% set cart_4 = (data.child_registration_01_one)|number_format(2) + (data.child_registration_02_one)|number_format(2) + (data.child_registration_03_one)|number_format(2) + (data.child_registration_04_one)|number_format(2) + (dv)|number_format(2) %}

  {% set cart_5 = (data.child_registration_01_one)|number_format(2) + (data.child_registration_02_one)|number_format(2) + (data.child_registration_03_one)|number_format(2) + (data.child_registration_04_one)|number_format(2) + (data.child_registration_05_one)|number_format(2) + (dv)|number_format(2) %}

  {% if (cart_total)|number_format(0) == "1" %}
    {{ (cart_1)|number_format(2, '.', ',') }}
  {% elseif (cart_total)|number_format(0) == "2" %}
    {{ (cart_2)|number_format(2, '.', ',') }}
  {% elseif (cart_total)|number_format(0) == "3" %}
    {{ (cart_3)|number_format(2, '.', ',') }}
  {% elseif (cart_total)|number_format(0) == "4" %}
    {{ (cart_4)|number_format(2, '.', ',') }}
  {% elseif (cart_total)|number_format(0) == "5" %}
    {{ (cart_5)|number_format(2, '.', ',') }}
  {% else %}
    <p> 0.00 </p>
  {% endif %}
{% endapply %}

```

What am I doing wrong?

# Answer
> 2 votes
Use `number_format(2, '.', '')` to remove commas so you can perform math operations.

---
Tags: webforms
---


# Question
Title: How can I use EntityForm ::save() in a custom module?
How can i call public function ContactFormEditForm::save. My goal is refer to return value, do something like email, custom logged message, etc.

Refer to api."Return value int Either SAVED\_NEW or SAVED\_UPDATED, depending on the operation performed."

Un myCustom.module file how to do: if contact Form == specific Form, and if the form submitted. $value = $form-\>save():

how do custom module know when user submitted ? hook for entity Form saved ? Must use Event ? i check some docs, but for dispatched to entity Form save(). same question, how Event know the form saved ?

pls give some direction, my concept is not clear.

thks

# Answer
> 0 votes
This is a submission handler. Use a form alter hook and inspect the existing #submit array, you probably see the ::save() method already registered:

```
$form['actions']['submit']['#submit']

```

*How do custom module know when user submitted?*

Add your own submit handler to this array. See Add a custom submission handler to a form

---
Tags: forms, 9
---


# Question
Title: Local task for content node doesn't show up and raises 'Access denied'
After spending two days trying to figure this out, it's probably better to ask for help.

I need to add a custom tab next to `View Edit Delete Revisions Translate` for content nodes (a local task, if I understand the terminology correctly). This tab is supposed to open a form where the user can select from a choice of tasks to perform on the current node (e.g. generating a summary of the text with A.I.).

I have already successfully added another tab that opens a View (/admin/content/query/%). It works fine:

MODULE\_NAME.routing.yml

```
# This works fine
MODULE_NAME.manage_content:
  path: '/admin/content/query/{node}'
  requirements:
    _role: 'administrator, content_editor'
  options:
    parameters:
      node:
        type: 'entity:node'

```

MODULE\_NAME.link.tasks.yml

```
# This works fine
MODULE_NAME.manage_content:
  route_name: 'MODULE_NAME.manage_content'
  title: 'Manage'
  base_route: entity.node.canonical
  weight: 200

```

I just can't get it to work for the new tab (it doesn't even show up), which is supposed to open a Form:

MODULE\_NAME.routing.yml

```
# This won't work no matter what
MODULE_NAME.node_options:
  path: '/node/{node}/options'
  defaults:
    _form: '\Drupal\MODULE_NAME\Form\ConfirmOptionsForm'
  requirements:
    _role: 'administrator, content_editor'
  options:
    parameters:
      node:
        type: 'entity:node'

```

MODULE\_NAME.link.tasks.yml

```
# This won't work no matter what
MODULE_NAME.node_options:
  route_name: 'MODULE_NAME.node_options'
  title: 'Options'
  base_route: entity.node.canonical
  weight: 210

```

`ConfirmOptionsForm` is a subclass of `ConfirmFormBase`.

When I call `/node/1234/options` manually with a web browser, Drupal shows an 'Access denied' error (You are not authorized to access this page). This suggests the path is somehow off limits, but how? Trying other paths didn't help.

What am I missing?

# Answer
> 2 votes
One thing to note is that with `_role: 'administrator,content_editor'` the route is accessible to users who have both the roles, not either one or the other role.

As described in Structure of routes, you can separate the single roles an accounts needs to have to access the route with a + sign. In your case, instead of `_role: 'administrator,content_editor'`, you would use `_role: 'administrator+content_editor'`. That would make the route accessible to users who have either the *administrator* or the *content editor* role.

However, in Drupal, it is preferred to use permissions instead of roles. It allows better flexibility because the permission can be added to more roles without changing the route definition.

This is the first step I would go with.

---
Tags: forms, routes, 10
---


# Question
Title: Data is not saved on the entity when the source and destination field names are the same but have different types
I'm migrating from Drupal 7 to Drupal 9.

On the source Drupal 7 user entity there is a Text (list) field with various values. These need to be migrated to a `taxonomy_term` reference field on the Drupal 9 site, where the referenced terms have names corresponding to the values provided in the D7 source.

I'm using `entity_lookup` to link the Text (list) values to entities on the D9 site, and this works fine, **but only if the source D7 and destination D9 field names are different**.

So, on the Drupal 7 site and the Drupal 9 site when both fields have the same name. Let's say the name is `field_organisations`. I'm using the following in my process plugin:

```
process:
  field_organisations:
    -
      plugin: sub_process
      source: field_organisations
      process:
        target_id:
          plugin: entity_lookup
          entity_type: taxonomy_term
          bundle_key: vid
          bundle: organisations
          value_key: name
          source: value

```

Regardless of what I do, after migration, none of the `field_organisations` data have been migrated.

However, if I change the name of the destination field so that it does not match the source field, like this:

```
process:
  field_organisations_new:
    -
      plugin: sub_process
      source: field_organisations
      process:
        target_id:
          plugin: entity_lookup
          entity_type: taxonomy_term
          bundle_key: vid
          bundle: organisations
          value_key: name
          source: value

```

... then it works fine - even though the only difference is that the field name has been changed.

It's as if Drupal is erroneously trying to overwrite the D9 term reference field with the D7 list (text) data because the field names are the same, and ignoring my explicit process configuration.

But I've seen no documentation to say this is expected and don't know how to stop it from happening.

# Answer
I have been given the solution for this via the Drupal Slack channel (thankyou, https://www.drupal.org/u/mikelutz and https://www.drupal.org/u/osab).

The problem was that my migration was using the wrong class.

My migration .yml file contained:

```
class: Drupal\user\Plugin\migrate\User

```

Changing this to:

```
class: Drupal\migrate\Plugin\Migration

```

Fixed the problem.

### Explanation

The core `d7_user` migration uses `Drupal\user\Plugin\migrate\User` specifically to populate the user fields dynamically from a D7 source.

When writing a custom migration, we need to use the standard `Drupal\migrate\Plugin\Migration` class as we are defining the process and don’t need or want to have it overwritten.

Migration `.yml`s are plugin definitions. Plugin definitions take a `class` key to determine which plugin class to pass the configuration to.

For custom migrations, that should almost always be `\Drupal\migrate\Plugin\Migration` unless we are providing our own class for custom advanced handling.

Some core migrations do use other classes for the migration plugin, usually to dynamically add processes, as they were all written for the core upgrade UI, which needs to dynamically insert processes for detected D7 fields.

It is important if we are writing custom migration plugin definitions to use the correct plugin class for our use case.

`\Drupal\migrate\Plugin\Migration` is the base class, that basically says run the processes as defined in the `.yml` with no modification.
> 1 votes

---
Tags: 9, migrations
---


# Question
Title: How to pass node argument to a local task form?
Suppose I have a route for a local task like this:

```
MODULE_NAME.node_options:
  path: '/node/{node}/options'
  defaults:
    _form: '\Drupal\MODULE_NAME\Form\NodeOptionsForm'
    _title: 'Options'
  requirements:
    _entity_access: 'node.update'
    node: \d+
  options:
    parameters:
      node:
        type: 'entity:node'

```

`NodeOptionsForm` shall present 2-3 radio buttons to the user to select a service to perform on the node, e.g. create a summary of the body using A.I.

a) Which base class should I use for the form?

b) How is the {node} argument actually passed to the form instance? Or in other words, how must the form instance be created in order to have access to the node?

# Answer
You can use the NodeInterface class in your buildForm like below

```
<?php

namespace Drupal\MODULE_NAME\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\node\NodeInterface;

/**
 * @internal
 */
class NodeOptionsForm extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'make_special_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, NodeInterface $node = NULL) {
    // Node object will be in $node and you can perform your logic in this function.
    $form['#title'] = $node->label();
    $form['#node'] = $node;
    return $form;
  }

```

a) Which base class should I use for the form? =\> **FormBase class will be used for all basic forms unless it a config form.**

b) How is the {node} argument actually passed to the form instance? Or in other words, how must the form instance be created in order to have access to the node? =\> **You can pass it as NodeInterface $node in buildForm.**
> 1 votes

# Answer
Routes for local tasks do not have different requirements, compared to routes that are not used for local tasks, apart from being added in the *.links.task.yml* file for the module.

For example, the *Book* module define the following local task.

```
entity.node.book_outline_form:
  route_name: entity.node.book_outline_form
  base_route: entity.node.canonical
  title: Outline
  weight: 2

```

The route is defined by these lines.

```
entity.node.book_outline_form:
  path: '/node/{node}/outline'
  defaults:
    _entity_form: 'node.book_outline'
    _title: 'Outline'
  requirements:
    _permission: 'administer book outlines'
    _entity_access: 'node.view'
    node: \d+
  options:
    _node_operation_route: TRUE

```

In this case, the form is defined with `_entity_form`. It could have used `_form` too; in that case, the `_form` value is the name (namespace included) of a class that implements `FormInterface`, which is implemented by the `FormBase`, a base class module can extend for their forms.
Other base classes that can be used for forms are `ConfigFormBase`, for configuration forms, `ConfirmFormBase`, for confirmation forms, or `ImageEffectFormBase`, for an image effect settings.

Any route parameters are passed to the `buildForm()` method any class that implements `FormInterface` needs to implement.

The alternative is doing like the Book module does, adding a new form class using `hook_entity_build()` and using `_entity_form` in the route definition.

```
function book_entity_type_build(array &$entity_types) {
  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
  $entity_types['node']->setFormClass('book_outline', 'Drupal\\book\\Form\\BookOutlineForm')
    ->setLinkTemplate('book-outline-form', '/node/{node}/outline')
    ->setLinkTemplate('book-remove-form', '/node/{node}/outline/remove')
    ->addConstraint('BookOutline', []);
}

```

In this case, the edited entity is passed in `$this->entity` to the methods of the entity form class.
> 0 votes

---
Tags: forms, routes, 10
---


# Question
Title: How can I properly create separate storage for a base field?
What is the correct and supported way to create a separate table storage for a base field on a custom entity? I tried the answer here, using `setCustomStorage(TRUE)`, but it didn't work, and I don't think that I need to actually create custom storage, I just wanted a separate table in the database for the field.

I was able to get a separate storage table with `BundleFieldDefinition::create('address')` but I was not sure if it is ok to create a bundle field within the `baseFieldDefinitions`?

From what I understand, the `BundleFieldDefinition` class just extends the base field class, and returns `FALSE` on `isBaseField()`.

The snippet below works fine, but is this a supported way of doing it?

```
/**
 * {@inheritdoc}
 */
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
  $fields = parent::baseFieldDefinitions($entity_type);
  $fields['shipping_address'] = BundleFieldDefinition::create('address')
    ->setLabel(t('Shipping Address'))
    ->setDescription(t('The shipping address.'))
    ->setCardinality(1)
    ->setSetting('field_overrides', [AddressField::ADDITIONAL_NAME => ['override' => FieldOverride::HIDDEN]])
    ->setDisplayOptions('form', [
      'type' => 'address_default',
      'weight' => 4,
    ])
    ->setDisplayConfigurable('form', TRUE)
    ->setDisplayConfigurable('view', TRUE);

   return $fields;
}

```

# Answer
> 0 votes
To store the field data in a separate database table, you need to override `ContentEntityBase::bundleFieldDefinitions()`, which is the method for adding bundle fields or overriding base fields. That does not allow to decide the database table name, but only to avoid using a shared database table that otherwise Drupal would use.

For an entity that depends from the *Entity API* module, Defining bundle fields in code shows how to define bundle fields for an entity. In particular, it shows how to define the storage for the added bundle fields.

Supposing that the entity class is `MyEntity` and that the machine name of the module that implements that class is *mymodule*, the code to use in your case would be the following one.

```
/**
 * Entity class.
 */
class MyEntity /* extends … */ {

  /**
   * Class properties and other methods
   */

  /**
   * {@inheritdoc}
   */
  public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
    if ($bundle == 'mybundle') {
      $fields = parent::bundleFieldDefinitions($entity_type, $bundle, array $base_field_definitions);
      $fields['shipping_address'] = BundleFieldDefinition::create('address')
        ->setLabel(t('Shipping Address'))
        ->setDescription(t('The shipping address.'))
        ->setCardinality(1)
        ->setSetting('field_overrides', [AddressField::ADDITIONAL_NAME => ['override' => FieldOverride::HIDDEN]])
        ->setDisplayOptions('form', ['type' => 'address_default', 'weight' => 4])
        ->setDisplayConfigurable('form', TRUE)
        ->setDisplayConfigurable('view', TRUE);

      return $fields;
    }
  }

  /**
   * Other methods
   */

}

```

```
/**
 * mymodule.module
 */

/**
 * Implements hook_entity_field_storage_info().
 */
function mymodule_entity_field_storage_info(EntityTypeInterface $entity_type) {
  if ($entity_type->id() == 'myentity') {
    return MyEntity::bundleFieldDefinitions($entity_type, 'mybundle', []);
  }
}

```

---
Tags: entities, 9
---