title: AJAX Modal Form

text:
# Question
Title: AJAX Modal Form
I created a modal form with Ajax:

```
<?php

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

namespace Drupal\hello\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax;
use Drupal\Core\Ajax\OpenModalDialogCommand;

/**
 * Description of HelloModalForm
 *
 * @author arthur
 */
class HelloModalForm extends FormBase {

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

    $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
    $form['node_title'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Node\'s title'),
      '#description' => $this->t('Enter a portion of the title to search for'),
    );

    $form['actions']['type'] = 'actions';

    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Search'),
      '#ajax' => array( // here we add ajax callback where we will process
        'callback' => '::open_modal', // the data that came from the form in modal window
       ),
    );

    $form['#title'] = 'Seach for Node by Title';

    return $form;

  }

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

  public function validateForm(array &$form, FormStateInterface $form_state) {
    // input your code for validation, no validation required in this search
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {

  }

  public function open_modal(&$form, FormStateInterface $form_state) {
    $node_title = $form_state->getValue('node_title');
    $query = \Drupal::entityQuery('node')->condition('title', $node_title, 'CONTAINS');
    $entity = $query->execute();
    $key = array_keys($entity);
    $id = !empty($key[0]) ? $key[0] : NULL;
    $response = new AjaxResponse();
    $title = 'Node ID';
    if ($id !== NULL) {
      $content = '<div class="test-popup-content"> Node ID is: ' . $id . '</div>';
      $options = array(
        'dialogClass' => 'popup-dialog-class',
        'width' => '300',
        'height' => '300',
      );
      $response->addCommand(new OpenModalDialogCommand($title, $content, $options));
    } else {
      $content = 'Not found record with this title <strong>' . $node_title . '</strong>';
      $options = array(
        'dialogClass' => 'popup-dialog-class',
        'width' => '300',
        'height' => '300',
      );
      $response->addCommand(new OpenModalDialogCommand($title, $content, $options));
    }
    return $response;
  }
}

```

Error Message on calling Modal form:

> User error: "type" is an invalid render array key in Drupal\Core\Render\Element::children() (line 97 of core/lib/Drupal/Core/Render/Element.php). Drupal\Core\Render\Element::children(Array) (Line: 1027) Drupal\Core\Form\FormBuilder-\>doBuildForm('hello\_model\_form', Array, Object) (Line: 1073) Drupal\Core\Form\FormBuilder-\>doBuildForm('hello\_model\_form', Array, Object) (Line: 575) Drupal\Core\Form\FormBuilder-\>processForm('hello\_model\_form', Array, Object) (Line: 321) Drupal\Core\Form\FormBuilder-\>buildForm(Object, Object) (Line: 91) Drupal\Core\Controller\FormController-\>getContentResult(Object, Object) call\_user\_func\_array(Array, Array) (Line: 123) Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-\>Drupal\Core\EventSubscriber{closure}() (Line: 573) Drupal\Core\Render\Renderer-\>executeInRenderContext(Object, Object) (Line: 124) Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-\>wrapControllerExecutionInRenderContext(Array, Array) (Line: 97) Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber-\>Drupal\Core\EventSubscriber{closure}() (Line: 151) Symfony\Component\HttpKernel\HttpKernel-\>handleRaw(Object, 1) (Line: 68) Symfony\Component\HttpKernel\HttpKernel-\>handle(Object, 1, 1) (Line: 57) Drupal\Core\StackMiddleware\Session-\>handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\KernelPreHandle-\>handle(Object, 1, 1) (Line: 106) Drupal\page\_cache\StackMiddleware\PageCache-\>pass(Object, 1, 1) (Line: 85) Drupal\page\_cache\StackMiddleware\PageCache-\>handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\ReverseProxyMiddleware-\>handle(Object, 1, 1) (Line: 52) Drupal\Core\StackMiddleware\NegotiationMiddleware-\>handle(Object, 1, 1) (Line: 23) Stack\StackedHttpKernel-\>handle(Object, 1, 1) (Line: 708) Drupal\Core\DrupalKernel-\>handle(Object) (Line: 19) User error: "type" is an invalid render array key in Drupal\Core\Render\Element::children() (line 97 of core/lib/Drupal/Core/Render/Element.php). Drupal\Core\Render\Element::children(Array, ) (Line: 402) Drupal\Core\Render\Renderer-\>doRender(Array) (Line: 444) Drupal\Core\Render\Renderer-\>doRender(Array, ) (Line: 200) Drupal\Core\Render\Renderer-\>render(Array, ) (Line: 226) Drupal\Core\Render\MainContent\HtmlRenderer-\>Drupal\Core\Render\MainContent{closure}() (Line: 573) Drupal\Core\Render\Renderer-\>executeInRenderContext(Object, Object) (Line: 227) Drupal\Core\Render\MainContent\HtmlRenderer-\>prepare(Array, Object, Object) (Line: 117) Drupal\Core\Render\MainContent\HtmlRenderer-\>renderResponse(Array, Object, Object) (Line: 90) Drupal\Core\EventSubscriber\MainContentViewSubscriber-\>onViewRenderArray(Object, 'kernel.view', Object) call\_user\_func(Array, Object, 'kernel.view', Object) (Line: 111) Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher-\>dispatch('kernel.view', Object) (Line: 156) Symfony\Component\HttpKernel\HttpKernel-\>handleRaw(Object, 1) (Line: 68) Symfony\Component\HttpKernel\HttpKernel-\>handle(Object, 1, 1) (Line: 57) Drupal\Core\StackMiddleware\Session-\>handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\KernelPreHandle-\>handle(Object, 1, 1) (Line: 106) Drupal\page\_cache\StackMiddleware\PageCache-\>pass(Object, 1, 1) (Line: 85) Drupal\page\_cache\StackMiddleware\PageCache-\>handle(Object, 1, 1) (Line: 47) Drupal\Core\StackMiddleware\ReverseProxyMiddleware-\>handle(Object, 1, 1) (Line: 52) Drupal\Core\StackMiddleware\NegotiationMiddleware-\>handle(Object, 1, 1) (Line: 23) Stack\StackedHttpKernel-\>handle(Object, 1, 1) (Line: 708) Drupal\Core\DrupalKernel-\>handle(Object) (Line: 19)

# Answer
> 0 votes
> User error: "type" is an invalid render array key in Drupal\Core\Render\Element::children()

You forgot the leading `#` in your `actions` form render element:

```
$form['actions']['type'] = 'actions';

```

Should be:

```
$form['actions']['#type'] = 'actions';
                  ^ Add leading #.

```

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


# Question
Title: $form_state values are empty after ajax $form modification
Im doing a module to generate form validation on field length, first i display a select of availble content types. When the target content type is selected an ajax request display the end of the form with an another select wich contain avaibles fields of the content type selected before. When the form is submited form\_state values of the step 2 of the form are empty. When i display the var\_dump in the submitform, only 'content\_type' has a value.

The code here

```
class OpenLimitLengthSettingsForm extends ConfigFormBase{

const PLACEHOLDERVALUE = '_none';
const LIMITABLEFIELDTYPES = ['integer', 'string_long', 'string', 'text_with_summary', 'text_long', 'text'];
const SKIPPEDFIELDS = ['nid', 'vid'];
/**
 * Gets the configuration names that will be editable.
 *
 * @return array
 *   An array of configuration object names that are editable if called in
 *   conjunction with the trait's config() method.
 */
protected function getEditableConfigNames()
{
    return array("open_limit_length.config");
}

/**
 * Returns a unique string identifying the form.
 *
 * The returned ID should be a unique string that can be a valid PHP function
 * name, since it's used in hook implementation names such as
 * hook_form_FORM_ID_alter().
 *
 * @return string
 *   The unique string identifying the form.
 */
public function getFormId()
{
    return "open-sendmail-settings-form";
}

public function buildForm(array $form, FormStateInterface $form_state)
{
  $config = $this->config('open_limit_length.config');

  //Loading content types
  $contentTypes = $this->getAllContentTypes();
  $contentTypeOptions = [self::PLACEHOLDERVALUE => $this->t("-- Choisir un type de contenu --")];
  foreach($contentTypes as $contentType){
    $contentTypeOptions[$contentType->get('type')] = $contentType->get('name');
  }

  //Building form's render array
  $form["title"] = [
    "#markup" => "<h2>".$this->t("Limitation de taille de champ")."</h2>"
  ];

  $form["add_limit"] = [
      '#type' => 'fieldset',
      '#title' => $this->t("Ajouter une limitation"),
      '#prefix' => '<div id="open_limit_length_mutistep_form">',
      '#suffix' => '</div>'
    ];

  $form["add_limit"]['content_type'] = [
    '#type' => 'select',
    '#title' => $this->t("Type de contenu"),
    '#options' => $contentTypeOptions,
    '#ajax' => [
      'callback' => '::getFieldsOfContentType',
      'wrapper' => 'open_limit_length_mutistep_form'
    ]
  ];

  $form['add_limit']['available_fields'] = [
    '#type' => 'select',
    '#title' => $this->t("Champ à limiter"),
    '#options' => '',
    '#access' => false
  ];

  $form['add_limit']['field_limit'] = [
    '#type' => 'textfield',
    '#title' => $this->t('Taille maximum'),
    '#attributes' => [
      ' type' => 'number'
    ],
    '#access' => false
  ];
  $form['add_limit']['text_limit'] = [
    '#type' => 'textarea',
    '#title' => $this->t("Message d'erreur en cas de dépassement de la limite"),
    '#suffix' => '<div><i>'.$this->t("Exemple : Le champ {{field_name}} est limité à {{nb_max_car}}, taille actuelle {{current_nb_car}}").'</i></div>',
    '#access' => false,
  ];

  $form['add_limit']['submit'] = [
    '#type' => 'submit',
    '#value' => $this->t("Enregistrer"),
    '#access' => false,
  ];

    return parent::buildForm($form, $form_state);
}

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

private function getAllContentTypes(){
  $types = \Drupal::entityTypeManager()
    ->getStorage('node_type')
    ->loadMultiple();
  return $types;
}

$selectedContentType = $form_state->getValues()['content_type'];
$entityManager = \Drupal::service('entity_field.manager');
if($selectedContentType != self::PLACEHOLDERVALUE){
  $fields = $entityManager->getFieldDefinitions('node', $selectedContentType);
  $optionsFields = [self::PLACEHOLDERVALUE => '-- Choisir un champ --'];
  /** @var \Drupal\Core\Field\BaseFieldDefinition $field */
  foreach($fields as $field){
    if(in_array($field->getType(), self::LIMITABLEFIELDTYPES) && !in_array($field->getName(), self::SKIPPEDFIELDS)){
      $optionsFields[$field->getName()] = $field->getLabel();
    }
  }

  $form['add_limit']['available_fields']['#options'] = $optionsFields;
  $form['add_limit']['available_fields']['#access'] = true;
  $form['add_limit']['field_limit']['#access'] = true;
  $form['add_limit']['text_limit']['#access'] = true;
  $form['add_limit']['submit']['#access'] = true;

  $form_state->setRebuild();

  $response->addCommand(new ReplaceCommand('#open_limit_length_mutistep_form', $form['add_limit']));
}else{
  $response->addCommand(new AlertCommand("Veuillez selectionner un type de contenu valide"));
}

return $response;}}

```

