# Question
Title: can we change block title using template_preprocess_block?
I am having a need to dynamically change the title of a block. Here is what I am trying but no avail.

```
function MYMODULE_preprocess_block(&$variables) {

  if ($variables['elements']['#id'] == "views_block__weekly_schedule_all_blocks_block_2") {

    //$variables['elements']['content']['#title']['#markup'] = "Foobar";

    //$variables['elements']['content']['#title'] = 'foibar';
  }
}

```

Any help is appreciated.

# Answer
See the `block_example.module`. It's `hook_block_view_alter` you can use to do this programmatically. You can probably use it in a `*.theme` as well.

Source `block_example_block_view_alter`.

```
use Drupal\Core\Block\BlockPluginInterface;

function MYMODULE_block_view_alter(array &$build, BlockPluginInterface $block) {

  // We'll search for the string 'uppercase'.
  $definition = $block
    ->getPluginDefinition();
  if (!empty($build['#configuration']['label']) && mb_strpos($build['#configuration']['label'], 'uppercase') || !empty($definition['subject']) && mb_strpos($definition['subject'], 'uppercase')) {

    // This will uppercase the block title.
    $build['#configuration']['label'] = mb_strtoupper($build['#configuration']['label']);
  }
}

```

---

Most often you find answers to questions like that really fast when you google for *Drupal X how to X programmatically* or similar.
> 3 votes

# Answer
`$variables['label'] = 'My label';`

Source: https://api.drupal.org/api/drupal/core%21modules%21block%21block.module/function/template\_preprocess\_block/8.2.x
> 0 votes

---
Tags: views, 8, hooks
---


title: Add comments to Webform submissions

text:
# Question
Title: Add comments to Webform submissions
I'm trying to figure out allow commenting on the submissions so there can be a back and forth dialog between the user and site admin(s).

In Drupal 8 webform submissions are entities (type: webform\_submission) and comments are a field.

I have created a new Comment Type (webform\_submission\_comment) with the "Target entity type" set to webform\_submission).

How do I attach a comment field to the webform\_submission entity?

# Answer
> 3 votes
Webform submissions are content entities without Field API enabled. Comments can only be attached to fieldable entities. Webform submission data is not stored Field API, but your use case is a very reasonable example of why Field API could/should be enabled. The challenge is the UX for supporting fields, and webform elements at the same time could be overwhelming. I am not prepared to support this the core Webform module. A dedicated webform\_comment.module could be created to enable Field API and might even only support for adding comments to submissions.

---

You are going to have use hook\_entity\_type\_alter() to add 'field\_ui\_base\_route' to the WebformSubmission entity.

> If your content entity is fieldable, provide 'field\_ui\_base\_route' annotation, giving the name of the route that the Manage Fields, Manage Display, and Manage Form Display pages from the Field UI module will be attached to. This is usually the bundle settings edit page, or an entity type settings page if there are no bundles.

-- https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21entity.api.php/8.2.x

# Answer
> 0 votes
I have got this working rather easily by doing the following:

1. Implement the following hook in my custom module and clear the cache:

/\**

* Implements hook\_entity\_type\_alter().
*
* @param array $entity\_types
* @return void \*/ function mymodule\_entity\_type\_alter(array &$entity\_types) { $entity\_types\['webform\_submission'\]-\>fieldable = TRUE; $entity\_types\['webform\_submission'\]-\>set('field\_ui\_base\_route', 'entity.webform.edit\_form'); }

2. With Comment module enabled, go to administer comment types: admin/structure/comment and add a comment type that targets webform submissions.
3. Go to webform administration page: admin/structure/webform and click on the Operations dropdown for the webform you wish to add comments to. You should now find a Manage Fields link.
4. Click on Manage Fields and add a comment field of the type you just created.

# Answer
> 0 votes
As @NewZeal mentioned I create custom module with this code:

```
<?php

function MYMODULE_entity_type_alter(array &$entity_types) {
    $entity_types['webform_submission']->fieldable = TRUE;
    $entity_types['webform_submission']->set('field_ui_base_route', 'entity.webform.edit_form');
}

```

Now you can create fields for each webform but I if you go to `/admin/structure/webform/manage/MYFORM/form-display` i got this error:

```
The website encountered an unexpected error. Please try again later.
Error: Call to a member function getEntityTypeId() on null in Drupal\webform\Breadcrumb\WebformBreadcrumbBuilder->build() (line 159 of modules/webform/src/Breadcrumb/WebformBreadcrumbBuilder.php).

```

How can I solve it?

---
Tags: 8, webforms, comments
---


# Question
Title: How to put fields created with BaseFieldDefinition::create() within the advanced group on node edit pages?
I am wanting to create some fields for a few of my existing content types but not sure how to go about it. Currently I am creating fields like this

```
function HOOK_entity_base_field_info(EntityTypeInterface $entity_type) {
  if ($entity_type->id() === 'node') {
    $fields = [];

    $fields['layout_select'] = BaseFieldDefinition::create('list_string')
      ->setLabel(t('Layout selection'))
      ->setName('layout_select')
      ->setSetting('allowed_values', ['one' => 'one', 'two' => 'two'])
      ->setSetting('default_value', NULL)
      ->setDisplayOptions('form', [
        'type' => 'options_select',
        'weight' => 0
      ]);

    return $fields;
  }
}

```

The problem is, when I set the display options for the form here, they are shown in the main area of the page with the rest of the fields but I want them to be shown in a "details" element in the "#advanced" group on the right side of the edit page like some others are.

Currently, my work around is to define a details element and then just create a form element that corresponds to the field I created with BaseFieldDefinition::create(), like this

```
function HOOK_form_node_form_alter(&$form, FormStateInterface $form_state) {
  $node = $form_state->getFormObject()->getEntity();

  $form['test'] = [
    '#type' => 'details',
    '#title' => t('Test Element'),
    '#group' => 'advanced',
    '#weight' => 99
  ];

  $form['test']['layout_select'] = [
    '#type' => 'select',
    '#title' => 'Layout Selection',
    '#options' => [
      'one' => 'One',
      'two' => 'Two',
    ],
    '#default_value' => $node->layout_select->value ?? NULL
  ];
}

```

I can't imagine this is the correct way to implement this but I haven't done this before and am not sure how to do it correctly.

# Answer
> 1 votes
You are doing the correct way to register field and add grouping via form. The grouping is form's scope. You cannot add it from field definition (which is child element of form) One modification, to avoid duplication in your work around(almost there, you are going right)

```
function HOOK_form_node_form_alter(&$form, FormStateInterface $form_state) {
  $node = $form_state->getFormObject()->getEntity();
  $form['layout_select']['#group'] = 'advanced';
  $form['layout_select']['#default_value'] = $node->layout_select->value ?? NULL;
}

```

---
Tags: nodes, forms, hooks
---


# Question
Title: Is it good practice to call a form inside a controller?
I have a list which needs to be displayed and filtered and sorted using filters and sort drop-down. I also need to add a pagination. I also have a map integrated to the page which will change based on the results.

Is it advisable to directly use the *\_form* parameter in routing.yml file and attach to a `FormBase` or create a controller and call the form within the controller?

# Answer
The `_form` parameter is converted to a `_controller` parameter pointing at a core form controller. So technically it doesn't matter whether you use the core controller or a custom controller. If you use a custom controller you probably want to return not only the form but also additional content. Then place the entire form array as a sub-key in the controller render array without rendering it.
> 7 votes

# Answer
You could use a controller to show a form via the *form\_builder* service. That's what Drupal core does too, but only to show a form inside a page that contains more than the form, for example in the `SystemController` class and its `SystemController::themesPage()`.

```
  $build = [];
  $build[] = [
    '#theme' => 'system_themes_page',
    '#theme_groups' => $theme_groups,
    '#theme_group_titles' => $theme_group_titles,
  ];
  $build[] = $this->formBuilder
    ->getForm('Drupal\\system\\Form\\ThemeAdminForm', $admin_theme_options);
  return $build;

```

Routes showing a single form, whose class is set with the *\_form* property, are really using a controller (`HtmlFormController`) Drupal sets for them, which just builds the form with the *form\_builder* service.
Instead of implementing a controller to render a single form with the same service, and use it for a route used in my module, I would rather set the form to show with *\_form* and let the Drupal controller render the form.
> 1 votes

---
Tags: forms, 9
---


title: Error: on cron (field_purge_batch)

text:
# Question
Title: Error: on cron (field_purge_batch)
Seems that Drupal got issues removing deleted fields on cron (just a theory).

Got the following error message after cron ran. Anybody got an idea how to get rid of it?

```
Warning: foreach() argument must be of type array|object, bool given in field_purge_batch() (line 96 of /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/modules/field/field.purge.inc)
#0 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/includes/bootstrap.inc(347): _drupal_error_handler_real(2, 'foreach() argum...', '/Users/captainEvil', 96)
#1 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/modules/field/field.purge.inc(96): _drupal_error_handler(2, 'foreach() argum...', '/Users/captainEvil', 96)
#2 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/modules/field/field.module(169): field_purge_batch(50)
#3 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/Cron.php(249): field_cron()
#4 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(405): Drupal\Core\Cron->Drupal\Core\{closure}(Object(Closure), 'field')
#5 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/Cron.php(257): Drupal\Core\Extension\ModuleHandler->invokeAllWith('cron', Object(Closure))
#6 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/Cron.php(136): Drupal\Core\Cron->invokeCronHandlers()
#7 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/ProxyClass/Cron.php(75): Drupal\Core\Cron->run()
#8 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/modules/system/src/CronController.php(59): Drupal\Core\ProxyClass\Cron->run()
#9 [internal function]: Drupal\system\CronController->runManually()
#10 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#11 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/Render/Renderer.php(564): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#12 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#13 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
#14 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/vendor/symfony/http-kernel/HttpKernel.php(158): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#15 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/vendor/symfony/http-kernel/HttpKernel.php(80): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1)
#16 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/modules/contrib/simple_oauth/src/HttpMiddleware/BasicAuthSwap.php(67): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#17 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/StackMiddleware/Session.php(58): Drupal\simple_oauth\HttpMiddleware\BasicAuthSwap->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#18 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#19 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#20 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#21 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/vendor/asm89/stack-cors/src/Asm89/Stack/Cors.php(49): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#22 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Asm89\Stack\Cors->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#23 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#24 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#25 /Users/captainEvil/WORK/WORKSPACE/valet/bq/bq-be/web/core/lib/Drupal/Core/DrupalKernel.php(709): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#26 /Users/captainEvil/WORK/WORKSPACE/valet/BQ/bq-be/web/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#27 /Users/captainEvil/.composer/vendor/weprovide/valet-plus/server.php(131): require('/Users/captainEvil')
#28 {main}

```