I'm searching an issue since this morning but nothing solved my problem. Thanks for your help

# Answer
> 1 votes
All of your form elements have an `'#access' => false` attribute. Remove these and your values will pull through in the submit handler.

---
Tags: 8, forms, ajax
---


# Question
Title: How can you remove another modules events?
So, I have an event subscriber for Drupal commerce that listens for "commerce\_order.place.post\_transition" and will send a bespoke order email (due to not being able to change some of the things like subject title in the commerce module).

Commerce also has an event subscriber listening to "commerce\_order.place.post\_transition" which will send an order receipt email. I need to unsubscribe this event to prevent sending duplicate emails but searching through google and comments sections of articles has lead me to a dead end.

Any ideas?

# Answer
> 3 votes
Remove the event subcriber service from the container:

*my\_module/src/MyModuleServiceProvider.php*

```
namespace Drupal\my_module;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;

/**
 * Remove the foo event subscriber.
 */
class MyModuleServiceProvider extends ServiceProviderBase {

  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container) {
    $container->removeDefinition('foo_event_subscriber');
  }

}

```

You find the service name in the *MODULE.services.yml* file of the other module.

More info https://www.drupal.org/docs/8/api/services-and-dependency-injection/altering-existing-services-providing-dynamic-services

# Answer
> 1 votes
This doesn't answer your question specifically but is an alternative. If it's the standard commerce email you could go to "Commerce \> configuration \> Orders \> Order types" and within each order type you can control to "Email the customer a receipt when an order is placed"

# Answer
> 1 votes
Decorate the existing event as described in this article: https://matthieuscarset.com/en/blog/how-safely-override-or-extend-other-services-methods-drupal-8

In mymodule/src/EventSubscriber/MySubscriber.php:

```
namespace Drupal\mymodule\EventSubscriber;

class MySubscriber extends ParentSubscriber {

  /**
   * {@inheritDoc}
   */
  public function decoratedMethod(...$args) {
    parent::decoratedMethod(...$args); // or whatever you want to do
  }
}

```

In mymodule/mymodule.services.yml:

```
services:
  mymodule.myservice:
    public: false
    class: Drupal\mymodule\EventSubscriber\mySubscriber
    decorates: decorated_provider.decorated_service_name

```

# Answer
> -2 votes
and welcome to Drupal Answers.

Assuming you're using Drupal 8, you may try the below code to hide the email fieldset:

```
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
    if ($form_id == "commerce_order_type_edit_form") {
        $form["emails"] = [
            "#checked" => FALSE,
        ];
    }
}

```

Hope that helps.

---
Tags: commerce, event-subscribers
---


# Question
Title: Hiding a tab on a user profile based on the user role
I'm making a site using Drupal 8 and I have several roles defined, one of them is Writer. I made a view to show as a tab in the user profile pages called Backlist. If the user is a writer, they can add a list of their books they have written. Everyone visiting the site has access to the backlist information under that tab. What I'm trying to do is make it so the tab ONLY shows in profiles that are writers.

This is very similar to this question: Hide views tab display on user profile to profile owner That answer didn't work for me because it seems that the 'hide view' is no longer in the validation settings.

As I have it now, the tab shows all the time, and if there's no content, it just shows a message. So is it possible to hide a views tab, in a profile, based on the owner's role?

```
Contextual filters:

Configure contextual filter: User: User ID
validation criteria: User_ID
Restrict user based on role: Writer
Action to take if filter value does not validate: Display Contents of No results found

```

# Answer
Just under `Display content of "No results found"` I see `Display "Access denied"` you need to use that one.

**Denied users won't see the tab anymore.**

If the display of your view is a page you can even manage the access directly into the "page's parameters" block and restrict the access by user role without using a contextual filter (unless the view really needs one).
> 1 votes

---
Tags: views, users, navigation
---


# Question
Title: Message display in administration Repport and MySQL SELECT different
When look at log details from http://website/admin/reports/dblog/event/12599, it shows the following message.

> Starting execution of search\_cron(), execution of node\_cron() took 5.26ms.

When I query the database table used, I get the following.

> Starting execution of @module\_cron(), execution of @module\_previous\_cron() took @time.

How do I get, querying the database, the same message I see on the log?

# Answer
The message shown in the log is the output of `t('Starting execution of @module_cron(), execution of @module_previous_cron() took @time.')` (or `new TranslatableMarkup('Starting execution of @module_cron(), execution of @module_previous_cron() took @time.')` while in the database you find the string passed to `t()` or `new TranslatableMarkup()`.

To get the string output in the log, you need to find the list of the placeholder values passed to `t()`, which are in the same database table.
That is essentially what `DbLogController::eventDetails()`, the controller showing pages like /admin/reports/dblog/event/12599 does.

```
  $dblog = $this->database->query('SELECT w.*, u.uid FROM {watchdog} w LEFT JOIN {users} u ON u.uid = w.uid WHERE w.wid = :id', [
    ':id' => $event_id,
  ])
    ->fetchObject();
  if (empty($dblog)) {
    throw new NotFoundHttpException();
  }
  $build = [];
  $severity = RfcLogLevel::getLevels();
  $message = $this->formatMessage($dblog);

```

In the URL you shown, `$event_id` is 12599.
`formatMessage()` is a public method of `DbLogController`. You can copy the code from that method, or instantiate the controller in the appropriate way. For example, the following function would return the message with the placeholders replaced by their values.

```
function mymodule_get_log_message($event_id) {
  $message = '';
  $dblog = \Drupal::database->query('SELECT w.*, u.uid FROM {watchdog} w LEFT JOIN {users} u ON u.uid = w.uid WHERE w.wid = :id', [
    ':id' => $event_id,
  ])
    ->fetchObject();
  if (!empty($dblog)) {
    // Check for required properties.
    if (isset($dblog->message, $dblog->variables)) {
      $variables = @unserialize($dblog->variables);

    // Messages without variables or user specified text.
    if ($variables === NULL) {
      $message = Xss::filterAdmin($dblog->message);
    }
    elseif (!is_array($variables)) {
      $message = new TranslatableMarkup('Log data is corrupted and cannot be unserialized: @message', ['@message' => Xss::filterAdmin($dblog->message)]);
    }
    else {
      // Ensure backtrace strings are properly formatted.
      if (isset($variables['@backtrace_string'])) {
        $variables['@backtrace_string'] = new FormattableMarkup('<pre class="backtrace">@backtrace_string</pre>', $variables);
      }
      $message = (Xss::filterAdmin($dblog->message), $variables);
    }
  }

  return $message
}

```

As usual, where possible, use Dependency Injection instead of `\Drupal`. When sub-classing some classes, a `t()` method is available; that should be used instead of `t()` or `new TranslatableMarkup()`.
> 1 votes

---
Tags: log-messages
---


title: Watchdog and translations

text:
# Question
Title: Watchdog and translations
Coder says:

> The `$message` argument to `watchdog()` should NOT be enclosed within `t()`, so that it can be properly translated at display time.

Does this mean that `$message` will be translated by `watchdog()` by default?

# Answer
As per the core documentation we should use the watchdog function without the `t()` because it is translating when reading and outputing the log message.

Watchdog invokes `dblog_watchdog()` in "modules/dblog/dblog.module" and dblog\_watchdog() is not translating anything before writing into the database BUT it is translating when reading and outputing the log message.

Reference:
> 4 votes

# Answer
Might be if we store the translated string in the database(tokens replaced with real values), it will make it non translatable while displaying it to the user.So storing the string with tokens directly and replacing those at the time of display makes more sense as translation seems to be taken care of at presentation layer.

and I consider the same reason responsible for title in menu as they are kept untranslated as well.
> 1 votes

# Answer
No, `watchdog()` doesn't translate the message. The message will be translated when the message is shown to the users, for example, in admin/reports/event/%, which is the page output from `dblog_event()`.

```
  $severity = watchdog_severity_levels();
  $result = db_query('SELECT w.*, u.name, u.uid FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid WHERE w.wid = :id', array(
    ':id' => $id,
  ))->fetchObject();
  if ($dblog = $result) {
    $rows = array(
      array(
        array(
          'data' => t('Type'),
          'header' => TRUE,
        ),
        t($dblog->type),
      ),
      array(
        array(
          'data' => t('Date'),
          'header' => TRUE,
        ),
        format_date($dblog->timestamp, 'long'),
      ),
      array(
        array(
          'data' => t('User'),
          'header' => TRUE,
        ),
        theme('username', array(
          'account' => $dblog,
        )),
      ),
      array(
        array(
          'data' => t('Location'),
          'header' => TRUE,
        ),
        l($dblog->location, $dblog->location),
      ),
      array(
        array(
          'data' => t('Referrer'),
          'header' => TRUE,
        ),
        l($dblog->referer, $dblog->referer),
      ),
      array(
        array(
          'data' => t('Message'),
          'header' => TRUE,
        ),
        theme('dblog_message', array(
          'event' => $dblog,
        )),
      ),
      array(
        array(
          'data' => t('Severity'),
          'header' => TRUE,
        ),
        $severity[$dblog->severity],
      ),
      array(
        array(
          'data' => t('Hostname'),
          'header' => TRUE,
        ),
        check_plain($dblog->hostname),
      ),
      array(
        array(
          'data' => t('Operations'),
          'header' => TRUE,
        ),
        $dblog->link,
      ),
    );
    $build['dblog_table'] = array(
      '#theme' => 'table',
      '#rows' => $rows,
      '#attributes' => array(
        'class' => array(
          'dblog-event',
        ),
      ),
    );
    return $build;
  }

```
> 0 votes

---
Tags: 7, log-messages
---


# Question
Title: How do I get a block configuration value in a module?
I created a custom block that contains a form field.

This is my `blockSubmit()` method.

```
public function blockSubmit($form, FormStateInterface $form_state) {
    // Save our custom settings when the form is submitted.
    $this->setConfigurationValue('my_text_field', $form_state->getValue('my_text_field'));
}

```

Now I want to access the *my\_text\_field* value from outside the custom block class.

# Answer
> 19 votes
You can load the block configuration entity, and get the settings.

```
$block = \Drupal\block\Entity\Block::load($block_id);
if ($block) {
  $settings = $block->get('settings');
  $my_text_field = $settings['my_text_field'];
}

```

`$block_id` is the machine name you see in the block layout when you save the block.

**Edit: Store module configuration**

If you want to store configuration for modules don't use a block form, but use a configuration form. Reference https://www.drupal.org/docs/8/api/configuration-api/working-with-configuration-forms (see comment from @Berdir)

**Dump all blocks and their settings**

```
$blocks = \Drupal\block\Entity\Block::loadMultiple();
foreach ($blocks as $key => $block) {
  $settings = $block->get('settings');
  var_dump([$key => $settings]);
}

```

# Answer
> 4 votes
Replace `BLOCK_ID` with your block's ID and dig the variables in it using get function

```
$config = \Drupal::config('block.block.BLOCK_ID');
$config->get('settings.my_text_field');

```

# Answer
> -2 votes
I understand that the code above sounds like it should work, Block::load($bid) and $bid is from the annotation of the Block class. But the start of my code is this:

```
/**
 * Provides a 'SearchFiltersBlock' block.
 *
 * @Block(
 *  id = "search_filters_block",
 *  admin_label = @Translation("Filters"),
 * )
 */
class SearchFiltersBlock extends BlockBase {

```

yet, ::load('search\_filters\_block') returns NULL.

I tried this: Block::loadMultiple() to see what blocks existed and i see one with the id "filters" and it has plugin value "search\_filters\_block".

No idea.

---
Tags: 8, blocks
---


# Question
Title: How can I alter node markup from a custom module (not theme)?
In a custom D8 *module* (not a theme or sub-theme) what is the best way to alter all nodes of a specific content type by prepending them with simple markup?

I'm trying this approach with no success ...

`custom/custom.module`:

```
<?php
/**
 * @file
 * Custom module hook implementations.
 */
/**
 * Implements hook_theme().
 */
function custom_theme() {
  return [
    'custom_article_node' => [
      'template' => 'custom-article-node',
      'variables' => [],
    ],
  ];
}

```

`custom/templates/custom-article-node.html.twig`:

```
<i>This is a Custom Article node.</i>
{{ content }}

```

I'm not sure how to pass the node to the template, or to test what content type it is ... and I'm not sure if this theme hook is even executing.

(I know how to override templates in the theme layer, but in this case I need to do it in a custom module.)

# Answer
> 1 votes
This did the trick:

`custom.module`:

```
<?php

/**
 * @file
 * Custom module hook implementations.
 */

/**
 * Implements hook_theme().
 */
function custom_theme() {
  return [
    'node__custom_article' => [
      'template' => 'node--custom-article',
      'base hook' => 'node',
    ],
  ];
}

```

Credit where it's due: https://www.drupal.org/forum/support/module-development-and-code-questions/2015-06-03/drupal-8-override-template-with#comment-12461953

---
Tags: 8, theming
---


# Question
Title: Can I extend the image field formatter without defining a custom one?
XY problem: I need to extend the default image widget in the entity edit form with some custom fields so that, per image, e.g. a copyright and description, independently from the alt and title field, can be set.

I can add the fields by altering the core image module files, and by manually adding the respective database columns. But of course, I would like to alter the plugins with a custom module.

I was able to create a custom formatter based on the ImageWidget as described in this tutorial.

My question is: is there a way to alter the default image widget/ field type to add custom fields rather than defining custom formatters/ widgets?

# Answer
As an alternative, more flexible way, you could chose to use either File entity or Media entity, both give you a fieldable entity that you can add your additional fields, without having to write a single line of custom code.

File entity makes the files themself fieldable and adds file types, so images can have different fields than videos for example.

Media entity adds a separate entity that you work with, and works well combined with a number of other modules like Entity Browser and Inline Entity Form. There are some good tutorials out there:

http://www.annertech.com/blog/reusable-media-drupal-8-tutorial http://flocondetoile.fr/blog/managing-media-drupal-8
> 3 votes

# Answer
I needed to do something similar to this in Drupal 8. I wanted to add a description field to the image field so that it could be displayed for each image.

I couldn't find a solution, so I ended up creating a custom module to do this. Ended up creating a custom field type, custom field widget and custom field formatter. Also using hook theme, a .field.inc to provide the variables for a template, and finally the said template.

This is one of the first pages I came across on Google searching for this, so I thought I'd add it in case it helps someone else.

https://github.com/WiddleWabbit/Drupal-ExtendedImage
> 1 votes

---
Tags: entities, 8, media
---


title: How to classify a view by letter?

text:
# Question
Title: How to classify a view by letter?
I have tags (taxonomy terms) and created a tags pageview.

I want to sort my tags alphabetically and group them by letter of the alphabet.

How can I do this? Thank you

I want a single page. I don't want to filter the results.

**A :**

ring

accessory

**B :**

bracelet

cap

candle

...

**UPDATE**

I have found a possible solution but I need help. In my view I created a "Global: Custom text" field and I grouped this field in the format of the view.

It sounds really good. Now what TWIG code to put in the "Global: Custom text" field to extract the first letter of `{{ name }}` (which corresponds to the field "Taxonomy term: Name").

I tested the following code, but it doesn't work :

```
{{ '{{ name }}'|first }}

```

# Answer
> 1 votes
I expect you could arrive at this by having a hyerachrical vocabulary. Use the drag handles indent terms as below.

```
A
- term 1
- term 2

B
- term 3
- term 4

```

If you needed to list terms in a view, you could use the 'terms with depth' option.

No idea why someone has downvoted your question. It seems perfectly reasonable.

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


# Question
Title: How can I keep new nodes within a certain range of IDs so as to not conflict with migrated node IDs?
In Drupal 8, I am preparing a migration and at the same time, the users are adding nodes of content manually. For the migration I need to keep the same node ID as the source. Is there any way I can limit manually added content to a certain range of node ids so that it doesn't conflict with my migrated nodes which will be added afterwards.

# Answer
> 4 votes
I have encountered the same problem and where there may be clashes you can set the value of AUTO\_INCREMENT to a high value to ensure there is no overlap between new content items, which get higher node IDs, and old items, which keep their existing ones. For MySQL:

```
ALTER TABLE node AUTO_INCREMENT=100000;
ALTER TABLE node_revision AUTO_INCREMENT=100000;

```

Depending on your migration you may need to apply this to other items such as taxonomy term IDs as well.

# Answer
> 3 votes
Why would you need to keep the same node ID for the migration?

When you use the Migrate module, it maps the old node ID with the new one; you just need to use the *entity\_lookup* or *migration\_lookup* process plugin to process your referenced entities. (See Understanding the entity\_lookup and entity\_generate process plugins from Migrate Tools for more details.)

# Answer
> 2 votes
Messing with nids is a tricky business. The Custom Nid module or this question might aid you but technically it's really hard and not advised to alter nids as the column is set to auto increment in the database. There are also a lot of references across the database so changing a nid will probably wreck some things.

You could implement a check in the node\_save function which checks on node save what the current assigned nid is and if the next nid (+1) is still below the lowest nid from your migration data. If that check fails you could temporary prevent new nodes from being created until the migration is done.

---
Tags: nodes, migrations
---


title: How can I clone a fieldset?

text:
# Question
Title: How can I clone a fieldset?
I've been searching for this for a while, but most of the articles I have found are from YEARS ago, so I wanted to jump in here and see if any of you lovely people have an idea... :)

I am creating a webform for a customer that has a fieldset that needs to be applied to different sections within the form, but with all the same fields within that fieldset.

Is there a way to actually duplicate/clone a fieldset within a webform in Drupal 8?

I'm using:

* Drupal 8.9.1
* Webform Version: 8.x-5.19

Any help would be very much appreciated!

Thank You! Nicole

# Answer
> 2 votes
Export config, then you'll have the fieldset in the resulting webform's Yaml. Then simply copy the whole fieldset in the Yaml, paste it to somewhere else in the Yaml and rename the elements. Now import the config again and your elements will appear in the form.

Export, paste, rename, import. That's it.

---
Tags: 8, webforms
---


title: Is there a token for the cron token?

text:
# Question
Title: Is there a token for the cron token?
For internal use by editors I would like to get cron link into a custom menu, but I need to do this dynamically, such that it can used across multiple sites.

Editors do not have access to Admin Toolbar which is why I need a link instead.

Why do I need this? I want allow editors to make a quick backup with Backup Migrate, but I don't want to give them full access and the module permissions are not granular enough to just make a quick database backup.

A colleague suggested letting editors run a cron job instead. This seems like a solution.

I already have Menu Token module installed, so I am wondering if there is a token for a site's cron token?

If not. Is another approach recommended?

# Answer
> 2 votes
The cron key is generated by Drupal core then stored as state data (`system.cron_key`) when Drupal is first installed. `system_token_info()` doesn't expose this key as a token.

You could just make a static menu link with the `/cron/$KEY` path as the key will remain static as long as the `system.cron_key` entry remains in the state table.

If the end goal is to only envoke the Backup Migrate cron handler and custom development is an option, creating your own custom route that invokes the specific backup code (e.g. `backup_migrate_cron()`) would be a more direct method and have a less chance of side effects from regular arbitrary runs of all cron handlers

---
Tags: tokens, cron, backups
---


# Question
Title: Why authenticate request returned 403 after successful login?
I have front-end with AngularJS and its connected to drupal backend. I am using drupal services module for rest api.

I have an angularjs web app in subdomain \[admin.example.com\]. My authentication subdomain \[account.example.com\] developed with drupal 7.

I can login successfully to account.example.com from admin.example.com using http request from angularjs, so I stored newly generated token. But when i try to collect user data from \[account.example.com\] using previously stored token, i get 403 status. I'm sure my token is correct.

This work well with chrome disable-web-security mode, when i try from regular mode its response me 403. but i did not get any cors error.

Someone please help me, i'm stack on this stage...

My Apache Conf file \[account.example.com\]:

```
<VirtualHost *:80>
    ServerName account.example.com
    ServerAlias account.example.com
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/example_account

    <Directory "/var/www/example_account">
        AllowOverride All
        Require all granted
        Header always set Access-Control-Allow-Origin "*"
        Header always set Access-Control-Allow-Headers "Content-Type, Accept, Authorization, X-CSRF-Token"
        Header always set Access-Control-Allow-Methods "GET,POST"
        Header always set Access-Control-Allow-Credentials true
    </Directory>

        #RewriteEngine On
        #RewriteCond %{REQUEST_METHOD} OPTIONS
        #RewriteRule ^(.*)$ $1 [R=200,L]

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

```

Here is header requests:

# Answer
> 0 votes
Try to be specific with the ACAO header, like

```
Access-Control-Allow-Origin: admin.example.com

```

The wildcard is not really appreciated, browsers may treat this as high security risk and block the request.

---
Tags: 7
---


title: How do I re-create a built-in view?

text:
# Question
Title: How do I re-create a built-in view?
I duplicated a view before making changes, but it didn't save and I'd changed most of the view settings before I realised I was working on the original.

How can I recreate the standard taxonomy view?

I am using Drupal 9, if that makes a difference.

# Answer
* Export your current config using `drush cex -y`
* Copy/paste the `/web/core/modules/taxonomy/config/optional/views.view.taxonomy_term.yml` into your config directory (usually `/config`)
* Import the config using `drush cim -y`
> 1 votes

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


# Question
Title: Replace a word in a custom block or paragraph with a token related to a content type field value
I have a content type with a mix of paragraphs and custom blocks. Most custom blocks (content) are the same on all pages except for one word that needs to be replaced by an other one. I would like to replace that word with an other one related to a field on the content type page.

I thought it could be done with **Token Filter** (https://www.drupal.org/project/token\_filter) but that is **not an option**.

**EDIT 2: explain with example** I have a content type 'CMS page'. It has a field 'field\_brand\_name'. This field is used to replace a string in paragraphs or custom blocks that exists on the content type page.

If I create a page for Magento and a page for Drupal and a page for WordPress. The only that needs to be replaced is the brand name in the text (Magento, Drupal or WordPress) on all custom blocks or paragraphs that I have used on that specific CMS page ... That could be resolved by a Token if there was a context for it, but there is no ... so the token is not replaced. Is that clear enough?

# Answer
> 0 votes
First create your own module. In mymodule\_tokens.module insert below:

```
<?php

use Drupal\Core\Render\BubbleableMetadata;

/**
 * Implements hook_token_info().
 */

function mymodule_tokens_token_info(): array
{
    $type = array(
        'name' => t('My Module Tokens'),
        'description' => t('Custom tokens to solve use-case problems for the website.'),
    );
    $node['brand'] = array(
        'name' => t("Brand name from node"),
        'description' => t("Brand name to replace in text, custom blocks, paragraphs, ..."),
    );
    return array(
        'types' => array(
            'mymodule_tokens' => $type,
        ),
        'tokens' => array(
            'mymodule_tokens' => $node,
        ),
    );
}

/**
 * Implements hook_tokens().
 */

function mymodule_tokens_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata): array
{
    $replacements = [];

    if ($type == 'mymodule_tokens') {
        foreach ($tokens as $name => $original) {
            switch ($name) {
                case 'brand':
                    $node = \Drupal::routeMatch()->getParameter('node');
                    if ($node instanceof \Drupal\node\NodeInterface) {
                        if ($node->hasField('field_brand') && !$node->get('field_brand')->isEmpty()) {
                            $brand_name = $node->field_brand->value;
                            $replacements[$original] = $brand_name;
                        } else {
                            $replacements[$original] = null;
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    }

    return $replacements;
}

```

---
Tags: blocks, tokens, paragraphs
---


title: How to limit to certain page with TWIG?

text:
# Question
Title: How to limit to certain page with TWIG?
I want this code to appear only when I visit one of the three paths below. How to do this in TWIG ?

```
/product/add/produit

```

or

```
/product/*/edit

```

or

```
/product/*/duplicate

```

The condition below does not work. In addition, you must put the three urls :

```
  {% if '/product/add/produit' in url %}
  <div class="modal fade" id="modal-product-list-tags" tabindex="-1" role="dialog" aria-labelledby="Liste des catégories">
    <div class="modal-dialog modal-sm" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
          <div class="modal-title h4" id="ProductListTags">Liste des catégories</div>
        </div>
        <div class="modal-body pb-0">
          {{ drupal_view('product_list_tags', 'block_1') }}
        </div>
      </div>
    </div>
  </div>
  {% endif %}

```

# Answer
> 1 votes
Place the views block in *Block Layout* and configure the visibility to show the block on the three paths.

Then use the block template of the placed views block to add the modal wrapper:

*block--views-block--product-list-tags-block-1.html.twig*

```
  <div class="modal fade" id="modal-product-list-tags" tabindex="-1" role="dialog" aria-labelledby="Liste des catégories">
    <div class="modal-dialog modal-sm" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
          <div class="modal-title h4" id="ProductListTags">Liste des catégories</div>
        </div>
        <div class="modal-body pb-0">

          <div{{ attributes }}>
            {{ content }}
          </div>

        </div>
      </div>
    </div>
  </div>

```

---
Tags: 8, theming
---


# Question
Title: How can I downgrade a module with Composer?
I updated the following module to its stable version :

https://www.drupal.org/project/commerce\_pricelist/releases/8.x-2.0-rc2

This module completely broke my site. There has been no database update. How can I revert to the RC2 version ?

# Answer
> 8 votes
* Open your `composer.json` and search for the line containing `drupal/commerce_pricelist`
* Replace the line by this one : `"drupal/commerce_pricelist": "2.0-rc2",`
* Execute `composer update drupal/commerce_pricelist`

Or simply run `composer require 'drupal/commerce_pricelist:2.0-rc2'` as suggested @4k4 in the comments

# Answer
> 0 votes
This situation is an example of why you should use version control. If you are using a version control system such as Git, you will not have to use `composer` itself to downgrade.

If you are using git, and you commit `composer.lock` and `composer.json` each time you update your modules with composer, then all you have to do is `git revert` the previous commit (or `git checkout` if you haven't committed the changes yet) and then run `composer install`.

---
Tags: 8, composer
---


# Question
Title: how a user can add another user but this is not an admin
I have 5 roles (*Admin*, *HRM*, *Registrar*, *Staff*, and *HOD*). *Admin* users will give special access to *HRM* users to add new users whose role is *Staff*.

*Registrar* and *HOD* roles shouldn't be shown in the *Add users* form. When I try to give permissions, *Registrar* and *HOD* roles are available in the form.

Can anyone help me in this?

# Answer
> 2 votes
There are two contrib modules which will do that for you:

Role Delegation

> This module allows site administrators to grant specific roles the authority to assign selected roles to users, without them needing the administer permissions permission.

RoleAssign

> RoleAssign specifically allows site administrators to further delegate the task of managing user's roles while withholding the Administer permissions permission.

The former is somewhat more configurable, and has the added benefit of a stable release.

If neither of those do what you're looking for, it's pretty easy to alter the user form manually. Here's a very contrived example:

```
function MYMODULE_form_user_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  if ($some_condition) {
    $form['account']['roles']['#options'] = [
      'foo' => 'Foo role',
      'bar' => 'Bar role',
    ];
  }
}

```

# Answer
> 0 votes
From a custom module you can build a custom form + a custom permission that you will give to the HRM users to access this form.

On form submit, gather the informations filled in the fields and create a Staff user programmatically.

---
Tags: 8, users
---


# Question
Title: How can I build an accordion without Javascript using the Field Group module?
I'm using the Field Group module to make accordions on my site, but it loads JQuery and slows the page down. Is there a way to do this without JS?

# Answer
Yes, you can use the HTML 5 details tag.

On the content type display administration page, create a field group.

For the **Format**, chose `HTML element`.

For **Field group label**, enter the text you want to show to click to display the rest of the text.

For the **Element**, enter `details`.

For **Show Label**, select Yes.

For **Label element**, enter `summary`.

To style with CSS, add extra CSS classes as needed.
> 1 votes

---
Tags: 8
---


title: How can I read Yaml files?

text:
# Question
Title: How can I read Yaml files?
I have been trying to figure out how to decode ( also try to encode) my YML file so I can have full control over on PHP array. I try this...

And as you can see, I did not get the information inside of the YML file.

My question is what I'm doing wrong ? Why is not showing me the information inside of `/core/modules/toolbar/toolbar.breakpoints.yml` file?

Here is code snippet...

```
use Drupal\Component\Serialization\Yaml;

$breakpointEncoded = Yaml::encode('/core/modules/toolbar/toolbar.breakpoints.yml');
var_dump($breakpointEncoded);

```

# Answer
> 16 votes
The arg to `decode` is:

> The raw data string to decode

So you need (e.g.):

```
$breakpointEncoded = Yaml::decode(file_get_contents('/PATH/TO/core/modules/toolbar/toolbar.breakpoints.yml'));

```

# Answer
> 3 votes
You can use the Symfony component as well in Drupal 8:

```
use Symfony\Component\Yaml\Yaml;

$file_path = DRUPAL_ROOT . '/core/modules/toolbar/toolbar.breakpoints.yml';
$file_contents = file_get_contents($file_path);
$ymldata = Yaml::parse($file_contents);

```

# Answer
> 1 votes
Even simplier now with a one-liner on Drupal 8.9 (the `decode` function has been removed from the Yaml Symfony Dependency utility class) :

```
use Symfony\Component\Yaml\Yaml;

$ymldata = Yaml::parseFile(DRUPAL_ROOT . '/core/modules/toolbar/toolbar.breakpoints.yml');

```

---
Tags: 8
---


# Question
Title: How to get instance of referenced entity?
I have a node object with image field named `field_image`. When I do

```
$node
  ->get('field_image')
  ->first()
  ->getValue()

```

I get array with some properties instead of entity object. The array looks like this:

```
'target_id' => string '8' (length=1)
'alt' => string '' (length=0)
'title' => string '' (length=0)
'width' => string '587' (length=3)
'height' => string '458' (length=3)
'_loaded' => boolean true
  '_accessCacheability' =>
    object(Drupal\Core\Cache\CacheableMetadata)[1092]
      protected 'cacheContexts' =>
        array (size=0)
          ...
      protected 'cacheTags' =>
        array (size=0)
          ...
      protected 'cacheMaxAge' => int -1

```

Do I have to manullay load the file entity using `target_id` or there is a way to automatically get referenced entity object from instance of `Drupal\image\Plugin\Field\FieldType\ImageItem`?

Why the referenced entity is not accessible via getter? It could be lazy loaded if it's not available immediately.

# Answer
The path to referenced entity is very long:

```
// $id = some node ID
// $field = field name for entity reference field
$node = Node::load($id);

/** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $referenceItem */
$referenceItem = $node->get($field)->first();

/** @var \Drupal\Core\Entity\Plugin\DataType\EntityReference $entityReference */
$entityReference = $referenceItem->get('entity');

/** @var \Drupal\Core\Entity\Plugin\DataType\EntityAdapter $entityAdapter */
$entityAdapter = $entityReference->getTarget();

/** @var \Drupal\Core\Entity\EntityInterface $referencedEntity */
$referencedEntity = $entityAdapter->getValue();

// At this point $referencedEntity is the referenced entity object.

```

Of course one can still get it via one liner call, but still, it is cumbersome and I wonder why `EntityReferenceItem` does not provide method that would return the reference entity object.

```
$referencedEntity = $node
  ->get($field)
  ->first()
  ->get('entity')
  ->getTarget()
  ->getValue()
;

```

Note: if you have php 8, you can use the nullsafe operator:

```
$referencedEntity = $node
  ?->get($field)
  ?->first()
  ?->get('entity')
  ?->getTarget()
  ?->getValue()
;

```

It's also worth noting that it's quite easy to get array of all referenced entities:

```
$node->get($field)->referencedEntities();

```

It works because for entity reference fields `$node->get($field)` returns instance of `EntityReferenceFieldItemList` which implements `referencedEntities()` method.
> 110 votes

# Answer
You can use `$node->field_image->entity`, if you want the first value.
> 43 votes

# Answer
For how to get an entity from a referenced field. Im agree with @SiliconMind about referencedEntities it return an array of entity objects keyed by field item deltas.

Just simple:

`$node->get('field_name')->referencedEntities();`

EntityReferenceFieldItemList::referencedEntities
> 23 votes

# Answer
What worked for me was:

```
$entity_id = $node->get('field_contact')->first()->getValue()['target_id'];

$entity = Node::load($entity_id)->toArray();

```

The other answers didn't produce the entity fields array I was expecting
> 13 votes

# Answer
`$ENTITY->FIELD_MACHINE_NAME->entity` returns the first item that referenced. but if you want to get value of the specified field in that entity use

```
$ENTITY->FIELD_MACHINE_NAME->entity->FIELDMACHINENAME_IN_REFERENCED_ENTITY->value

```

for example, if you want to get `hospital_key` of the `hospital` entity reference field on user entity. use

```
$user->field_hospital->entity->field_hospital_key->value

```
> 1 votes

# Answer
Here's a gist for a NestedEntityReference utility class I cooked up, modeled after the NestedArray utility class in Drupal core: https://gist.github.com/GuyPaddock/69ce592e2b58862da852afc5d7563c4a

This provides a way to access the targets of ER fields safely, even if the ER field is empty or refers to non-existent entities (e.g. if a target entity was deleted separately through an admin interface, such as in the case of https://www.drupal.org/project/entityreference/issues/2827177). As a bonus, this utility class bakes-in some development-time assertions so you can catch data structure/data issues early.

Example of usage (navigating from a node -\> media entity -\> URL to video file in the entity):

```
/** @var \Drupal\media\MediaInterface|null $video_media */
$video_media =
  NestedEntityReference::getTargetEntity(
    $my_node,
    'field_video',
    MediaInterface::class
  );

if ($video_media !== NULL) {
  /** @var \Drupal\file\FileInterface $video_file */
  $video_file =
    NestedEntityReference::getTargetEntity(
      $video_media,
      'field_file',
      FileInterface::class
    );

  $file_url = $video_file->createFileUrl()
}

```

Feedback on the Gist is welcome!
> 0 votes

---
Tags: 8, entities
---


title: Is it possible to import an SQL file?

text:
# Question
Title: Is it possible to import an SQL file?
I have an SQL database created from another application and I would like to add it to my existing Drupal 8 site. I didn't find a way to do so.

I came across the Data module, but I have no idea how to use it and I don't find any documentation.

Does anyone know how to achieve this?

# Answer
For usage on Data module please check external documentation https://www.drupal.org/node/2180593

There is another drupal 8 stable module that can be helpful to achieve the results. You can import the custom sql table into the drupal DB directly and can be used in Drupal Views directly.

https://www.drupal.org/project/view\_custom\_table
> 1 votes

# Answer
It really depends on what you want to import.

Migrate is the module suite of choice. See Drupal 8 external content migration translation problem for a multilingual setup ..
> 0 votes

---
Tags: database, importing-exporting
---


# Question
Title: How to Output Realtime Computed Field Value
I have created a computed field (computed\_field module) and I'd like the calculated value of this field to be computed on the fly for each of my views results.

Specifically, I have a start time, and and end time for each "Offer" (content type) in my view. I have created a computed field that determines whether the current time is between the start time, and end time, and then outputs a string value of "now" or "ending\_soon" or "starting\_soon" or "default" (if it's outside the parameters). I'm doing this all because I need to use the contents of this calculated field as a path variable for custom map markers in a google map (different 'pins' for offers/deals that are happening now, vs ones that are happen earlier or later in the day).

`inside my THEMENAME.theme file:`

```
function computed_field_field_now_compute($entity_type_manager, $entity, $fields, $delta)
{
  // from the database:
  $timestamp = $fields['field_business_dates'][0]['value'] ?? "";
  $endtimestamp = $fields['field_business_dates'][0]['end_value'] ?? "";

  $now = gmdate('Y-m-d\TH:i:s\Z');
  $utc = new DateTimeZone('UTC');
  $startDate = new DateTime($timestamp, $utc);
  $endDate = new DateTime($endtimestamp, $utc);
  $nowDate = new DateTime($now, $utc);
  $startSwatch = date_format($startDate, 'B');
  $endSwatch = date_format($endDate, 'B');
  $nowSwatch = date_format($nowDate,'B');
  $cutOffSwatch = 22; // Note: 41.6 = 1 hour;
  $endingSoonTime = $endSwatch - $cutOffSwatch;
  $startingSoonTime = $startSwatch - $cutOffSwatch;
  $value = "default";

  if ($nowSwatch >= $startSwatch && $nowSwatch <= $endSwatch) {
    if ($nowSwatch >= $endingSoonTime) {
      $value = "ending_soon";
    } else {
      $value = "now";
    }
  } else if ($nowSwatch >= $startingSoonTime && $nowSwatch <= $startSwatch) {
    $value = "starting_soon";
  } else {
    // return default value
  }
  return $value;
}

```

As these calculations are time-sensitive, I've turned off caching with the hope that the values are calculated on the fly and displayed in my view. But they are not displayed in views, and don't seem to display at all unless I save each individual node first. As I have over 6500 nodes...I don't see this as feasible. How can I ensure that when a view needs to display the calculated field, that the calculation is executed and rendered?

# Answer
**"How do I output a computed field value in real time?"**

The answer is that you cannot. The Computed Field module updates the value on entity save. So, to get the most recent value, you have to save the entity.

If you are trying to show a value that you compute in a view, computed field is a bad solution because you will have to re-save all the entities whenever you display the view, which is horrible for performance.

**Alternative solution idea**

Since you're doing calculations based on time, one option might be to use Views filters. Make a primary view that shows the default pins, and then embed or attach additional views that have filters that are set to find the pins for `ending_soon` and `starting_soon`.

If you need to override the Views filter calculations, you can do that in `hook_views_pre_view()`:

Here's a code example from one of my sites where I override the filter value to use "midnight for the logged-in user's timezone)."

```
function MYMODULE_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
  if ($view->id() === 'my_view' && ($display_id === 'my_display') {
    $filters = $view->display_handler->getOption('filters');
    if ($filters['field_datetime_target_value']) {
      $user_timezone = date_default_timezone_get();
      $current_timestamp = \Drupal::time()->getCurrentTime();
      $midnight_usertimezone_datestring = MYMODULE_get_midnight_datestring("$current_timestamp");

      $filters['field_datetime_target_value']['value']['value'] = $midnight_usertimezone_datestring;
    }
    $view->display_handler->overrideOption('filters', $filters);
  }
}

```
> 5 votes

---
Tags: 8, views, caching
---


title: Populating Select2 with AJAX

text:
# Question
Title: Populating Select2 with AJAX
I am trying to populate a selec2 field on open with AJAX in Drupal 8. In my hook\_form\_alter, I have added the following code:

```
  $form['#prefix'] = '<div id="form-ajax-wrapper">';
  $form['#suffix'] = '</div>';

  $form['field_author']['widget']['#ajax'] = [
    'callback' => 'myPopulate',
    'wrapper' => 'form-ajax-wrapper',
    'event' => 'select2:opening',
  ];

```

which correctly calls to the callback function when I try to open the drop-down list:

```
function reloadOptions(array $form, FormStateInterface $form_state){
  $query = \Drupal::entityQuery('node');
  $query->condition('type', 'author');
  $query->condition('status', 1);
  $nids = $query->execute();
  $nodes = Node::loadMultiple($nids);

  foreach ($nodes as $node) {
    $options[$node->id()] = FieldFilteredMarkup::create($node->getTitle());
  }

  $form['field_author']['widget']['#options'] = $options;

  return $form;
}

```

The query is ok, and the way in which the options are loaded also seems ok. However, when I click on the selec2 field to open it, the ajax throbber is shown but the drop-down list does not open.

Any ideas why is this happening?

Thanks!

**EDIT:** A capture of the behaviour of the selector2. As you can see, the drop-down list is not displayed after you click. However, if the ajax call is removed, it works correctly.

# Answer
In the following post, a working solution has been provided: https://www.drupal.org/forum/support/post-installation/2020-10-20/populating-select2-with-ajax

@No Sssweat also provided an alternative solution, where an update button was hidden in the form and was automatically activated with JS when a new item was added.

Many thanks for your time.
> 0 votes

# Answer
The ajax callback is pointing to the wrong function, should be:

```
callback' => 'reloadOptions',

```

It's better to make it return just the field rather than the entire form

```
$form['field_author']['#prefix'] = '<div id="author-ajax-wrapper">';
$form['field_author']['#suffix'] = '</div>';

$form['field_author']['widget']['#ajax'] = [
  'callback' => 'reloadOptions',
  'wrapper' => 'author-ajax-wrapper',
  'event' => 'select2:opening',
];

```

Adjust the reloadOptions fuction, so it returns just the specific field

```
return $form['field_author'];

```
> 0 votes

---
Tags: ajax
---


title: "drush cc" fails

text:
# Question
Title: "drush cc" fails
Does anyone know why Drush doesn't recognize the Drupal 7 installation when I run `drush cache:clear`?

It gives me the following error message.

> Command cache-rebuild requires Drupal core version 8+ to run.

`drush status` and `drush -d` give me the right root and right configuration.

I installed Drush with `composer require "drush/drush": "7.x-dev"`.

# Answer
> 1 votes
As @leymannx said in the comments you should better use drush 8 since it's the recommended version for a drupal 7 site (https://www.drush.org/install/#drupal-compatibility).

If `drush --version` returns something else than `7.x-dev` it means you're using another drush than the one you think. You can go in your website `/web` directory and execute `../vendor/bin/drush cc` to use the one you installed for this project.

---
Tags: drush, caching
---


# Question
Title: How can I programmatically add data to an address field?
I'm trying to import user data from a json file. So far I managed to import most of the information, but now I'm stuck on the address field (created with Address module for Drupal 8).
In the json file (exported from a Drupal 7 website), there is city, country code and country name.

How can I import this data into the new field (the machine name is *field\_address*)?

So far I tried using `Drupal::entityTypeManager`.

```
$values = array(
            'name' => $user["name"],
            'pass' => '',
            'status' => $user["status"],
            'mail' => $user["e_mail"],
            'field_first_name' => $user["first_name"],
            'field_last_name' => $user["last_name"],
            'field_address' => $city,
        );

        $userStorage = \Drupal::entityTypeManager()->getStorage('user');
        $userEntity = $userStorage->create($values);

```

It doesn't work: The address field stays empty.

Should I use the sub fields?

# Answer
> 2 votes
Thanks to 4k4 answer I was able to import the data. Here is the code:

```
$adressCountryCode = "NL";
$addressCity = "Amsterdam";

$values = [
  'name' => $user["name"],
  'pass' => '',
  'status' => $user["status"],
  'mail' => $user["e_mail"],
  'field_address' => [
     'country_code' => $adressCountryCode,
     'locality' => $addressCity,
  ],
];

```

# Answer
> 2 votes
If you have a field with multiple properties then use an extra array:

```
$values = [
  'name' => $user["name"],
  'pass' => '',
  'status' => $user["status"],
  'mail' => $user["e_mail"],

  'field_address' => [
    'first_name' => $user["first_name"],
    'last_name' => $user["last_name"],
    'city' => $city,
  ],
];

```

---
Tags: 8, entities, migrations
---


title: Access orders with own products

text:
# Question
Title: Access orders with own products
In my store, i am allowing customers to create products like Courses using Drupal 7 Commerce module, Is there a way using views or whatever method to enable the sellers on my site to see orders placed for their products?

Example: If Stanley is Selling Product1 and Product2, he will be able to see orders for product1 and product2, for now only admin can see the orders.

Your help will be highly appreciated.

# Answer
> 1 votes
Yes, you can use Views as Patrick suggests. Make it a View of Order entities with relationships joining Orders to Line Items and Line Items to the referenced Products. You can then apply a contextual filter to only show results whose Product uid matches the currently logged in user's uid.

A couple things to keep in mind...

1. Such a View would need to "Disable SQL rewriting" in its advanced settings, because it won't work so long as normal entity access control conditions are applied to the query.
2. You should include in the View itself all the information you need the course seller to see rather than trying to link them directly to a standalone page per Order. If that's what you want, you're going to actually need to hook into the access control system via custom code.

---
Tags: 7, commerce
---


# Question
Title: What is the difference between the "complete" and " checkout complete" order statuses?
I am using the Drupal 7 Commerce module. I would like to execute a special code when the payment of the order is completed.

What is the difference between *checkout complete* and *complete*?

I googled and I found suggestions for these hook implementations.

### First option

```
function mymodule_commerce_order_update($order) {
  if ($order->status == 'completed' ) {
    // ...
  }
}

```

### Second option

```
function my_module_commerce_order_presave($order) {
  if ($order->status == 'completed' ) {
    // ...
  }
}

```

###Third option

I found some suggestions to implement `hook_commerce_order_updated()`.

### Fourth option

```
function mymodule_commerce_checkout_complete($order) {
  if ($order->status == 'completed' ) {
    // ...
  }
}

```

# Answer
None of the above. You should be using `hook_commerce_payment_order_paid_in_full()`, which is always invoked the first time an order's balance drops to $0 or less.

Read more about it in commerce/modules/payment/commerce\_payment.api.php.
> 2 votes

---
Tags: 7, commerce, hooks
---


# Question
Title: Should I use t() in hook_update_N() or admin UI in a custom module?
## Background / motivation

Many implementations of `hook_update_N()` and `hook_install()` in contrib and core modules in D7 and D8/D9 contain calls to the `t()` function. In general, I think it is considered a "best practice" to use `t()` for all kinds of strings that will be displayed to any user unknown to us.

For custom site-specific modules, I often avoid the `t()`, if I know that the message will never be shown to anybody outside the developers. This applies especially to `hook_update_N()` and `hook_install()`. Sometimes I use `format_string()` instead, to get the replacement without the translation.

My own motivation is like this:

* I don't want these one-off strings to pollute the database and the translations UI. (not sure under which circumstances this would happen)
* The audience of an update hook is a small team of developers and devops, who are used to code comments written in English.
* I want the original English message to appear in logs, UI and CLI output, and in copy+paste snippets sent around between developers.
* I want developers / site builders to always see the same string.

Personally, I sometimes even go further, and don't use `t()` for names of custom field formatters, plugins etc.

I have a colleague who is not convinced by my pragmatic arguments, and wants to do things "by the book". He places high value on consistency, and wants to use `t()` everywhere.

Perhaps one argument in favor of `t()` is that it would make it easier to later copy parts of the code into a contrib or in-house module, without having to modify all the strings. Not very likely for a typical hook\_update\_N(), but the possibility exists.

## Question

Can it be "acceptable" as a team policy to not require `t()` for strings with an "internal" audience?

In which cases could it be acceptable to not use `t()`?

Is there any convention or good reason we could use to decide this, beyond personal preference?

## EDIT

There are some more specific questions hiding in the original question. I am putting these in a section clearly marked as "EDIT" to not be accused of a Heisenberging.

> In which cases could it be acceptable to not use `t()`?

Specific cases which could be discussed:

* Messages returned from `hook_update_N()`.
* Exceptions which are thrown in `hook_update_N()` on failure. (#817160 suggests to NOT translate exception messages.)
* Names of field formatters and other plugins defined in custom modules. An argument could be made that original names should not be translated.
* (`watchdog()` / `Drupal::logger()` calls are mentioned in a comment, but I am less interested in those atm)

The arguments for/against apply differently to these cases.

# Answer
Ever hear the expression "You Play Like You Practice"? If you get in the habit of NOT using `t()` for strings that are translatable just because it's only for your site ("practice"), then when it counts (i.e. "play") you will probably also leave out `t()`, because that's what you're used to.

There is really no downside to doing it correctly here. You're not saving anything or making any measurable difference in performance. The upside is that if you do it the same everywhere, you're not going to introduce a bug by leaving off `t()` where it is needed, and you can then also use the automated coding standards tools to check your code without seeing a lot of fails from your missing `t()` functions - that keeps these many fails from obscuring the few real problems you might have.
> 3 votes

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


# Question
Title: Exclude specific nodes from a view based on role permissions
I am using View access per node to hide certain nodes from the general public and allow specific roles to view it, which is simple and works like a charm.

The issue is that those nodes are shown, even when browsing with anonymous user. I can't find a way for the view to identify the "View access per node" status for each row.

I thought to change my approach; I was looking through the Comparison and Overview of Access Control modules, but any non-deprecated option available in Drupal 8 seems an overkill for this case.

# Answer
> 1 votes
Views does not respect `hook_node_access` which is what this module uses. Module creator should've used `hook_node_access_records` along with `hook_node_grants` instead.

You could try comment #3 as a workaround.

> ```
> /**
>  * Implements hook_views_pre_render().
>  */
> function example_views_pre_render(ViewExecutable $view) {
>   $user = \Drupal::currentUser();
>   $vapn_config = \Drupal::service('config.factory')->get('vapn.vapnconfig');
>   $vapn_node_types = $vapn_config->get('vapn_node_list');
>
>   foreach ($view->result as $key => $row) {
>     if ($row->_entity) {
>       $is_vapn_bundle = FALSE;
>       if ($bundle = $row->_entity->bundle()) {
>         $is_vapn_bundle = in_array($bundle, $vapn_node_types);
>       }
>
>       if (!$row->_entity->access('view', $user) && !$view->query->options['disable_sql_rewrite'] && $is_vapn_bundle) {
>         unset($view->result[$key]);
>       }
>     }
>   }
> }
>
> ```
>
> credit: ash2303

---
Tags: 8, views, nodes
---


title: Cookie Compliance and Google Analytics

text:
# Question
Title: Cookie Compliance and Google Analytics
I'm using Drupal 8.6.14 (going to upgrade soon) and I am trying to create a cookie consent page that actually works!

I've used many different modules like EU Cookie Compliance, GDPR Compliance and several others, but all of them fail to block Google Analytics cookies.

I even used a couple of patches on Google Analytics that I found in the community in order to support EU Cookie Compliance module, but all of them fail.

To be exact, EU Cookie Compliance seems to load the cookies as normal, then deleting them as the dialog of consent appears and then loading them all again once I pick any option.

All the other solutions seem not to work at all (I get the cookies any time the page loads). BTW, all the solutions I've found are for \<8 versions.

Any idea how I can get this done? Am I missing something?

# Answer
From the EU Cookie Compliance module's project page on drupal.org:

> If you want to conditionally set cookies in your module, there is a JavaScript function provided that returns `TRUE` if the user has given their consent:
>
> `Drupal.eu_cookie_compliance.hasAgreed()`
>
> For example, if you want to disable Google Analytics, you could do the following: http://drupal.org/node/1648286#comment-6145800
>
> Another example of how it can be used with Google Analytics is provided by dagomar in this comment.
>
> Here is another example showing how to set cookies after user clicks the accept button: http://drupal.org/node/1624876#comment-6111688

I've personally used this to prevent third-party code snippets from loading until after compliance is granted, by making a custom module and including the call to `hasAgreed()` in my module's JavaScript behaviors.

But as the first example above shows, a custom module is not necessary for Google Analytics in particular. You can simply add the following code to the **Advanced Settings-\>Custom JS** in Google Analytics:

```
if (!Drupal.eu_cookie_compliance.hasAgreed()){
window['ga-disable-UA-xxxx-1'] = true;
}

```

**EDIT (2020-02-23):**

It seems that you want to enforce extremely strict GDPR compliance, and prevent the cookies from being loaded at all unless consent has been granted.

You can do this with a custom module, leveraging the same `hasAgreed()` JavaScript behavior provided by the EU Cookie Compilance module.

First you need to remove the code snippet from your site completely and replace it with a placeholder.

If it's just one script in your HTML head, you might just edit `html.html.twig`.

If there are multiple scripts you need to prevent from running, it will be more work.

In my case, I replaced dozens of different third-party forms with an empty `<div>` element:

```
<div id="1234" class="thirdPartyFormWrapper"></div>

```

My custom JavaScript behavior looks for all the DOM elements with that class:

```
document.getElementsByClassName('thirdPartyFormWrapper');

```

The 4-digit number in the div ID corresponds to the unique third-party form ID for each form.

If consent has *not* been granted (or if the EU Cookie Compliance module is not installed or enabled, and `hasAgreed()` is not available) then my custom module uses the 4-digit ID to look up substitute content (saying, *e.g.*, "Please accept cookies to view the Yoyodyne, Inc. Gnomovision Mailing List Subscription Form," or whatever that particular form is.)

If consent *has* been granted, then my custom module uses the 4-digit ID to inject the JavaScript snippet for each of the third-party forms into the placeholder `<div>`.

Once the form snippet is injected, you can figure out how to handle the cookies. If consent is withheld, neither snippets nor cookies will load.

You can also use this technique to handle cookies for extremely strict GDPR compliance, following this pattern:

```
/**
 * Cookie handling for strict GDPR compliance
 */
  Drupal.behaviors.customCookieConsent = {
    attach: function (context, settings) {
      if (!Drupal.eu_cookie_compliance || !Drupal.eu_cookie_compliance.hasAgreed()) {
        // Bail out if cookie consent not given
        return;
      }
      // If cookie consent is given, set cookie (unless already set)
      if (!$.cookie('customConsentTime')){
        var consentTime = new Date();
        $.cookie('customConsentTime', consentTime.toISOString(), {expires: 3650});
      }
    },
  };

```

This approach is a bit more work, but it will prevent scripts and cookies from being loaded at all before consent is granted.

Finally, I should note that based on your comments here and on Drupal.org, I think you should do some research on "Drupal Behaviors" for your JavaScript. This will help you to avoid the "Uncaught ReferenceError: Drupal is not defined" message you have been seeing.
> 7 votes

# Answer
There is a new module for Drupal 8 and 9: COOKiES. It supports the modules Google Analytics and Google Tag Manager (and more). Maybe that's what you are looking for.

> ## COOKiES
>
> User consent management module for Drupal 8 and 9.
>
> The module enables existing third-party-integration modules continued to be used in compliance with the GDPR (of course without manipulating their code). It solves the basic problem that when using third-party-integration modules, the user must agree to the use of cookies (according to GDPR) before they are installed.
>
> IMPORTANT: No liability is assumed regarding compliance with the GDPR.
>
> The COOKiES module provides (with the Library Cookies JSR) a fully configurable user interface for user decisions. It also supports out-of-the-box some key third-party integration modules (especially those included in the Thunder distribution):
>
> * Google Analytics module
> * Google Tag Manager
> * Video embed, core:media module
> * Twitter media module
> * Instagram media module
> 4 votes

# Answer
This is how I solved the issue.

**Setup:**

* Drupal 8.9.6
* Eu Cookie Compliance 8.x-1.x-dev
* Google Analytics 3.1

Settings under `/admin/config/system/eu-cookie-compliance/settings`:

* **Consent method:** Opt-in. Don't track visitors unless they specifically give consent. (GDPR compliant)
* **Disable Javascripts:** `https://www.googletagmanager.com/gtag/js`

It behaves as expected:

* Google Analytics cookies are not loaded unless the user accepts cookies
* If the user rejects cookies, cookie banner is removed and no Google Analytics are placed in any subsequent page loads
> 1 votes

---
Tags: 8, cookies
---


title: Problem with cookie and session cache

text:
# Question
Title: Problem with cookie and session cache
I have a problem with the Drupal cache. The cache remembers session and cookie values. Everything works fine when I'm logged in or when I completely turn off any cache.

Is it possible to use cookies and avoid they are cached for anonymous users?

# Answer
> 0 votes
First of all, you need to add the correct cache context when rendering cookie/session values. See https://www.drupal.org/docs/drupal-apis/cache-api/cache-contexts. Then you should no longer need to completely turn off caching and sessions should work fine, anonymous and logged in.

Using non-session cookies server-side can be a problem with reverse proxies in general and the built-in *Internal Page Cache* in specific. Disable it by triggering the kill switch on pages depending on cookies without a session:

```
\Drupal::service('page_cache_kill_switch')->trigger();

```

Don't use this trigger too often, it disables all page caching. If you need it on the majority of your pages then uninstall the *Internal Page Cache*, but keep the *Internal Dynamic Page Cache* enabled. If the dynamic page cache is too slow then put a third-party page cache in front which has the options you need to manage your cookies.

---
Tags: 8, caching, cookies
---


# Question
Title: Contextual filter based on base level of taxonomy
I've been trying to get the following working for a couple of hours:

I have a views block, it displays a single content type. The content type has a taxonomy field. The taxonomy items are structured as this:

```
- option A
- option B
- option C
- - option C1
- - option C2
- - option C3
- option D

```

I use the values to categorize the content of the nodes. Each node has a single taxonomy value and displays the view block itself.

I want the view to display all nodes of the same taxonomy (this is no problem for A, B and D). But for content tagged as C1, C2 and C3 I want to show all content within the parent taxonomy, "option c".

I have tinkered with depth and parent fields for relations/contextual filters without success... don't really know what to try next and I can't find and decent resources with similar examples that solves my problem. I would prefer to solve it within the views UI if possible.

# Answer
If your content type contains a reference field to a taxonomy term with depth, you can use a view block with a normal filter, no contextual filter needed.

* Choose 'add filter' \> 'Has taxonomy terms (with depth)'
* Next screen, select the taxonomy vocabulary (I don't know what it's name is in your case, it should be the vocabulary in which 'option c' is a term) and set 'Depth' to 1, this will also select the first level of children
* Next screen, select the parent term for c1, c2 and c3 (in your case 'option c')

The block will now show all content where the reference field has been used to select option C or it's children.

I used this technique in this site: www.zorgsaamwonen.nl which uses 3 main themes with a lot of child themes.
> 0 votes

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


# Question
Title: How do I change the original language of a product type?
On a multilingual site with `commerce` project I've created a product type while having one language selected as default but now I want to switch it to a different one. On `/admin/commerce/config/product-types/producttypemachinename/edit/translate` I see what the current original language is oviously but I can't edit it on `/admin/commerce/config/product-types/producttypemachinename/edit`. Is it ok if I edit it in the database? Does anyone have some ready SQL statements or at least know where it's stored?

I think product type is a Configuration Entity and I'm now searching where these are stored in the database.

I've found **something** in

```
SELECT * from `drupal_config` WHERE name LIKE "commerce_product.commerce_product_type%";
SELECT * from `drupal_key_value` WHERE collection="config.entity.key_store.commerce_product_type";

```

but the data columns there are `longblob`.

Update: with the next SQL I can confirm that original language is stored in the "config" table:

```
SELECT collection,name,CAST(data as CHAR) from `drupal_config` WHERE name LIKE "commerce_product.commerce_product_type%";

```

Update: even after editing the longblob value and setting langcode to `en` it's still not English original in the admin interface.

Update: just had to clear the cache, it's now changed.

# Answer
Since I haven't found any easy way I had to edit it in the database manually and clear the cache after that.

### Update:

It's easy with exporting at

`/admin/config/development/configuration/single/export` and importing at

`/admin/config/development/configuration/single/import`
> 0 votes

---
Tags: 8, commerce, i18n-l10n
---


# Question
Title: How do I edit serialized values in "config" and "key_value" tables?
While trying to switch original language of a Commerce product type I've encountered *longblob* serialized data in *config* and *key\_value* database tables.

Is there a quick way to edit them, possibly without writing a lot of PHP code?

# Answer
> 2 votes
Don't edit the serialized config, edit the config as YAML. Try for example

`drush cedit`

See other options (UI and command line) here: https://www.drupal.org/docs/configuration-management

# Answer
> 1 votes
### Export-import way

(added as a later edit)

It's possible that the values you need can be exported at

`/admin/config/development/configuration/single/export`

Then edited and re-imported at

`/admin/config/development/configuration/single/import`

### SQL way

Do not try it unless you can afford losing your database and you really understand what you are doing.

I've managed to edit it by using these SQL commands:

```
select hex('serialized string that you got with CAST(data as CHAR) here');
UPDATE `drupal_config` SET data=0xHEXVALUEFROMPREVIOUSSTEP WHERE name="commerce_product.commerce_product_type.yourproducttypemachinename";

```

The SQL does not expect there to be any translated values, select with `WHERE name="commerce_product.commerce_product_type.yourproducttypemachinename"` should return only one row.

---
Tags: 8, database
---


# Question
Title: Translate configuration values in custom webform handler
I created a Custom Webform Handler, which uses the email and name data from the form input to subscribe the user to a newsletter service through the vendors API.

Ich created a configuration form with this handler, where I can input the API key and the mailing list of the newsletter service.

This all works well up until the point where I want to translate the webform to a different language. I need to have a different configuration for the mailing list in German than in English.

I checked the code of the handlers that come with the webform module, but I can't figure out, how to define, which configuration field values should be translated. I need to have the `newsletter_list` form element to be translated.

Can anyone help?

This is my shortened code

```
<?php
/**
  * @file custom_webform_handler/src/Plugin/WebformHandler/NewsletterWebformHandler.php
  */
namespace Drupal\custom_webform_handler\Plugin\WebformHandler;

use Drupal\webform\Plugin\WebformHandlerBase;

// ...
/**
 * ´Newsletter Webform handler.
 *
 * @WebformHandler(
 *   id = "newsletter",
 *   label = @Translation("Newsletter Subscription"),
 *   category = @Translation("Subscription"),
 *   description = @Translation("Subscribe to Newsletter"),
 *   cardinality = \Drupal\webform\Plugin\WebformHandlerInterface::CARDINALITY_SINGLE,
 *   results = \Drupal\webform\Plugin\WebformHandlerInterface::RESULTS_IGNORED,
 *   submission = \Drupal\webform\Plugin\WebformHandlerInterface::SUBMISSION_REQUIRED,
 * )
 */

class NewsletterWebformHandler extends WebformHandlerBase
{
  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'newsletter_apikey' => '',
      'newsletter_list' => '',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $form['newsletter'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Newsletter settings'),
    ];
    $form['newsletter']['newsletter_apikey'] = [
      '#type' => 'textfield',
      '#title' => $this->t('API key'),
      '#default_value' => $this->configuration['newsletter_apikey'],
      '#required' => TRUE,
    ];
    $form['newsletter']['newsletter_list'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Mailing List'),
      '#default_value' => $this->configuration['newsletter_list'],
      '#required' => TRUE,
    ];

    return $this->setSettingsParents($form);

  }
  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    parent::submitConfigurationForm($form, $form_state);
    // ...
  }

// ...
}

```

I read that I need to have a schema for doing this, so I tried adding one, but it didn't change anything

```
# file custom_webform_handler/config/schema/custom_webform_handler.schema.yml
webform.handler.newsletter:
  type: mapping
  label: 'Newsletter'
  mapping:
    newsletter_list:
      label: 'Mailing List'
      type: string

```

# Edit

To make it more clear: I created a Handler that has this configuration form

The connection settings are the ones that need to be translated

When I go to the translation page of my webform, I can translate the Email-Handler settings, but not my custom Newsletter Subscription handler settings

# Answer
> 2 votes
I did provide the wrong type. It should be `label` and not `string`

```
webform.handler.newsletter2go:
  type: mapping
  label: 'Newsletter2go'
  mapping:
    newsletter2go_formcode:
      label: Formcode
      type: label

```

# Answer
> 0 votes
You should be able to add translations in /config/install/language/\[langcode\]/config.name.yml

so `/config/install/language/fr/custom_webform_handler.handler.newsletter.yml`

But the whole config translation of not really well supported/buggy, you need to make sure you're default language is EN! If not, cli\_language may help, cli language needs to be set to EN, and your module needs to be installed via cli (fe. drush).

---

**Update:** To be able to translate your custom configuration you need to provide something, like a custom\_webform.config\_translation.yml:

custom\_webform.newsletter\_settings\_form: base\_route\_name: \[not sure about the route ..\] names: \- webform.handler.newsletter

Dunno about which route to choose ... maybe entity.webform.settings\_form

See also: https://www.drupal.org/docs/user\_guide/en/language-config-translate.html

---
Tags: 8, webforms, i18n-l10n
---


# Question
Title: After moving a module to another folder , i cannot clear reminiscent module paths
I have moved the contrib module pagerer from

> /sites/my\_site/modules

to

> /modules/contrib

It breaks the site as some files are unaccessible

> /platforms/drupal8-development/sites/recherche-dev.univ-amu.fr/modules/pagerer/src/Entity/PagererPreset.php): failed to open stream: No such file or directory in require()

i guess i would need to perform a registry rebuild but i don't know how.

drush rr outputs

> The drush command 'rr' could not be found

# Answer
i have ended up putting in local.settings.php

```
   /**
 * Class Loader.
 *
 * If the APC extension is detected, the Symfony APC class loader is used for
 * performance reasons. Detection can be prevented by setting
 * class_loader_auto_detect to false, as in the example below.
 */
$settings['class_loader_auto_detect'] = FALSE;

```
> 1 votes

# Answer
Drupal stores a cached version of the container at the cache\_container table. This table contains, among other things, the list of module paths.

For most cases running `drush cr` should be enough but if you see that even `drush cr` crashes then you will need to create a database update like this in an already installed module:

```
/**
 * Clears all caches after moving modules from modules to modules/contrib.
 */
function mymodule_update_8100(&$sandbox) {
  drupal_flush_all_caches();
}

```

And then run `drush updb -y`.
> 0 votes

---
Tags: 8
---


# Question
Title: Is checking the value of $order->status sufficient to understand when an order has been completed?
If I want to use this hook in order to execute a code when the order is complete.

```
function hook_commerce_order_update($order) {
  if ($order->status == 'completed') {
    // ...
  }
}

```

Is this condition sufficient, or should I add the following in order to prevent the confusion with the complete status that belongs to the checkout state?

```
 if ($order->status != $order->original->status) {
    $status = commerce_order_status_load($order->status);
    $state = commerce_order_state_load($status['state']);
    if (($state['name'] == 'completed') && ($order->status == 'completed')) {
      // ...
    }
  }

```

# Answer
> 0 votes
All the checkout order statuses are prefixed with `checkout_`, so there is no need to check the state. Just bear in mind that in Commerce 1.x, an order may be moved into and out of that status multiple times. If you need to ensure an operation only occurs *once* per order, you can follow the core precedent of logging the timestamp for your operation in the `$order->data` array.

---
Tags: 7, commerce
---


# Question
Title: Unable to display message when account is flagged
I have this code in my sub theme :

**bootstrap\_subtheme\_front\_office\_old.theme**

```
<?php

/**
 * Implements hook_preprocess_HOOK() for user.html.twig.
 */
function bootstrap_subtheme_front_office_old_preprocess_user(&$variables) {
  $flag_id = 'flag_role_association';
  $flag_service = \Drupal::service('flag');
  $flag = $flag_service->getFlagById($flag_id);
  $user_to_flag = $variables['user'];
  $flag_status = $flag_service->getFlagging($flag, $user_to_flag);
  $variables['is_flagged_role_association'] = $flag_status;

  $flag_id = 'flag_role_pop_up_store';
  $flag_service = \Drupal::service('flag');
  $flag = $flag_service->getFlagById($flag_id);
  $user_to_flag = $variables['user'];
  $flag_status = $flag_service->getFlagging($flag, $user_to_flag);
  $variables['is_flagged_role_pop_up_store'] = $flag_status;

  $flag_id = 'flag_role_artisan';
  $flag_service = \Drupal::service('flag');
  $flag = $flag_service->getFlagById($flag_id);
  $user_to_flag = $variables['user'];
  $flag_status = $flag_service->getFlagging($flag, $user_to_flag);
  $variables['is_flagged_role_artisan'] = $flag_status;
}

```

And this templates :

**user--account-roles.html.twig**

```
<div class="card p-4 overflow-hidden shadow rounded bg-white">

  <div class="alert alert-light" role="alert">
    <p class="text-center">Vous trouverez sur cette page les différents types de compte disponible.</p>
    <p class="text-center">Chaque type de compte vous donne droit à des autorisations au sein de la plateforme.</p>
    <p class="text-center font-weight-bold">Vous devez avoir un numéro de SIRET.</p>
    <p class="text-center">Les modifications peuvent prendre 24 heures pour ếtre appliquées.</p>
  </div>

  <p>Les associations sont destinées aux comités des fêtes, offices de tourisme, ... qui organisent des événements. Vous pourrez y publier divers types de contenu.</p>
  {% if 'association' in user.getroles %}
    <div><i class="fas fa-circle text-success"></i> Votre compte association est actif.</div>
  {% elseif 'association' not in user.getroles and is_flagged_role_association %}
    <div><i class="fas fa-circle text-warning"></i> Votre compte association est en attente.</div>
  {% elseif 'association' not in user.getroles and not is_flagged_role_association %}
    <div><i class="fas fa-circle text-danger"></i> Votre compte association est inactif.</div>
    {{ content.flag_role_association }}
  {% endif %}

  <span class="border-top mt-4 mb-4"></span>

  <p>Les boutiques éphémères vous permettent d'exposer les créations des artisans présents sur la plateforme (pas de vente en ligne).</p>
  {% if 'pop_up_store' in user.getroles %}
    <div><i class="fas fa-circle text-success"></i> Votre compte boutique éphémère est actif.</div>
  {% elseif 'pop_up_store' not in user.getroles and is_flagged_role_pop_up_store %}
    <div><i class="fas fa-circle text-warning"></i> Votre compte boutique éphémère est en attente.</div>
  {% elseif 'pop_up_store' not in user.getroles and not is_flagged_role_pop_up_store %}
    <div><i class="fas fa-circle text-danger"></i> Votre compte boutique éphémère est inactif.</div>
    {{ content.flag_role_pop_up_store }}
  {% endif %}

  <span class="border-top mt-4 mb-4"></span>

  <p>Si vous êtes artisans, nous serions ravis de vous accueillir sur notre marketplace. Nous facturons une commission de 10% sur chaque vente. Vous recevrez une facture à chaque début de mois, si vous réalisez des ventes le mois précédent. Plus d'infos sur <a href="/node/271">cette page</a>.</p>
  <p>Pas de vente = Rien à payer</p>
  {% if 'marchand' in user.getroles %}
    <div><i class="fas fa-circle text-success"></i> Votre compte artisan est actif.</div>
  {% elseif 'marchand' not in user.getroles and is_flagged_role_artisan %}
    <div><i class="fas fa-circle text-warning"></i> Votre compte artisan est en attente.</div>
  {% elseif 'marchand' not in user.getroles and not is_flagged_role_artisan %}
    <div><i class="fas fa-circle text-danger"></i> Votre compte artisan est inactif.</div>
    {{ content.flag_role_artisan }}
  {% endif %}

</div>

```

When I go to a user account page, I have a blank page where it says "The website encountered an unexpected error. Please try again later."

In my Drupal logs, I have the PHP error below.

How can I correct this ?

```
Type    php
Date    Vendredi, 6 novembre, 2020 - 04:25
Utilisateur administrateur
Emplacement https://dev.example.com/user/1
Référent
Message TypeError : Argument 1 passed to Drupal\flag\FlagService::getFlagging() must implement interface Drupal\flag\FlagInterface, null given, called in /home/ubuntu/www-example-com/web/themes/custom/bootstrap_subtheme_front_office_old/bootstrap_subtheme_front_office_old.theme on line 11 dans Drupal\flag\FlagService->getFlagging() (/home/ubuntu/www-example-com/web/modules/contrib/flag/src/FlagService.php ligne 84)
#0 /home/ubuntu/www-example-com/web/themes/custom/bootstrap_subtheme_front_office_old/bootstrap_subtheme_front_office_old.theme(11): Drupal\flag\FlagService->getFlagging()
#1 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/Theme/ThemeManager.php(287): bootstrap_subtheme_front_office_old_preprocess_user()
#2 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/Render/Renderer.php(431): Drupal\Core\Theme\ThemeManager->render()
#3 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/Render/Renderer.php(200): Drupal\Core\Render\Renderer->doRender()
#4 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php(226): Drupal\Core\Render\Renderer->render()
#5 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/Render/Renderer.php(573): Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}()
#6 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php(227): Drupal\Core\Render\Renderer->executeInRenderContext()
#7 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php(117): Drupal\Core\Render\MainContent\HtmlRenderer->prepare()
#8 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php(90): Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse()
#9 [internal function]: Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray()
#10 /home/ubuntu/www-example-com/web/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func()
#11 /home/ubuntu/www-example-com/vendor/symfony/http-kernel/HttpKernel.php(156): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
#12 /home/ubuntu/www-example-com/vendor/symfony/http-kernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw()
#13 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\Component\HttpKernel\HttpKernel->handle()
#14 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle()
#15 /home/ubuntu/www-example-com/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
#16 /home/ubuntu/www-example-com/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\page_cache\StackMiddleware\PageCache->pass()
#17 /home/ubuntu/www-example-com/web/core/modules/ban/src/BanMiddleware.php(50): Drupal\page_cache\StackMiddleware\PageCache->handle()
#18 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\ban\BanMiddleware->handle()
#19 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(52): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
#20 /home/ubuntu/www-example-com/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
#21 /home/ubuntu/www-example-com/web/core/lib/Drupal/Core/DrupalKernel.php(708): Stack\StackedHttpKernel->handle()
#22 /home/ubuntu/www-example-com/web/index.php(19): Drupal\Core\DrupalKernel->handle()
#23 {main}
.
Severity    Erreur

```

These are "Global" flags, here is the machine name (screenshot). Only the end of the machine name changes depending on the type of flag.

**UPDATE**

# Answer
There's no need to implement three times your flag service, once is enough (same for your user to flag).

The error says `Message TypeError : Argument 1 passed to Drupal\flag\FlagService::getFlagging() must implement interface Drupal\flag\FlagInterface, null given` which means your `$flag` variable is null. Most likely the flag service is unable to retrieve a flag for the flag ids you're giving (`flag_role_association`, `flag_role_pop_up_store`, `flag_role_artisan`). Are you sure about those values ?

I would personnaly rewrite your hook as follow ; it should remove the error and display the page but I am not sure it will completely solve your problem as long as `$flag` will be null.

```
<?php

/**
 * Implements hook_preprocess_HOOK() for user.html.twig.
 */
function bootstrap_subtheme_front_office_old_preprocess_user(&$variables) {
  $flag_service = \Drupal::service('flag');
  $user_to_flag = $variables['user'];

  $flag_ids = [
    'flag_role_association' => 'is_flagged_role_association',
    'flag_role_pop_up_store' => 'is_flagged_role_pop_up_store',
    'flag_role_artisan' => 'is_flagged_role_artisan',
  ];

  foreach ($flag_ids as $flag_id => $var_flag) {
    if ($flag = $flag_service->getFlagById($flag_id)) {
      if ($flag_status = $flag_service->getFlagging($flag, $user_to_flag)) {
        $variables[$var_flag] = $flag_status;
      }
    }
  }
}

```
> 3 votes

---
Tags: 8, theming, users, flags
---