# Answer
The warning is caused by the database value `field.storage.deleted` (collection `state`) in the table `key_value`.

If there are no fields to delete it should contain a serialized empty array:

```
a:0:{}

```

An empty value is also OK, but it must not contain a boolean as placeholder for an empty array.
> 1 votes

---
Tags: cron, 9, entities
---


# Question
Title: How can I display a larger image when clicking on a thumbnail for an image field?
Many of the answers are related to Drupal 7, but I'm asking for Drupal 8/9. I have an image field and currently display it as a 100x100 thumbnail. I want to link it to a larger image or make it into a slideshow. From the display layout, I am able to select content, but it goes to the page itself. And if I select media, it tries to goto the media/edit page of that image. How can I link it to a larger version of the image or make it into a slideshow?

# Answer
> 1 votes
Use the Colorbox contrib module.

Here is a good tutorial of it.

---
Tags: 9, media
---


# Question
Title: How can I ensure my_custom_module.install runs my_custom_module_update_8101()?
I have a custom module in Drupal 8.9.3. `hook_schema()` runs and creates the module table. I would like to run a `hook_update_N()` implementation to change the auto increment to start at a specific number, but it doesn't appear to run.

```
function my_custom_module_update_8101() {
  $sql = 'alter table {my_custom_table}  AUTO_INCREMENT = 100000000000;';
  Database::getConnection()->exec($sql);
}

```

I heard there's a table where I can see my custom module is installed, and what version of the schema it's on, but I am unable to locate these tables. And the tables I do find appear the value is blob format so I cannot read it easily. Any ideas what I'm doing incorrectly?

# Answer
> 3 votes
Update hooks are there to get the module into a known good state - the same state as when the module gets installed. It's for when you need to make changes to an already installed module, I'm not sure there's a scenario where it would make sense to include an update hook in a new module.

As leymannx mentioned in the comments, `hook_install()` is the best place for your code. It's invoked after the schema is installed, so you'll be able to make your changes there.

# Answer
> 2 votes
In the code shown in the question, `Database::getConnection()->exec($sql)` will cause an error, since the object returned by `Database::getConnection()` (a `Connection` object) doesn't have any `exec()` method.
If then the file containing the `my_custom_module_update_8101` function doesn't include a `use Drupal\Core\Database\Database;` line, PHP will throw an error about a not found class.

Hooks implemented by Drupal core modules use `\Drupal::database()` to query the database.
To execute a generic SQL query, you should use `\Drupal::database()->query()`, for example in `hook_install()`, for the reasons given after.

```
Drupal::database()->query('ALTER TABLE {my_custom_table} AUTO_INCREMENT = 100000000000;');

```

If you installed the module and edited its .install file to add that hook, it doesn't work because Drupal caches the list of hooks implemented by modules and it won't notice a new hook is added until a new module is installed or an existing module is uninstalled.

If you installed a module that already implements `my_custom_module_update_8101()`, that hook won't be invoked because the module is installed, not updated. `hook_update_N()` is for modules that are updated.
When a module is installed, Drupal records the higher number used from an update hook; it will execute the update hook with a number that is higher than that, when the module is updated. This means that, installing a module that already implements `my_custom_module_update_8101()`, Drupal will never invoke that hook, even when the module is later updated.

The only hook that is invoked when a module is installed is `hook_install()`. That is the hook you should use.
Keep in mind that, if the module is already installed, you need to uninstall it and re-install it, to make Drupal run its installation hook.

---
Tags: hooks
---


# Question
Title: Trying to implement bundle classes for a custom content type
I've got a custom content type (generated by drush) that extends ContentEntityBase and a bundle class (also generated by drush) that extends my content type. I've registered my bundle with hook\_entity\_bundle\_info() in my\_module.module, and the entity type bundle service shows my bundle belonging to my content type:

```
    >>> $bundleInfo = \Drupal::service('entity_type.bundle.info')
=> Drupal\Core\Entity\EntityTypeBundleInfo {#1475
     +"_serviceId": "entity_type.bundle.info",
   }

>>> $bundles = $bundleInfo->getBundleInfo('my_content_type')
=> [
     "my_content_type" => [],
     "dc_thing" => [
       "label" => Drupal\Core\StringTranslation\TranslatableMarkup {#5566},
       "class" => "Drupal\my_module\Entity\Bundle\DcThing",
     ],
   ]

```

But when I try creating an entity using my dc\_thing bundle, Drupal complains that my content type is missing a bundle

```
 >>> $etm = \Drupal::service('entity_type.manager')
=> Drupal\Core\Entity\EntityTypeManager {#996
     +"_serviceId": "entity_type.manager",
   }

>>> $thing = $etm->getStorage('my_content_type')->create(['type' => 'dc_thing', 'label' => 'Particle Mang'])
Drupal\Core\Entity\EntityStorageException with message 'Missing bundle for entity type my_content_type'

```

All of the example code I've been able to find for bundle classes extend Node, but as far as I'm aware, the only bundles for Node in core are for Article and Basic Page, I don't see where there's a bundle defined for the Node entity type.

```
>>> $article = $etm->getStorage('node')->create(['type' => 'article', 'label' => 'test article'])

```

works just fine.

# Answer
My problem was in my create params and content entity annotation.

In my entity\_keys annotation, I had `"bundle" = "bundle",`

Changing `'type' => 'dc_thing'` to `'bundle' => 'dc_thing'` got me unstuck. Then changing my annotation to `"bundle" = "type",` got things working as expected (passing my bundle as `type` in my create statement.

Big ups to John Pitcairn on d.o.
> 0 votes

---
Tags: entities
---


# Question
Title: How to add a theme suggestion to the textfield input based on the name of the view?
I am using the following hook in a custom module:

```
MY_MODULE_theme_suggestions_input_alter(&$suggestions, array $variables) {

  $suggestions[] = 'input_'. $element['#type']. '__'. 'form_id__' $element ['#form_id']. '__'. $element['#name'];
}

```

With which I get something similar ***(In my case I have an exposed filter using search api)***:

```
input-textfield-form-id-views-exposed-form-search-api-fulltext.html.twig

```

How can I get the suggestion in the following way?

```
input-textfiel--viewName--search-api-fulltext.html.twig

```

Where `viewName` is the name of the `view` from which the field is exported.

How can I access the view information from this hook?

# Answer
If the View is displayed as a page, you can get the View ID from the current route parameters:

```
$view_id = \Drupal::routeMatch()->getParameter('view_id');
if ($view_id) {
  $suggestions[] = 'input_'. $element['#type']. '__'. $view_id . '__'. $element['#name'];
}

```

If it's a block, I can't think of a nice way to do it generically. One non-nice way would be to alter the form, and add a property to each element which can then be picked up in the suggestions hook.

Something like this:

```
function MODULE_form_views_exposed_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  // You could check that the current display is a block here too if you need to
  $view_id = $form_state->getStorage()['view']->id();
  _MODULE_add_view_id_to_input_elements($form, $view_id);
}

function _MODULE_add_view_id_to_input_elements(array &$root_element, $view_id) {
  $input_types = ['textfield', 'submit', '...'];

  if (in_array($root_element['#type'], $input_types)) {
    $root_element['#MODULE_view_id'] = $view_id;
  }

  foreach (\Drupal\Core\Render\Element::children($root_element) as $key) {
    _MODULE_add_view_id_to_input_elements($root_element[$key], $view_id);
  }
}

```

And then in the suggestions hook:

```
if (isset($element['#MODULE_view_id'])) {
  $suggestions[] = 'input_'. $element['#type'] . '__' . $element['#MODULE_view_id'] . '__'. $element['#name'];
}

```

This isn't particularly pleasant, but the exposed form elements themselves don't carry any context so you have to wedge it in there somehow I guess. Hopefully there's a cleaner method out there somewhere.
> 2 votes

# Answer
Thanks to Clive answer, this would be rather :

```
function MYMODULE_theme_suggestions_input_alter(&$suggestions, array $variables) {
  $view_id = \Drupal::routeMatch()->getParameter('view_id');
  if ($view_id) {
    $suggestions[] = 'input_'. $variables['element']['#type']. '__'. $view_id . '__'. $variables['element']['#name'];
  }
}

```
> 0 votes

---
Tags: views, 8, theming
---


# Question
Title: Drupal Commerce Freezes on "Pay and Complete Purchase"
I have two products on my Drupal (9.4.2) Commerce site. I can complete the checkout process for one of the products, and the order shows up in the view at /admin/commerce/orders. The other one, however, gets hung up after I click the "Pay and Complete Purchase" button. After a while, the screen goes white and there's no error message at all. Nothing shows up in the log file, either. The payment gateway (Stripe) does show the payment going through, but there is no record of the order on my site. I can't figure out what the difference is between the two products that would cause this behavior. They are virtually the same, the only difference being the name of the products. In fact, I deleted the problem product and then replaced it by duplicating the product that works. Unfortunately, the problem remains.

The output of the console during the checkout process for both products is the same:

```
Loading failed for the <script> with source “https://www.googletagmanager.com/gtag/js?id=UA-68402666-1”. 23785:17:1
Layout was forced before the page was fully loaded. If stylesheets are not yet loaded this may cause a flash of unstyled content. modernizr.min.js:3:5914

Cookie “SSESS881388a882e9883aafd6264d030b0353” does not have a proper “SameSite” attribute value. Soon, cookies without the “SameSite” attribute or with an invalid value will be treated as “Lax”. This means that the cookie will no longer be sent in third-party contexts. If your application depends on this cookie being available in such contexts, please add the “SameSite=None“ attribute to it. To know more about the “SameSite“ attribute, read https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/SameSite 23785

Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user’s experience. For more help http://xhr.spec.whatwg.org/ jquery.min.js:2:81867

Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”). moz-extension:71:797851
Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”). moz-extension:71:797851

Partitioned cookie or storage access was provided to “https://m.stripe.network/inner.html#url=https%3A%2F%2Fnew.classicalstudies.org%2Fcheckout%2F8715%2Forder_information&title=Checkout%20%7C%20Society%20for%20Classical%20Studies%20Test&referrer=https%3A%2F%2Fnew.classicalstudies.org%2Fcart&muid=4b05ae8f-a19e-4a6b-a213-2174d88e5d99451e13&sid=NA&version=6&preview=false” because it is loaded in the third-party context and dynamic state partitioning is enabled.

```

I can't figure out why one can be processed but the other can't.

# Answer
> 1 votes
My problem was caused by an improperly configured license expiration field on the product variation. I discovered this by adding the following to the site's index.php (web/index.php):

```
ini_set('display_errors',1);
error_reporting(E_ALL|E_STRICT);

```

On the white screen that would come up after the transaction timed out, the error reported was:

```
Fatal error: Maximum execution time of 120 seconds exceeded in /home/blistein/domains/new.classicalstudies.org/web/modules/contrib/recurring_period/src/Plugin/RecurringPeriod/FixedReferenceDateInterval.php on line 177

```

That led me to examine the license expiration field, and I found that it was set to a date prior to the date of the transaction. I changed the year to the next year and changed the interval field to "1 Years". After that, the transaction went through without issue.

I hope this helps someone.

---
Tags: commerce, 9
---


title: Rule triggers twice

text:
# Question
Title: Rule triggers twice
Simple rule to send account email after updating a commerce license.

Export

```
{ "rules_membership_activation_email_notification_v2" : {
    "LABEL" : "Membership activation email notification v2",
    "PLUGIN" : "reaction rule",
    "WEIGHT" : "-10",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules", "commerce_license" ],
    "ON" : { "commerce_license_update" : [] },
    "DO" : [
      { "user_send_account_email" : {
          "account" : [ "commerce-license:owner" ],
          "email_type" : "status_activated"
        }
      }
    ]
  }
}

```

Debug

```
Rules debug information:
" Reacting on event After updating an existing commerce license.

    0 ms Reacting on event After updating an existing commerce license.
    12.037 ms Evaluating conditions of rule Membership activation email notification v2. [edit]
    12.046 ms AND evaluated to TRUE.
    " Rule Membership activation email notification v2 fires. [edit]
        0 ms Rule Membership activation email notification v2 fires.
        0.207 ms Evaluating the action Send account e-mail. [edit]
        55.557 ms Rule Membership activation email notification v2 has fired.
    67.623 ms Finished reacting on event After updating an existing commerce license.

" Reacting on event After updating an existing commerce license.

    0 ms Reacting on event After updating an existing commerce license.
    0.111 ms Evaluating conditions of rule Membership activation email notification v2. [edit]
    0.122 ms AND evaluated to TRUE.
    " Rule Membership activation email notification v2 fires. [edit]
        0 ms Rule Membership activation email notification v2 fires.
        0.113 ms Evaluating the action Send account e-mail. [edit]
        28.104 ms Rule Membership activation email notification v2 has fired.
    28.243 ms Finished reacting on event After updating an existing commerce license.

```

As you can see it triggers twice and sends two duplicate emails, should send one.

Tried with other random actions, they all trigger twice.

Got another rule that sends email on new license creation after checkout and it is not duplicate, it only triggers once as it should.

# Answer
Issue was solved with this https://www.drupal.org/project/commerce\_license/issues/2205923#comment-8525711

> This works just like for any other entity type, you check that commerce-license:status is not equal to commerce-license:original:status (confirming that it has just changed), and then in the next condition you check that commerce-license:status is expired.

Except 'original' now is 'unchanged'.

Don't know how or why, but it works.
> 0 votes

---
Tags: 7, commerce, rules
---


# Question
Title: Delete a custom field from node_field_data table
A custom module added a field to the `node_field_data` table. Deleting the field in a hook update like this:

```
function HOOK_update_N() {
  Database::getConnection()->schema()->dropField('node_field_data', 'my_field');
}

```

deletes the field, but as soon as configuration is imported a `Column not found: 1054 Unknown column` error is thrown.

```
[error]  Drupal\Core\Database\DatabaseExceptionWrapper: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'data.my_field' in 'field list':
SELECT "revision".*, "data"."my_field" AS "my_field"
FROM
"node_field_revision" "revision"
LEFT OUTER JOIN "node_field_data" "data" ON ("revision"."nid" = "data"."nid" AND "revision"."langcode" = "data"."langcode")
WHERE ("revision"."nid" IN (:db_condition_placeholder_0)) AND ("revision"."vid" IN (:db_condition_placeholder_1))
ORDER BY "revision"."nid" ASC; Array
(
    [:db_condition_placeholder_0] => 100000
    [:db_condition_placeholder_1] => 200000
)
 in Drupal\Core\Entity\Sql\SqlContentEntityStorage->loadFromSharedTables() (line 579 of /var/www/html/docroot/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).

```

Here’s the same query, only more readable.

```
SELECT revision.*, data.my_field AS my_field
    FROM node_field_revision revision
    LEFT OUTER JOIN node_field_data data ON (revision.nid = data.nid AND revision.langcode = data.langcode)
    WHERE (revision.nid IN (100000)) AND (revision.vid IN (200000))
    ORDER BY revision.nid;

```

So the config import is triggering some cleanup and `dropField()` on the database is **not** the way to go.

I seem to recall some other modules, maybe lingotek or workbench\_moderation, adding a field to the `node_field_data` table at one point. I wonder how they got their field out of the table if that was so?

The core content\_translation module adds field to the `node_field_data` table.

---

Yes, thanks, the database tables aren't directly accessed. I'm also uninstalling the module, so I'm using `hook_uninstall()` like this:

```
/**
 * Implements hook_uninstall().
 */
function my_module_uninstall() {
  $update_manager = \Drupal::entityDefinitionUpdateManager();
  $definition = $update_manager->getFieldStorageDefinition('my_field', 'node');
  $update_manager->uninstallFieldStorageDefinition($definition);
}

```

But when I run `drush -y pmu my_module`, I'm getting a

`[error] TypeError: Argument 1 passed to Drupal\Core\Entity\EntityDefinitionUpdateManager::uninstallFieldStorageDefinition() must implement interface Drupal\Core\Field\FieldStorageDefinitionInterface, null given,`

error.

---

Update: The error was because there was content in the field. We decided to do this in an update hook, not a `hook_uninstall` hook.

Here's that version of the code:

```
function my_module_update_N() {
  if (!\Drupal::database()->schema()->fieldExists('node_field_data', 'my_field')) {
    return;
  }

  // First, delete the content from the field.
  \Drupal::database()->query("UPDATE {node_field_data} SET my_field = NULL WHERE my_field IS NOT NULL");

  // Use the update manager to uninstall the field.
  $update_manager = \Drupal::entityDefinitionUpdateManager();
  $definition = $update_manager->getFieldStorageDefinition('my_field', 'node');
  $update_manager->uninstallFieldStorageDefinition($definition);
  $update_manager->updateEntityType($update_manager->getEntityType('node'));

  // Required because other hook updates and/or post-updates may run immediately after.
  drupal_flush_all_caches();
}

```

I add `updateEntityType()` and `drupal_flush_all_caches()` because of the next error. The next error was when the build got to the config:import step, it was throwing this error:

```
In ExceptionHandler.php line 53:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'my_field' in 'where clause': SELECT 1 AS "expression"
FROM
"node_field_data" "t"
WHERE "my_field" IS NOT NULL
LIMIT 1 OFFSET 0; Array
(
)

In StatementWrapper.php line 145:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'my_field' in 'where clause'

```

So then we tried the module installer service:

```
function my_module_update_N() {
  // Use module handler because it removes the my_module field from the node_field_data table.
  if (\Drupal::moduleHandler()->moduleExists('my_module')) {
    \Drupal::service('module_installer')->uninstall(['my_module']);
  }
}

```

Per the comment in the hook update, not only did the module handler delete the field in node\_field\_data, but it "alerted" other processes like config:import that the field was gone. The config is imported successfully, the build completes successfully, and the problem has been solved.

# Answer
> 2 votes
Basing on Updating Entities and Fields in Drupal 8, adding and deleting a entity field requires `\Drupal::entityDefinitionUpdateManager()`. (I changed the second code example to use the same field and entity name used in the first code example.)

A base field is added and removed using code similar to the following one.

```
$field_storage_definition = BaseFieldDefinition::create('boolean')
  ->setLabel(t('Revision translation affected'))
  ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
  ->setReadOnly(TRUE)
  ->setRevisionable(TRUE)
  ->setTranslatable(TRUE);

\Drupal::entityDefinitionUpdateManager()
  ->installFieldStorageDefinition('revision_translation_affected', 'block_content', 'block_content', $field_storage_definition);

```

```
$update_manager = \Drupal::entityDefinitionUpdateManager();
$definition = $update_manager->getFieldStorageDefinition('revision_translation_affected', 'block_content');
$update_manager->uninstallFieldStorageDefinition($definition);

```

The database tables aren't directly accessed. The update manager takes care of that.

---
Tags: database, 9
---


title: How do I execute PHP code in a view?

text:
# Question
Title: How do I execute PHP code in a view?
There are myriad applications to need to execute specific PHP functions in Views rows. In many cases, making a custom Plugin is a better option. In other cases, it's better to use a Twig or custom token input filter.

Yet there are unique, specific use cases in which I need to simply talk to custom functions and the database in ways that are outside of a plugin.

I've reviewed this guide - https://enzo.weknowinc.com/how-include-php-code-drupal-8-views/ \- but it did not work because Drupal console isn't functional for D9+, as it uses a later version of Symfony. All of the other resources I've found either 404 or cause errors due to being outdated.

Is there a way to accomplish the injection of PHP into views rows like D7?

# Answer
> 2 votes
In the current Drush version you can build plugins to run PHP in Views with the following commands:

Field:

```
drush gen plugin:views:field

```

Style rows:

```
drush gen plugin:views:style

```

The first example is a direct replacement for a PHP field in earlier Drupal versions. The second command produces a nice example of a configurable plugin including a views twig template and its preprocess hook.

---
Tags: views, plugins
---


# Question
Title: Why the view block under the search field was not rendered?
I created a block based on the view with machine name **search\_entity\_product\_block**:

Then I created a custom form with method `someMethod` which should render a block of the view below the search field:

```
class SearchFieldForm extends FormBase {

  public function getFormId() {
    return 'entity_product_admin_search_field';
  }

  public function someMethod($args) {

    $view = [
      '#type' => 'view',
      '#name' => 'search_entity_product',
      '#display_id' => 'search_entity_product_block',
      '#arguments' => $args,
      '#embed' => TRUE,
    ];

    return $view;
  }

  public function buildForm(array $form, FormStateInterface $form_state) {

    $form['search_field'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Search Product'),
    ];
    $form['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save'),
    ];

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    $args = $form_state->getValue('search_field');
    $this->someMethod($args);
  }

}

```

But the block didn't render.

# Answer
> 1 votes
The submit function needs only to request a form rebuild and then the form build method can place the View block under the search field:

```
class SearchFieldForm extends FormBase {

  public function getFormId() {
    return 'entity_product_admin_search_field';
  }

  public function someMethod($args) {

    $view = [
      '#type' => 'view',
      '#name' => 'search_entity_product',
      '#display_id' => 'search_entity_product_block',
      '#arguments' => $args,
      '#embed' => TRUE,
    ];

    return $view;
  }

  public function buildForm(array $form, FormStateInterface $form_state) {

    $form['search_field'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Search Product'),
    ];

    $args = $form_state->getValue('search_field');
    if ($args) {
      $form['result'] = $this->someMethod($args);
    }

    $form['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save'),
    ];

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    $form_state->setRebuild();
  }

}

```

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


# Question
Title: Multiple ajax form not working on whole site
I have multiple pages which contains multiple ajax forms. When I am working on a particular form, its ajax submission is working. But at that moment, if I go to second page form, ajax submission not working and the page gets reloaded.

But after clearing cache, if I work on second page form, its ajax submission working, but then first page ajax form submission not working.

How will I manage multiple ajax forms on multiple pages?

My ajax submission code looks like this:

```
$form['actions']['submit'] = array(
  '#type' => 'submit',
  '#value' => $this->t('Submit'),
  '#attributes' => array('class' => array('btn-red')),
  '#ajax' => [
    'callback' => '::submitCallBack',
    'progress' => array(
      'type' => 'throbber',
      'message' => 'Please wait...',
    ),
  ],
);

```

# Answer
After a lot of research I found that there is a confliction issue having same name of the submit button for all of the forms. So I changed the submit button name for each forms.

Now the ajax is working fine for all forms.

**Form 1 submit button:**

```
$form['form_one_submit'] = [
  '#type' => 'submit',
  '#value' => $this->t('Submit'),
  '#ajax' => [
    'callback' => '::callBackFunctionOne',
    'progress' => array(
      'type' => 'throbber',
      'message' => 'Just a moment...',
    ),
  ],
];

```

**Form 2 submit button:**

```
$form['form_two_submit'] = [
  '#type' => 'submit',
  '#value' => $this->t('Submit'),
  '#ajax' => [
    'callback' => '::callBackFunctionTwo',
    'progress' => array(
      'type' => 'throbber',
      'message' => 'Please wait...',
    ),
  ],
];

```
> 0 votes

---
Tags: forms, ajax
---


# Question
Title: How to add local Drush with Composer to a XAMPP Drupal on Windows?
I have installed Drupal 9 on XAMPP in Windows 11.

How could I add local Drush with Composer to a XAMPP Drupal on Windows?

# Answer
> 3 votes
From the Drush install webpage:

```
composer require drush/drush

```

---
Tags: drush, 9
---


# Question
Title: Sort nodes based on parent taxonomy term name in views
I have a taxonomy term "Store Locations". I have added terms as State & City by parent child concept. Like this:

I have created Store Locations as node and assign them in the taxonomy term like this:

Now I want to sort the nodes as per parent taxonomy term name.

For e.g: I have created the parent term "Bihar" first, then added "Andaman". So the term ID for Bihar is 6 and 7 for Andaman. So the sorting is showing Bihar at first and then Andaman.

I want to display them as alphabetical order of the parent term.

Currently the view is showing as per parent term id, not by name.

# Answer
I have added another relationship "Taxonomy Term" as Parent and in Sort Criteria added a filter "Taxonomy Term Name" in ascending order.
> 0 votes

---
Tags: 8, views, taxonomy-terms
---


# Question
Title: Where is the user documentation for the `attach_library()` function?
Where is the user documentation for `attach_library()`?

The function is described on this page, Libraries can now be attached from Twig templates via an attach\_library() function.

I'm trying to solve an issue where `attach_library()` doesn't work for anonymous users but yet it works for authenticated users. I'm not getting any replies there, so hoping to get a pointer to where the docs are to understand how the function works.

# Answer
That and various other ways are documented on Drupal.org.
> -1 votes

---
Tags: 9
---


# Question
Title: "The specified file temporary://fileXXXXXX could not be copied" warning
If i open my local website there is a indication like this.

> The specified file temporary://filel17IDM could not be copied, because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.

how to get out of this?

# Answer
> 2 votes
The temporary directory set under **Admin \> Configuration \> File System** is incorrect or does not have write permissions. Typically for local dev (on Linux/OSX machines) this path can simply be `/tmp`. On Windows, I believe it is `C:\temp`.

See: Configuring the temporary directory

# Answer
> 7 votes
> The specified file temporary://filel17IDM could not be copied, because the **destination directory** is not properly configured.

The problem is with the destination directory, not the temporary directory (which defaults to `/tmp` on Linux systems).

`/tmp` typically looks like this:

```
ls -la /tmp
drwxrwxrwt 13 root root 4096 Feb 19 09:52 .

```

Which means that any user can write to the directory.

Check the permissions of your `files/` directory, and any directories it contains. They should be writable by the webserver.

Also check that the destination **folder** exists and has the correct permissions, for example `files/translations/` may not exist and you'll get the error message mentioned above.

# Answer
> 4 votes
For me, I didn't have a folder called `translations` in the `files` folder typically stored in `sites/[site_path]/files`.

Creating a `translations` folder at `sites/default/files/translations` fixed it for me.

---
Tags: files
---


# Question
Title: not sure the properly way to call an entity
Hi sorry for the question but im new and im starting to undertand abou entities but is still hard for me. IM not sure about how to call the entities.

Here i didnt have a problem tu get the number.

```
$price= \Drupal::entityTypeManager()->getStorage('commerce_order_item')->load($id)->get('unit_price')->getValue()[0]['number'];

```

But here i dont undertand why i could not take a percentage y try to many combinations. Maybe some one can show me the proper way to write this.

```
  $product_tax= \Drupal::entityTypeManager()->getStorage('commerce_order')->load($id)->get('adjustments')[0][0]->get('value')->getvalue()['percentage'];

```

Debug:

```
^ Drupal\commerce_order\Entity\OrderItem {#3230 ▼
  #values: array:16 [▼
    "order_item_id" => array:1 [▶]
    "type" => array:1 [▶]
    "uuid" => array:1 [▶]
    "order_id" => array:1 [▶]
    "purchased_entity" => array:1 [▶]
    "title" => array:1 [▶]
    "quantity" => array:1 [▶]
    "unit_price" => array:1 [▼
      "x-default" => array:2 [▼
        "number" => "151.250000"
        "currency_code" => "EUR"
      ]
    ]
    "overridden_unit_price" => array:1 [▶]
    "total_price" => array:1 [▶]
    "uses_legacy_adjustments" => array:1 [▶]
    "data" => array:1 [▶]
    "created" => array:1 [▶]
    "changed" => array:1 [▶]
    "locked" => array:1 [▶]
    "adjustments" => array:1 [▼
      "x-default" => array:1 [▼
        0 => array:1 [▼
          "value" => Drupal\commerce_order\Adjustment {#3231 ▼
            #type: "tax"
            #label: "IVA Incluido"
            #amount: Drupal\commerce_price\Price {#3233 ▶}
            #percentage: "0.21"
            #sourceId: "europeo|es|standard"
            #included: true
            #locked: false
          }
        ]
      ]
    ]
  ]

```

# Answer
The *unit\_price* field has two properties: *number* and *currency\_code*. This means you could use both the following lines.

```
$price = \Drupal::entityTypeManager()->getStorage('commerce_order_item')->load($id)->get('unit_price')->getValue()[0]['number'];
$currency = \Drupal::entityTypeManager()->getStorage('commerce_order_item')->load($id)->get('unit_price')->getValue()[0]['currency_code'];

```

The *adjustments* field has only the dafault property, *value*. It means you can only use the following code.

```
$value = \Drupal::entityTypeManager()->getStorage('commerce_order_item')->load($id)->get('unit_price')->getValue();

```

`$value` should be an array containing the *#percentage* index. That value should be available in `$value[0]['#percentage']`. Debugging as you did, you could see what exactly `$value` contains.
> 2 votes

# Answer
Finally I understand how to get the values from arrays. This is the solution:

```
$percentage = \Drupal::entityTypeManager()->getStorage('commerce_order_item')->load($id)->getAdjustments()[0]->getPercentage();

```
> 0 votes

---
Tags: entities, 9
---


# Question
Title: How do you update a module's required library dependency in its composer.json file to a new version?
I'm trying to make a patch for a contrib module so that it will use a new version of one it's "required" vendor libraries.

The composer.json is in the module's directory and looks like this:

```
"require": {
        "wa72/htmlpagedom": "1.3",
        "drupal/pdf_api": "^2.0"
    },

```

I need "wa72/htmlpagedom:^3" to be installed so I changed the version number in the module's composer.json file

Running composer update drupal/MODULE\_NAME does nothing.

If I try "composer require "wa72/htmlpagedom:^3" -w" I get error/problems reports that the module is still locked at the original version (1.3).

I've tried deleting the composer.lock file and clearing Composer cache but nothing that I've tried has allowed me to install the updated version of htmlpagedom.

```
  Problem 1
    - Root composer.json requires wa72/htmlpagedom ^3, found wa72/htmlpagedom[dev-master, v3.0.0, 3.0.x-dev] but these were not loaded, likely because it conflicts with another require.
  Problem 2
    - drupal/printable is locked to version 2.1.3 and an update of this package was not requested.
    - drupal/printable 2.1.3 requires wa72/htmlpagedom ^1.3 -> found wa72/htmlpagedom[v1.3.0, ..., 1.x-dev] but it conflicts with your root composer.json require (^3).

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.

```

Screenshot of composer output:

# Answer
> 3 votes
Simple answer: You can't. Composer patching happens **after** calculating and downloading all dependencies.

2 possible workarounds:

* Fork the contrib module and require your forked custom module.
* Require the new version in your root project and alias it as the old version as demanded by the contrib module: `composer require wa72/htmlpagedom:X.Y.Z as 1.3`

And TBH, none of the above is a good idea :-) Better create a merge request for the contrib module in the official repository and fix it properly.

---
Tags: composer
---


# Question
Title: How to check in a custom constraint validator whether a field allows for multiple values or not
In my custom validator plugin I want to be able to tell whether the field value given was part of a field that allowed for more than 1 value.

For example

```
  public function validate($items, Constraint $constraint) {
    if(<if field is a multivalue field>){
       $count = $items->count();
    } else {
       $count = $items->value;
    }

```

However I'm not sure how to tell whether a field allowed for multiple values in this function.

I tried the getSettings() function but there didn't seem to be an allowed values setting displayed in the result.

How would I get the number of allowed values in a field?

# Answer
> 1 votes
Yes, this is the cardinality of the field. This is not a field setting, though, this is a field storage definition:

```
$cardinality = $items->getFieldDefinition()->getFieldStorageDefinition()->getCardinality();

```

---
Tags: 9, plugins
---


# Question
Title: Templates aren't called in custom module?
I am trying to add templates for the paragraph in a custom module, but it uses only the *paragraph.html.twig* template file.

*paragraph--example-ch-hero-panel.html.twig* is one of the suggested template files, which is the one I am using.

By default, The template should be taken from the paragraph, but it doesn't work in my case. I didn't implement `hook_theme()` in a module for this because I am not passing any value to the templates.

I tried the following code, but I got an error.

```
function example_ch_hero_panel_theme() {
  return [
    'paragraph__example_ch_hero_panel' => [
      'render element' => 'element',
      'template' => 'paragraph--example-ch-hero-panel',
      'base hook' => 'paragraph',
    ],
  ];
}

function example_ch_hero_panel_theme_registry_alter(&$theme_registry) {
  $theme_registry['page']['path'] = drupal_get_path('module', 'example_ch_hero_panel') . '/templates';
}

```

It throws the following exception.

> Twig\Error\LoaderError: Template "modules/custom/example\_ch\_hero\_panel/templates/page.html.twig" is not defined. in Twig\Loader\ChainLoader-\>getCacheKey()

Can anyone tell me how to fix this issue?

# Answer
Your problem is coming from this code:

```
$theme_registry['page']['path'] = drupal_get_path('module', 'example_ch_hero_panel') . '/templates';

```

The first array key, `page`, means you are working the `page` template. You've told the system to look for `page.html.twig` in your module's `/templates` directory. It's not finding it, so you get that error.

Remove that hook altogether, it's not the right way to do what you are trying to do.
> 1 votes

# Answer
The following code is taken from a module that creates an accordion from a paragraph. (The module name has been changed.)

The *paragraph--accordion.html.twig* template file exists in mymodule/templates/paragraph.

```
function mymodule_theme($existing, $type, $theme, $path) {
  $themes['paragraph__accordion'] = array(
    'template' => 'paragraph--accordion',
    'base hook' => 'paragraph',
    'path' => \Drupal::service('extension.list.module')->getPath('mymodule') . '/templates/paragraph'
  );

  return $themes;
}

```
> 0 votes

---
Tags: 8
---


title: Pass Term object to theme

text:
# Question
Title: Pass Term object to theme
In my controller, I have a function that gets a taxonomy term. If I pass the term name to my theme function (`$current_type = $term->name;`), that works.

```
$roots = $this->termStorage->loadTree(ProductsController::PRIMARY_CATEGORIES, 0, 1, FALSE);
$current_type = null;
foreach ($roots as $term){
  if($this->urlSafeTerm($term->name) == $category){
    // $current_type = $term->name;
    $current_type = Term::load($term->tid);
    break;
  }
}

$build = [
  '#theme' => 'product_category',
  '#type' => $current_type,
  ],
];

return $build;

```

In my hook\_theme function:

```
'product_category' => [
  'template' => 'products/category',
  'variables' => [
    'type' => NULL,
],

```

But if I try to load the term object (`$current_type = Term::load($term->tid);`) and pass that, I gives me:

```
TypeError: Illegal offset type in Drupal\Core\Render\ElementInfoManager->getInfo() (line 79 of /app/web/core/lib/Drupal/Core/Render/ElementInfoManager.php)

```

Is it not possible to pass a Term entity like this or is there something else I'm missing and/or doing wrong?

Thanks!

# Answer
> 2 votes
In a render array, *#type* is already a property used by Drupal, which cannot be used for other purposes from a theme hook. It's the machine name of the type of render/form element.
For example, in the following code, *#type* is what allows Drupal to understand that the first item is a detail element and the second one is a text field.

```
$form['author'] = array(
  '#type' => 'details',
  '#title' => >t('Author'),
);
$form['author']['name'] = array(
  '#type' => 'textfield',
  '#title' => t('Name'),
);

```

When Drupal finds *#type* in a render array, it will ask to the element plugin manager information about the element plugin to use. (See `ElementInfoManager::getInfo()`.) With the wrong value, it throws the exception you are seeing.

The solution is replacing *type* with a string that isn't already used by Drupal. Render API overview (where the purpose of *#type* and *#theme* is explained) and the documentation for `RenderElement` show a list of properties already used by Drupal.
For example, replacing *type* with *term\_id* should fix that error.

---
Tags: 9
---


# Question
Title: Prevent validation constraint from triggering when 'add more' button is clicked
I have a custom validation constraint plugin that prevents submission if an entity reference field has an odd number of values. The validation triggers upon submission just fine

```
  public function validate($items, Constraint $constraint) {
    $cardinality = $items->getFieldDefinition()->get('fieldStorage')->get('cardinality');
    $count = $cardinality == 1 ? $items->getValue()[0]['value'] : $items->count();
    if (is_string($constraint->divisibleBy)) {
      switch ($constraint->divisibleBy) {
        case 'odd':
          if ($count % 2 == 0) {
            $this->context->buildViolation($constraint->notDivisible)
              ->setParameter('%field_name', $items->getFieldDefinition()->label())
              ->setParameter('%divisibleBy', $constraint->divisibleBy)
              ->addViolation();
          }
          break;

        case 'even':
          if ($count % 2 != 0) {
            $this->context->buildViolation($constraint->notDivisible)
              ->setParameter('%field_name', $items->getFieldDefinition()->label())
              ->setParameter('%divisibleBy', $constraint->divisibleBy)
              ->addViolation();
          }
          break;
      }
    }

```

and in my custom paragraph class

```
  public static function alterFieldInfo(array &$fields): void {
    if (isset($fields['field_nodes'])) {
      $fields['field_nodes']->addConstraint('items_count_divisible', ['divisible_by' => 'even']);
    }
    if (isset($fields['field_maximum_items'])) {
      $fields['field_maximum_items']->addConstraint('items_count_divisible', ['divisible_by' => 'even']);
    }
  }

```

However there's one major problem. When clicking 'Add more' to one of my fields it triggers the validation and stops the 'Add more' button from adding another field.

The number of values needs to be even to succeed validation but the form does not let me add more than one value because one value is odd and fails the validation.

Is there a way to prevent the validation from occurring if it's an ajax call rebuilding the form and not an actual form submission?

# Answer
I was able to resolve this by setting the #limit\_validation\_errors property on the button to an empty array

Like so:

```
public static function alterFormElement(array &$element, FormStateInterface $form_state, array $context): void {
    $element['subform']['field_nodes']['widget']['add_more']['#limit_validation_errors'] = [];
}

```
> 1 votes

---
Tags: forms, 9, plugins
---


# Question
Title: Views skip contextual filter IF current user is Administrator
I have a View that has a contextual filter that uses a token to get entity reference values on the current user to limit a view (that also points at the same reference type). If they match up, that is all the View will return in its results.

However, for Administrator roles, I do not want to apply the filter (bypass it) without duplicating the view and having different views to maintain. I tried adding the first argument of "Authored by" using the current user, and checking the role of that user in the validation. This appeared to work at first, but when a node is authored by a lower level user, the validation appears to not work (no result shows). If I change the author to another user, the node appears in the View results for that lower level user.

Without having to duplicate a View, how can I grant Administrators full access but apply the second contextual filter otherwise?

# Answer
> 0 votes
Based on a similar question I saw, I had to add this:

```
function mymodule_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  try {
    $account = \Drupal::currentUser();
    // If user is not admin, remove the authored by argument
    if ($view->id() === 'portal' && $view->current_display == 'page_2' && !in_array('administrator', $account->getRoles())) {
      unset($query->where[0]["conditions"][0]);
      $query->where[0]["conditions"] = array_values($query->where[0]["conditions"]);
    }
  }
  catch(Error $e) {
    \Drupal::messenger()->addError('The server encountered a problem. Please contact the site\'s administrator.');
    \Drupal::logger('mymodule')->error("Error displaying Rate Manager: %e",
      ['%e' => $e]
    );
    return;
  }
}

```

This seems to support both cases, but now there is a code and argument position dependency that is not obvious from the UI. I wonder if there is a better solution?

---
Tags: views, 9
---


# Question
Title: Custom Field Formatters applied to multiple values vs individual? AKA wrap multiple values in a parent template
I’m writing a module that has a custom Field (cruises) and Field Formatter (Cruise Calendar). I have the backend squared away and have assigned “Unlimited” related cruises to my node. My goal is to display all the details of the related cruises as well as a single Cruise Calendar on each page with a single formatter. I’ve got a twig template working for each individual item displaying the details of each cruise, but I’m stuck as to how to best create the wrapper/calendar element in a twig template. The wrapper needs to be passed a simple list of which dates should be highlighted on the calendar.

At first I thought I could do this by creating a nested Render Array in my viewElements funtion, but the more I dig I don’t think that’s true. Overwriting viewElements in FormatterBase really only effects the individual elements right? How best can I create a custom template wrapper for my field formatter?

Here’s my sample code, when I thought I could return a nested Render Array. But of course if I return $wrapper my child elements don’t appear.

```

class FareHarborCalendar extends FormatterBase {

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = [];
    $all_cruise_dates = [];
    foreach ($items as $delta => $fh_cruise) {
        $local_cruise = FareharborCruises::load($fh_cruise->target_id);
        $availabilities = FareharborAvailabilities::getByTypeDate($fh_cruise->target_id);
        foreach($availabilities as $departure){
          $date_parts = explode("T", $departure->start);
          $all_cruise_dates[] = $date_parts[0];
        }
        $elements[$delta] = [
            '#theme' => 'fareharbor_cruise_details',
            '#cruise_id' => $fh_cruise->target_id,
            '#name' => $local_cruise->name->value,
            '#booking_notes' => $local_cruise->booking_notes->value,
            '#headline' => $local_cruise->headline->value,
            '#details' => $local_cruise,
            '#availabilities' => $availabilities,
        ];
    };
    $elements['#attached']['library'][] = 'fareharbor/fareharbor';

    $wrapper = [
      '#theme' => 'fareharbor_calendar',
      '#name' => "some fixed name",
      '#all_dates' => $all_cruise_dates,
      'child_details' => $elements,
    ];
    return $elements;
  }

}

```

My hook\_theme in .module file

```

/**
 * Implements hook_theme().
 */
function fareharbor_theme() {
  $vars['cruise_id'] = NULL;
  $vars['name'] = NULL;
  $vars['booking_notes'] = NULL;
  $vars['headline'] = NULL;
  $vars['details'] = NULL;
  $vars['availabilities'] = NULL;

  $theme['fareharbor_cruise_details'] = [
    'template' => 'fareharbor_cruise_details',
    'variables' => $vars,
  ];

  $cal_vars['name'] = NULL;
  $cal_vars['child_details'] = $theme['fareharbor_cruise_details'];
  $theme['fareharbor_calendar'] = [
    'template' => 'fareharbor_calendar',
    'variables' => $cal_vars,
  ];

  return $theme;

}

```

and a Dump of available values in fareharbor\_calendar.html.twig

```
^ array:14 [▼
  "name" => "some fixed name"
  "child_details" => array:2 [▼
    "template" => "fareharbor_cruise_details"
    "variables" => array:6 [▼
      "cruise_id" => null
      "name" => null
      "booking_notes" => null
      "headline" => null
      "details" => null
      "availabilities" => null
    ]
  ]
  "theme_hook_original" => "fareharbor_calendar"
  "attributes" => Drupal\Core\Template\Attribute {#4854 ▶}
  "title_attributes" => Drupal\Core\Template\Attribute {#4847 ▶}
  "content_attributes" => Drupal\Core\Template\Attribute {#4851 ▶}
  "title_prefix" => []
  "title_suffix" => []
  "db_is_active" => true
  "is_admin" => true
  "logged_in" => true
  "user" => Drupal\Core\Session\AccountProxy {#2996 ▶}
  "directory" => "themes/custom/flagship"
  "theme_hook_suggestions" => []
]

```

Any hints as to how to best go about this and have a better understanding of how it's supposed to work would be greatly appreciated.

thanks,

summer

# Answer
viewElements() has to return *a renderable array for $items, as an array of child elements keyed by consecutive numeric indexes starting from 0*, according to the formatter interface.

If you want to provide a different field wrapper you would need to override view(), but I wouldn't recommend to replace standard field theming with your own. Instead call the parent view() method and you can add additional variables if the render array contains the field template.

Extend the field template for your field type:

```
/**
 * Implements hook_theme().
 */
function mymodule_theme() {
  return [
    'field__myfieldtype' => [
      'base hook' => 'field',
    ],
  ];
}

```

Then your field module can provide a default `field--myfieldtype.html.twig` in its /templates folder and preprocess it in

```
function mymodule_preprocess_field__myfieldtype(&$variables) {
  // preprocess $variables
}

```
> 1 votes

---
Tags: 9
---


# Question
Title: How to correctly re-write static call to the OOP way?
1. Calling static function **entityQuery()**:

> `$query = \Drupal::entityQuery('node')->condition('type','article')->execute();`

2. Calling static function **loadMultiple()**:

> `$nodes = Node::loadMultiple($nids);`

Thanks!

# Answer
> 1 votes
It depends from where the code is executed. In a function that doesn't have the dependency injection as one of its parameters, the only way to use the dependency injection container is via the `\Drupal` class.
This means that, for example in a hook implementation, `\Drupal::entityQuery()` will be always called. When loading nodes, you could use either `Node::loadMultiple()` or the following code, which essentially is a simplified version of the code used by `EntityBase::loadMultiple()`.

```
$entity_type_manager = \Drupal::entityTypeManager();
$storage = $entity_type_manager->getStorage('node');
$nodes = $storage->loadMultiple($nids);

```

In a static method that doesn't that doesn't have the dependency injection as one of its parameters, the only use the dependency injection container is via the `\Drupal` class. For example, this is done in Drupal core with `ContentEntityBase::create()`.

```
public static function create(array $values = []) {
  $entity_type_repository = \Drupal::service('entity_type.repository');
  $entity_type_manager = \Drupal::entityTypeManager();
  $class_name = static::class;
  $storage = $entity_type_manager->getStorage($entity_type_repository
    ->getEntityTypeFromClass($class_name));

  if ($storage instanceof BundleEntityStorageInterface && ($bundle = $storage->getBundleFromClass($class_name))) {
    $values[$storage->getEntityType()->getKey('bundle')] = $bundle;
  }
  return $storage->create($values);
}

```

In code I wrote, I would verify the method is effectively called statically; if it's not, I would rewrite the code to use the dependency injection container, when possible.

In services, their dependencies will be passed to the classes that implement the service, so the code would become the following one, where `$this->entityTypeManager` is the property set from the class constructor, which contains the entity type manager.

```
$query = $this->entityTypeManager->getStorage('node')->getQuery();

```

```
$storage = $this->entityTypeManager->getStorage('node');
$nodes = $storage->loadMultiple($nids);

```

The same is done from classes that implement `ContainerInjectionInterface` (or other interfaces like `ContainerFactoryPluginInterface` for plugins). The difference is that their dependencies aren't defined in a file like services, but injected from their `create()` method.

As for calling a static method, there isn't anything wrong in that. In OOP there are classes with only static methods, which can only be called statically. (It's non possible to do differently, since those classes aren't used to create objects.)
What Symfony/Drupal suggest is to always use dependency injection when possible. That doesn't mean classes with all static methods cannot be implemented; in fact, Drupal has classes like `Crypt`, which is never instantiated with `new Crypt()`. (It wouldn't make sense, since it only has static methods.)

# Answer
> 0 votes
Dependency injection is a fairly big topic, but basically you should inject the relevant services into your class and then call the methods on them.

In drush php you can do something like:

```
$storage = $container->get('entity_type.manager')->getStorage('node');
$nodes = $storage->loadMultiple($nids);

```

---
Tags: 9
---


# Question
Title: Easy way to add Functional or Kernel tests to a View?
I have an administrative View that has a couple access checks based on current user. I would like to add an automated test to the view.

Since I only need to check the result count (no specific field) based on whats set in a users profile, how can I test this view?

Fields I will normally scaffold in setUp() using FieldConfig class, is there a similar one for Views?

These run in CI (I don't know how DTT works in this regard) and the View is apt to change, copying a YAML file into a module can often be forgot (and carry many dependencies with it).

# Answer
I wound up using Drupal Test Traits.

The only thing left for me to do is obtain a copy of the database to run the tests in CI, which I can use Drush to grab.
> 0 votes

---
Tags: 9, testing
---


title: Can I add fields to bundle classes?

text:
# Question
Title: Can I add fields to bundle classes?
The docs I've found so far tell how to add bundle-specific fields in either hook\_entity\_bundle\_field\_info() or in bundleFieldDefinitions() in my content entity class. While those work it seems cumbersome since they put all bundle field definitions in the same place. Since bundle classes extend a content entity class, it seems like it would be a lot cleaner to define additional fields in the bundle class they belong to.

Is that possible?

I've tried both implementing bundleFieldDefinitions() and overriding baseFieldDefinitions() in my bundle class, but it appears they never get called there.

# Answer
I was able to do this by implementing bundleFieldDefinitions in both my content entity class and my bundle class. The bundle class defines its fields, then the entity class bundleFieldDefinitions() determines the bundle and calls the appropriate bundle class bundleFieldDefinitions()
> 1 votes

---
Tags: entities
---


# Question
Title: Implement node access checks for a node when content moderation is in use
I want to hook into hook\_node\_access and if the action is update or delete on a particular node type, I want to check the current user and the current node and see if they share field values. If they do, that user should have access to edit or delete the node even if they are not the node owner.

With Content Moderation enabled, the $op passed to hook\_node\_access is always 'view all revisions' even on the Edit or Delete page. Why? How can I implement this?

# Answer
Here is what I came up with so far... I am not sure if this is bulletproof. The $op seems to change depending where you are (or maybe who you are) - for example the Content overview the $op is 'view all revisions' for an administrator. In a View listing nodes with operation links, the op is 'update', 'view', 'delete'. I'm unsure when the $op is one thing versus another, but I have:

```
/**
 * Implements hook_node_access().
 */
function mymodule_node_access(NodeInterface $node, $op, $account) {
  $type = $node->bundle();
  $route = \Drupal::routeMatch()->getRouteName();

  if ($type != 'offer_detail_page') {
    return AccessResult::neutral();
  }

  $op_check = [
    'update',
    'delete',
  ];

  $route_check = [
    'entity.node.edit_form',
    'entity.node.delete_form',
  ];

  if (!in_array($route, $route_check) && !in_array($op, $op_check)) {
    return AccessResult::neutral();
  }

  // Jump out if user is admin
  $admin_roles = [
    'administrator',
    'content_publisher',
    'supplier_author'
  ];

  $user_roles = $account->getRoles();

  foreach ($user_roles as $rid) {
    if (in_array($rid, $admin_roles)) {
      return AccessResult::neutral();
    }
  }

  // Get full account
  $account = User::load($account->id());
  $user_suppliers = array_column($account->get('field_suppliers')->getValue(), 'target_id');
  $node_suppliers = array_column($node->get('field_supplier')->getValue(), 'target_id');
  $user_has_suppliers_with_node = array_intersect($user_suppliers, $node_suppliers);
  return AccessResult::allowedIf(!empty($user_has_suppliers_with_node))->cachePerUser()->addCacheableDependency($node);
}

```

This appears to grant edit/delete access to related users at a glance. Is this enough? Am I missing something?

Edit: you also need to enable permission per Content Moderation transition state they should have access to. If they have no transition state access, they will never get the edit button, even if you grant it in code.
> 0 votes

---
Tags: 9
---


# Question
Title: Preprocess function for targeting the home page
What's the preprocess function for targeting the home page in a Drupal 8 site? Can I use a preprocess function that is called only for the home page?

# Answer
> 6 votes
To target the front page in a preprocess function you need a condition, because for preprocess you can't use name suggestions:

```
function mytheme_preprocess_page(&$variables) {
  if ($variables['is_front']) {
    // your code
  }
}

```

# Answer
> 1 votes
What you call home page, for Drupal is the front page. The suggestion given by `system_theme_suggestions_page()`, an implementation of `hook_theme_suggestion_HOOK()` from the System module, is page\__front; similarly, `system_theme_suggestions_html()` suggests html\__front. Both the suggestions are for the preprocess functions and the template files.

If by *home page* you mean a page that is not the front page, you need to write your own `hook_theme_suggestions_HOOK()` implementation that gives the right suggestion for that page. Keep in mind that the suggested template file is used only if it exists; otherwise, Drupal will use a different suggestion, or the default template file, if none of the suggested template files exist.

# Answer
> 0 votes
On today latest D9, you have:

```
 function THEMENAME_preprocess_html(&$variables) {
   if (\Drupal::service('path.matcher')->isFrontPage()) {
      // do something for your frontpage
   }
 }

```

---
Tags: theming, 8
---


# Question
Title: Can I debug Twig templates with Twig Xdebug and Apache Netbeans?
I am trying to debug Twig templates in Drupal 9, using WAMP, Apache Netbeans, and the *Twig Xdebug* module on Windows 7.

I have already set up NetBeans so I can debug PHP code in Drupal 9. They are working.
I run my Drupal 9 local test site in WAMP, using the following lines in the php.ini configuration file.

```
; XDEBUG Extension
[xdebug]
zend_extension="e:/wamp64/bin/php/php7.4.0/zend_ext/php_xdebug-2.8.0-7.4-vc15-x86_64.dll"
xdebug.remote_enable = On
xdebug.profiler_enable = off
xdebug.profiler_enable_trigger = Off
xdebug.profiler_output_name = cachegrind.out.%t.%p
xdebug.profiler_output_dir ="e:/wamp64/tmp"
xdebug.show_local_vars=0
xdebug.idekey = netbeans-xdebug
output_buffer = off
xdebug.remote_port = 9000

```

I have also enabled the Twig debugging in the *services.yml* file. I have added a `{{ breakpoint() }}` line in the *page.html.twig* file located in *templates* directory for the theme I am using. I also use Google Chrome with the *Xdebug helper* extension, which I set to *Debugging enabled* for the address of the local Drupal site (turned green) and its IDE key option to *netbeans-xdebug*.
Debugging PHP code works perfectly, as I mentioned previously, but I don't get any code break in the break-point line of the template file when I refresh the front page (I have also cleared the cache). In other words, I cannot debug Twig templates.

Is something missing or wrong in my procedure?

I am supposed to turn on the connection-listening in my IDE, but NetBeans has no such button. Since it works with PHP debugging, I guess it listens to connections.

I have followed the methodology described in the Twig Xdebug project page and on Debug Drupal 8 Twig Templates with the Twig\_Xdebug Module.

# Answer
> 2 votes
Enabling that flag in the YAML file is not enough to talk to xDebug, you also need the Twig XDebug module to bridge the gap:

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

Once that is installed, you can step through Twig templates with xdebug.

Noted from the docs: https://www.drupal.org/docs/theming-drupal/twig-in-drupal/debugging-twig-templates#s-viewing-variables

---
Tags: debugging
---


# Question
Title: Debugging hook_node_access in failing test
Related to this question, I have a functional test asserting that hook\_node\_access is doing what it should for different users.

While I can access edit and delete routes, I add an additional check for $node-\>access() and see what its result is:

```
$low_user->set('field_suppliers', $supplier->id());
$low_user->save();

// With the supplier set, now we should have access.
$this->drupalGet('/node/' . $offer->id() . '/edit');
$this->assertSession()->statusCodeEquals(200);

$this->drupalGet('/node/' . $offer->id() . '/delete');
$this->assertSession()->statusCodeEquals(200);

// Why is this required?
$offer->save();
$this->assertSame(TRUE, $offer->access('update', $low_user));
$this->assertSame(TRUE, $offer->access('delete', $low_user));

```

Everything passes except the last two statements unless I save the node. I *assume* this is due to the line:

```
AccessResult::allowedIf(!empty($user_has_suppliers_with_node))->cachePerUser()->addCacheableDependency($node);

```

I also tried using resetCache and invalidateTags against the node, neither worked. Only saving the node will the test pass - but this is not required in implementation.

Edit:

Swapping `$offer->save()` with `\Drupal::service('plugin.cache_clearer')->clearCachedDefinitions();` also works.

I suppose I should be simulating an admin logging in and updating that user account and hitting "Save" on the user form, but I also had trouble getting the edit array to do anything for an autocomplete field. That is the difference between what is implemented and how its being tested (user action vs code).

# Answer
This looks like the access result is stored in the static cache. Try to clear it before testing node access:

```
\Drupal::entityTypeManager()->getAccessControlHandler('node')->resetCache();

```
> 3 votes

---
Tags: 9, testing
---


title: Cannot Install Theme

text:
# Question
Title: Cannot Install Theme
my problem is that I cannot install this specific theme and also I cannot install the required module for that. As you can see in the picture, I cannot check the checkbox to install it. By the way I am using WAMP and Drupal 9.4.1

# Answer
When on the page for installing modules it's not possible to select a module, it means that at least one of the following conditions is true. (All these conditions are checked in `ModulesListForm::buildRow()`.)

* The module isn't compatible with the installed Drupal release
* The module requires a PHP version that is higher than the PHP version used for the site
* One of the module dependencies is missing

In any case, the full module description shows also the reason why the module cannot be installed.
What the screenshot show is a short description. To see the full description, you need to click on those little arrows (which could not seem arrows) shown between the module name and the module short description.

>

Notice that the *2.0.x* branch of the *IU Paragraphs* module is rather specific about the Drupal version that requires, since its .info.yml file contains the following line.

```
core_version_requirement: ^9.1.0-alpha1

```

The 8.x-1.x branch is compatible only with Drupal 8 (and not all the Drupal 8 releases.) (See its .info.yml file.)

Both the *2.0.x* and the *8.x-1.x* branches require some contributed modules. For example, the dependencies for the *2.0.x* branch are the following.

* autocomplete\_deluxe:autocomplete\_deluxe
* dropzonejs:dropzonejs\_eb\_widget
* drupal:block
* drupal:field
* drupal:field\_layout
* drupal:file
* drupal:image
* drupal:layout\_discovery
* drupal:link
* drupal:media
* drupal:node
* drupal:options
* drupal:path
* drupal:taxonomy
* drupal:text
* drupal:user
* drupal:views
* embed:embed
* entity\_browser:entity\_browser
* entity\_embed:entity\_embed
* entity\_reference\_revisions:entity\_reference\_revisions
* field\_group:field\_group
* file\_entity:file\_entity
* media\_entity\_browser:media\_entity\_browser
* paragraphs:paragraphs
* svg\_image\_field:svg\_image\_field
* viewsreference:viewsreference

Leaving out the lines starting with *drupal:*, which list Drupal core modules, the other lines list contributed modules that needs to be installed in order to install the *IU Paragraphs* module.
> 2 votes

---
Tags: installation
---


# Question
Title: What's the syntax of drush generate --answers argument?
So I am trying to automate theme creation using drush. There is no documentation on how to fill the --answers argument there https://drushcommands.com/drush-9x/core/generate/

I have tried:

```
drush generate theme --answers='{"Theme name":"test", "Theme machine name":"test", "Base theme":"Classy"}'

```

to no avail:(

# Answer
Finally found it:

```
drush generate theme --directory themes/custom --answers '{"name": "test", "machine_name": "test", "base_theme": "Classy"}'

```

in the absence of documentation, you'll find the needed json keys in the sources of drush code generator:

```
/sources/vendor/chi-teck/drupal-code-generator/src/Command/Drupal_8/Theme.php

```

in the "interact" method
> 4 votes

# Answer
You just need a space after --answers instead of =

```
drush generate theme --answers '{"Theme name": "test", "Theme machine name": "test", "Base theme": "Classy"}'

```

Different command, but same structure as shown here: https://cog-tools.readthedocs.io/en/latest/#command-line-options
> 2 votes

# Answer
The latest version of `drush` does not use JSON format for anwers anymore. Instead it accepts a sequence of answers like follows.

```
drush generate theme --answer=Test --answer=test --answer=classy --answer= --answer=

```

Note that for empty anwers the default value will be used.
> 0 votes

---
Tags: drush
---


# Question
Title: How to convert paragraph library item (ContentEntityBase) to render array for Twig template
I'm attempting to render an array of LibraryItems in a twig template but I'm having trouble figuring out how to retrieve the render array.

Currently my twig template looks like this

```
{% set paragraphs = node.getParagraphs() %}

{% for paragraph in paragraphs %}
{{ paragraph }}
{% endfor %}

```

But this gives me the error

> Exception: Object of type Drupal\paragraphs\_library\Entity\LibraryItem cannot be printed

How would I turn the LibraryItem entity into something printable? I'm willing to do this either on the twig side or in a hook but it would be helpful to know how to do both.

# Answer
> 2 votes
Since you want to know both, here is a Twig solution:

```
{{ paragraph|view }}

```

This is using the view filter of the module Twig Tweak.

In a multilingual site you need to translate the entity:

```
{{ paragraph|translation|view }}

```

# Answer
> 0 votes
I was able to accomplish this by using the ViewBuilder like so

```
$paragraphsRender = \Drupal::entityTypeManager()
  ->getViewBuilder('paragraphs_library_item')
  ->viewMultiple($paragraph_ids);

```

---
Tags: 9, paragraphs
---


# Question
Title: How do I find out which Contrib module is compatible with PHP 7?
Drupal.org misses a PHP version field. As far as I can see, I have to go through the issue queue or .info file for every third-party module to find out which PHP version is supported. Is that correct?

# Answer
> 6 votes
Sort of.

The PHP version isn't a required key for module .info files, and it's a *minimum* version of compatibility anyway. So a module could declare itself as requiring PHP5.6, but still work absolutely fine under PHP7. Or it could not declare a minimum version of PHP at all, and still work under PHP7. Or it could declare PHP5.6 as minimum, but not work at all in PHP7. You get the idea.

So yes, you need to check on a case-by-case basis to find out which will work under a specific version of PHP.

# Answer
> 0 votes
Yes, this is (still) correct.

If you just want to know if your **existing Installation** and modules are ready for a new PHP-Version, you can try to use PHP\_CodeSniffer.

This tool scans your directory to detect violations of a defined coding standard.

Depending on how you installed your website you can use *composer* for that. It could look something like that:

```
composer require --dev phpcompatibility/php-compatibility
cd [folder_of_your_drupal_composer_file]
vendor/bin/phpcs --config-set installed_paths vendor/phpcompatibility/php-compatibility/PHPCompatibility
vendor/bin/phpcs -p [folder_to_scan] --standard=PHPCompatibility --extensions=[extensions_to_check] --runtime-set testVersion [PHP-Version_to_check]

```

To check all your modules for compatibility for PHP8.0 and save the log to the file "compatibility\_php80.txt", the last line could look something like that:

```
vendor/bin/phpcs -p web/modules --standard=PHPCompatibility --extensions=module/php,inc/php,install/php,php/php --runtime-set testVersion 8.0 --report-full=compatibility_php80.txt

```

You can find a quite similar approach on the drupal handbook page "Drupal - PHP version compatibility check"

---
Tags: community-official-site
---


title: Custom entity integration

text:
# Question
Title: Custom entity integration
I have created an entity, contactdata, and am trying to expose this entity to views. I have created my own views\_data handler class, contactdataEntityViewsData, and have annotated my custom entity to point the views\_data hander to this class. I put a breakpoint in this class and I know that it is being invoked.

Here is the code in my contactdataEntityViewsData class:

```
<?php
/**
 * @file
 */

namespace Drupal\contactdata;

use Drupal\views\EntityViewsData;

class contactdataEntityViewsData  extends EntityViewsData  {
  /**
   * {@inheritdoc}
   */
public function getViewsData() {
  $data = parent::getViewsData();
  return $data;
}
}

```

Symptoms: The views UI can "see" my contactdata entity and will allow me to create a table with both base fields from the entity and non-base fields that I have added to it. However, when I run the view I get a table with the correct headers but with **no data**.

I am using the Creative Responsive theme on my site, but have also reset the default theme to Bartik, and the results are identical: a table with headers but no data.

I am running Drupal 9.2.4 with PHP 7.4.16 and mysql 5.7.30.

# Answer
Since you don't have anything of your own in contactdataEntityViewsData class you can delete your contactdataEntityViewsData.php file.

In your entity definition class that extends ContentEntityBase you should have handlers in the annotations that point to "Drupal\views\EntityViewsData". That should be enough for views to pick up your entity. Here is an example:

```
/**
 * Defines the Contact Data entity.
 *
 * @ContentEntityType(
 *   id = "ws_contact_data",
 *   label = @Translation("Contact Data"),
 *   base_table = "ws_contact_data",
 *   entity_keys = {
 *     "id" = "id",
 *     "uuid" = "uuid",
 *     "subscribers" = "subscribers",
 *     "hash" = "hash",
 *     "data" = "data",
 *   },
 *   handlers = {
 *    "views_data" = "Drupal\views\EntityViewsData",
 *     "form" = {
 *       "default" = "Drupal\Core\Entity\ContentEntityForm",
 *       "add" = "Drupal\Core\Entity\ContentEntityForm",
 *       "edit" = "Drupal\Core\Entity\ContentEntityForm",
 *       "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
 *     },
 *     "route_provider" = {
 *       "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
 *     },
 *   },
 *   links = {
 *     "canonical" = "/contact_data/{contact_data}",
 *     "add-page" = "/contact_data/add",
 *     "edit-form" = "/contact_data/{contact_data}/edit",
 *     "delete-form" = "/contact_data/{contact_data}/delete",
 *     "collection" = "/admin/content/contact_data",
 *   },
 *   fieldable = TRUE,
 *   admin_permission = "administer site configuration",
 *   field_ui_base_route = "entity.contact_data.edit_form",
 * )
 */

class ContactData extends ContentEntityBase implements ContactDataInterface {
...

```
> 1 votes

# Answer
Finally got this. I had not realized that when Views displays an entity, it constructs an EntityViewDisplay object, uses that object to create a render array, **and allows other modules to alter that render array.** I had created a hook\_entity\_display\_build\_alter method in a completely different module, this method was being invoked by views, and hence my problem.
> 1 votes

---
Tags: views, entities, 9
---


title: Where is the Migrate UI page?

text:
# Question
Title: Where is the Migrate UI page?
In Drupal 8.2.x there is the new migration UI tool. I've enabled it, but I can't find any link going to any UI page. Back in Drupal 7 when you enabled a module, it would have a configure link next to the module name in the modules page, but Drupal 8 doesn't. How would one find these configure links to the module pages?

# Answer
The Migrate Tools module provides tools for running and managing Drupal 8 migrations.

https://www.drupal.org/project/migrate\_tools
> 1 votes

# Answer
modules -\> migrate UI -\> configure.

Press on the gear and you will enter the migration process.
> 2 votes

# Answer
The path for this module's config page is example.com/upgrade.
> 0 votes

---
Tags: 8, migrations
---


# Question
Title: Weird Character output Field Collection data with Views Data Export (CSV)
I am using Field Collections on a content type, in Drupal 7. I am exporting this data as a Views Data Export with these collections. I can get everything to print out, however, I get a weird special character and I cannot seem to get rid of it. Below is the output. I don't like the way it looks but getting rid of the special character is paramount.

```
Name of Conference:Â Conference TypeTitle of Abstract:Â Testing each field and its meritsAuthors:Â Tim Snip, Fish Head, Testing Page, Water CupCity:Â AtlantaState:Â GACountry:Â U.S.A.Date:Â June, 2018

```

I have been clicking every check box and testing everything I can but not luck. Is there a way to get rid of this? or find out why it is even showing up?

# Answer
You have UTF-8 characters in your data. The `Â` character in your case is a UTF-8 non-breaking space, but it's being rendered with the wrong encoding.

You might be looking at the output in something that can't render UTF-8 correctly (some old, dumb text editor), or if you're using something that does understand UTF-8, perhaps the wrong encoding (i.e. iso-8859-1) was chosen when you opened the csv.
> 2 votes

# Answer
I know I am a few years late to the answer, but if there are UTF-8 characters like Â in your data, you can decode it by setting "utf8\_decode" in the character encoding conversion field in the Data export view.
> 2 votes

---
Tags: 7, views, importing-exporting
---


title: Install Commerce_Paypal Error

text:
# Question
Title: Install Commerce_Paypal Error
I have a brand new site that I created today. When I run composer require 'drupal/commerce\_paypal:^1.0@RC' I get this. What do I need to do to get this resolved? Shouldn't this just work? I installed Drupal and Commerce using the command in the docs. composer create-project drupalcommerce/project-base mystore --stability dev

```
Problem 1
- drupal/commerce_paypal[1.0.0-rc1, ..., 1.0.0-rc6] require sainsburys/guzzle-oauth2-plugin ^3.0 -> satisfiable by sainsburys/guzzle-oauth2-plugin[v3.0.0, ..., v3.0.6].
- sainsburys/guzzle-oauth2-plugin[v3.0.0, ..., v3.0.2] require guzzlehttp/guzzle ~6.0 -> found guzzlehttp/guzzle[6.0.0, ..., 6.5.x-dev] but the package is fixed to 7.4.5 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
- sainsburys/guzzle-oauth2-plugin[v3.0.3, ..., v3.0.6] require guzzlehttp/guzzle ^6.0 -> found guzzlehttp/guzzle[6.0.0, ..., 6.5.x-dev] but the package is fixed to 7.4.5 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
- Root composer.json requires drupal/commerce_paypal ^1.0@RC -> satisfiable by drupal/commerce_paypal[1.0.0-rc1, ..., 1.0.0-rc6].

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.

```

# Answer
> 0 votes
As the output reads, there is a locked version of Guzzle prevents upgrading. Add the `-W` switch as directed.

---
Tags: commerce
---


# Question
Title: How can I restrict access to listing users via JSON:API but allow users to edit their own accounts?
I am building a webapp with Drupal using JSON:API. When users have permission to view accounts, then they can go to `/jsonapi/user--user/` and get a list of all the accounts on the site.

I don't want to expose this information, so I tried disabling access to the resource in an EventSubscriber as described in the docs:

```
  public function disableResourceType(ResourceTypeBuildEvent $event) {
    if ($event->getResourceTypeName() === 'user--user') {
      $event->disableResourceType();
    }
  }

```

**However, when I disable access to the resource, users can no longer update their profiles via JSON:API.**

So how do I restrict access to GET but allow PATCH, POST, and DELETE?

# Answer
You need to make a routing event subscriber as described here:

```
namespace Drupal\MYMODULE\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

/**
 * Class MYMODULEJsonApiLimitingRouteSubscriber.
 *
 * Remove GET route for users.
 *
 */
class MYMODULEJsonApiLimitingRouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  protected function alterRoutes(RouteCollection $collection): void {
    foreach ($collection as $name => $route) {
      $defaults = $route->getDefaults();
      if (!empty($defaults['_is_jsonapi']) && !empty($defaults['resource_type'])) {
        $methods = $route->getMethods();
        if (in_array('GET', $methods) && $name === 'jsonapi.user--user.collection') {
          $collection->remove($name);
        }
      }
    }
  }
}

```

Notes

* JSON:API module has the concept of "collection" routes. These are the routes that list all of your entities, like `user--user`, so by disabling GET access to the collect route, users will not be able to get a list of all users, but they will still be able to get their individual accounts and make updates.
* If you use JSON:API Extras or custom code to rename the user route, the route name will change! For example, I renamed `user--user` to `users`, so my route is actually `jsonapi.users.collection`.

As a bonus, if you want to ensure that users can only access their own account, and not others, you need to implement `hook_entity_access()`:

```
function MYMODULE_user_access(UserInterface $user, string $operation, AccountInterface $account): AccessResult {
  if (!($account->hasPermission(PermissionCheck::AdministerUsers->value))) {
    $current_user_id = $account->id();
    $user_being_accessed_id = $user->id();
    if ($current_user_id === $user_being_accessed_id) {
      return AccessResult::allowed();
    }
  }
  return AccessResult::forbidden();
}

```

I came up with this solution based on this comment by bradjones1.
> 1 votes

---
Tags: 9
---