title: Web form Custom element

text:
# Question
Title: Web form Custom element
I created a custom webform element, It works perfectly, but when I add a table form element, It is not showing

My Code :

```
    <?php

namespace Drupal\webform_mapper\Plugin\WebformElement;

use Drupal\Component\Utility\NestedArray;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Form\FormStateInterface;
use Drupal\webform\Plugin\WebformElementBase;
use Drupal\webform\WebformSubmissionInterface;

/**
 * Provides a 'webform_example_element' element.
 *
 * @WebformElement(
 *   id = "webform_example_element",
 *   label = @Translation("Webform example element"),
 *   description = @Translation("Provides a webform element example."),
 *   category = @Translation("Example elements"),
 * )
 *
 * @see \Drupal\webform_example_element\Element\WebformExampleElement
 * @see \Drupal\webform\Plugin\WebformElementBase
 * @see \Drupal\webform\Plugin\WebformElementInterface
 * @see \Drupal\webform\Annotation\WebformElement
 */
class WebformExampleElement extends WebformElementBase {

  use DependencySerializationTrait;

  /**
   * {@inheritdoc}
   */
  protected function defineDefaultProperties() {
    return [
        'multiple' => '',
        'size' => '',
        'minlength' => '',
        'maxlength' => '',
        'placeholder' => '',
        'source_webform' => '',
        'target_elements' => [],
        'reference_element' => [],
        'reference_element_2' => [],
      ] + parent::defineDefaultProperties();
  }

  /* ************************************************************************ */

  /**
   * {@inheritdoc}
   */
  public function prepare(array &$element, WebformSubmissionInterface $webform_submission = NULL) {
    parent::prepare($element, $webform_submission);

    // Here you can customize the webform element's properties.
    // You can also customize the form/render element's properties via the
    // FormElement.
    //
    // @see \Drupal\webform_example_element\Element\WebformExampleElement::processWebformElementExample
  }

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

    $form['mapped_container'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Auto complete data element settings'),
      '#open' => TRUE,
      '#weight' => -10,
      '#attributes' => [
        'id' => ['webform-mapped-container'],
      ],
    ];

    $query = \Drupal::entityQuery('webform');
    $results = $query->execute();

    $form['mapped_container']['source_webform'] = [
      '#type' => 'select',
      '#title' => $this->t('Source webform'),
      '#options' => $results,
      '#ajax' => [
        'callback' => [$this, 'updateFormCallback'],
        'wrapper' => 'webform-mapped-container',
      ],
    ];

    $id = $form_state->getValue('source_webform') != NULL ? $form_state->getValue('source_webform') : '';
    if (!empty($id)) {
      $form['mapped_container']['reference_element'] = [
        '#type' => 'select',
        '#title' => $this->t('Reference Element'),
        '#options' => ['t1', 't2'],
      ];
      $form['mapped_container']['reference_element_2'] = [
        '#type' => 'select',
        '#title' => $this->t('Reference Element'),
        '#options' => ['t5', 't2'],
      ];

      $form['mapped_container']['target_elements'] = [
        '#type' => 'table',
        '#title' => $this->t('Map Source Elements to Target Elements'),
        '#header' => [
          $this
            ->t('Source Webform Elements'),
          $this
            ->t('Target Webform Elements'),
        ],
      ];

      for ($i = 1; $i <= 4; $i++) {
        $form['mapped_container']['target_elements'][$i]['name'] = [
          '#type' => 'textfield',
          '#title' => $this
            ->t('Name'),
          '#title_display' => 'invisible',
        ];
        $form['mapped_container']['target_elements'][$i]['phone'] = [
          '#type' => 'tel',
          '#title' => $this
            ->t('Phone'),
          '#title_display' => 'invisible',
        ];
      }

    }

    return $form;
  }

  public function updateFormCallback(array $form, FormStateInterface $form_state) {
    $id = $form_state->getValues()['properties']['source_webform'];
    $form_state->setValue('source_webform', $id);
    $triggering_element = $form_state->getTriggeringElement();
    $parents = array_slice($triggering_element['#array_parents'], 0, -1);
    $element = NestedArray::getValue($form, $parents);
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function preview() {
    return [];
  }

}

```

# Answer
> 0 votes
Solution : add the #access attribute

```
$form['mapped_container']['target_elements'] = [
      '#type' => 'table',
      '#title' => $this->t('Map Source Elements to Target Elements'),
      '#header' => [
        $this
          ->t('Source Webform Elements'),
        $this
          ->t('Target Webform Elements'),
      ],
      '#access' => TRUE,
    ];

    for ($i = 1; $i <= 4; $i++) {
      $form['mapped_container']['target_elements'][$i] = [
        '#access' => TRUE,
        'c1' => [
          '#access' => TRUE,
          '#type' => 'textfield',
          '#title' => $this->t('Name'),
        ],
        'c2' => [
          '#access' => TRUE,
          '#type' => 'tel',
          '#title' => $this->t('Phone'),
          '#title_display' => 'invisible',
        ],
      ];
    }

```

---
Tags: webforms
---


# Question
Title: What can we do to remedy the unrecoverable error we encounter for any Drush command?
We used Drush on our server without any problems up until now. Actually we didn't do / change anything relating to Drush.

But now, on every Drush command we issue, we only get an error like so:

> Drush command terminated abnormally due to an unrecoverable error.

Same error also occurs for `Drush status`. Only `drush --version` shows "Drush version: 6.6.0".

We installed drush via Composer. And the server is already restarted.

What can we do about this problem, which is a huge problem for us?

# Answer
> 1 votes
Make sure your Drush commands are issued from the appropriate subdirectory of your website (change to the directory where your Drupal site is installed and try again).

Since your question did not specify that, it "might" be the reason why ALL your DRUSH commands are failing ...

Refer to this issue for other possible causes (things you may want to check).

If you recently enabled contributed and/or custom modules, try to temporary disable them to check if the Drush issue gets resolved by doing so.

# Answer
> 1 votes
I was getting :

warning Drush command terminated abnormally.

And after long hours, i realized that drush was crashing as a results of

```
 Allowed memory size of 134217728 bytes exhausted (tried to allocate 40960 bytes)

```

Had to scroll up to pages and pages of debug info before i saw that.

If this is your problem, you can change the below value in php.ini to **512M** and try the drush command again.

```
memory_limit = 128M

```

Instead of changing the value in **/etc/php.ini,** a better solution is to add **drush.ini** file with the value to your path (see below)

1. create drush.ini in your path such as (/usr/local/bin/drush.ini) see its contents below. Change permissions so the user running drush can load the file.
2. add this to your ~/.bashrc (export PHP\_INI\_SCAN\_DIR=:/usr/local/bin) then (source ~/.bashrc) to reload it

content of drush.ini can be

\[PHP\]

memory\_limit = 512M

**Note**: drush.ini might be ignored even after setting as above so double check.

* See loaded config files :$ PHP\_INI\_SCAN\_DIR=:/usr/local/bin/ php --ini
* See memory limit assigned to the script:$ drush php:eval "echo ini\_get('memory\_limit');"

***Background***: How to have drush specific config values rather than changing php.ini

https://github.com/drush-ops/drush/issues/3294#issuecomment-618962852

https://github.com/drush-ops/drush/issues/3294

---
Tags: drush
---


# Question
Title: How to create a custom layout with for a view, I have tried to print the fields but nothing works I created the template but cant display rows
I have a view in drupal 7 but I cant show up the rows, I created a template for the row-style-output but nothing happen.

```
<?php

/**
 * @file
 * Default simple view template to all the fields as a row.
 *
 * - $view: The view in use.
 * - $fields: an array of $field objects. Each one contains:
 *   - $field->content: The output of the field.
 *   - $field->raw: The raw data for the field, if it exists. This is NOT output safe.
 *   - $field->class: The safe class id to use.
 *   - $field->handler: The Views field handler object controlling this field. Do not use
 *     var_export to dump this object, as it can't handle the recursion.
 *   - $field->inline: Whether or not the field should be inline.
 *   - $field->inline_html: either div or span based on the above flag.
 *   - $field->wrapper_prefix: A complete wrapper containing the inline_html to use.
 *   - $field->wrapper_suffix: The closing tag for the wrapper.
 *   - $field->separator: an optional separator that may appear before a field.
 *   - $field->label: The wrap label text to use.
 *   - $field->label_html: The full HTML of the label to use including
 *     configured element type.
 * - $row: The raw result object from the query, with all data it fetched.
 *
 * @ingroup views_templates
 */
?>

  <?php foreach ($fields as $id => $field): ?>
  <?php if (!empty($field->separator)): ?>
    <?php print $field->separator; ?>
  <?php endif; ?>

  <?php print $field->wrapper_prefix; ?>
    <?php print $field->label_html; ?>
    <?php print $field->content; ?>
  <?php print $field->wrapper_suffix; ?>
<?php endforeach; ?>

```

# Answer
According to your template name, it seems there is a mismatch between your template name and its content. You are using a template named `views-view--blog-page.tpl.php` but with the content of a `views-view-fields.tpl.php` file.

According to your Views template suggestions, here is how your templates shall be organised (from the most global one to the most accurate):

* `views-view--blog--page.tpl.php` should override Views module `views-view.tpl.php` file. This is the global template of your View. In it, you can find $rows variable, which is the global result of your view. But you don't have access to each row details.
* `views-view-unformatted--blog--page.tpl.php` should override `views-view-unformatted.tpl.php`. Here, you can alter your output at row level (e.g. Add a element around each row). Still no access to the details of each row.
* `views-view-fields--blog--page.tpl.php` should override `views-view-fields.tpl.php`. It is the template used to output a row content (fields-level). This is the one to use if you wish to alter the output of your rows content.
* `views-view-field--blog--page.tpl.php` should override `views-view-field.tpl.php`. Most accurate level. It is the output of each field inside each row.

Now, you just need to pick the Views template suiting your needs, override it with the right name and you should be fine. :-)
> 0 votes

---
Tags: 7, views
---


title: Search is very slow for certain roles

text:
# Question
Title: Search is very slow for certain roles
I'm a bit lost here. I have a strange problem and don't know where to begin. I use the core search function on a website I build. When I am logged in as administrator this search function is working and is very fast. When I log in as one of the users (with other role and permissions) the search function is very slow and sometimes even ending up in a 504 page.

I can't think of a good starting point to find out what the problem is. Who can help me think of a good debugging path?

# Answer
> 0 votes
The answer to your question about how to debug: you have to use a technique called “profiling”. By far the easiest PHP profiler to use is https://www.blackfire.io/. I’ve used it and I recommend it. Xdebug can profile too but by there is a lot to understand to use it https://xdebug.org/docs/profiler

---
Tags: search, 9, debugging
---


# Question
Title: Fatal error: "isEven" is an invalid render array key /web/core/lib/Drupal/Core/Render/Element.php
we have this code in template.theme but when we go to view the web, the page show a error as this: "isEven" is an invalid render array key /web/core/lib/Drupal/Core/Render/Element.php . I dont understand very good Drupal and as works it.

```
function fcjc_bootstrap_preprocess_paragraph(&$variables)
{
  /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
  $paragraph = $variables['paragraph'];
  if ($paragraph->getType() === 'image_text_full_width' || $paragraph->getType() === 'imaxe_texto_biografia_') {
    $variables['isEven'] = $variables['elements']['isEven'];
  }
}

function fcjc_bootstrap_preprocess_field__field_image_text_section(&$vars)
{
  foreach ($vars['items'] as $delta => &$item) {
    $classname = ($delta % 2 == 0 ? 'even' : 'odd');
    $item['attributes']->setAttribute('class', $classname);
    $item['content']['isEven'] = ($delta % 2 == 0);
    }
}

```

In paragraph.twig I have this: `<div class=" image col-sm-4 col-xs-12 {% if isEven %}right-shadow{% else %}left-shadow col-sm-push-8{% endif %}">`

Can Somebody can help me? please. Thx

# Answer
It's what @Beau wrote in the comment. You have to put a ***#*** in the array key.

The code should be:

```
function fcjc_bootstrap_preprocess_paragraph(&$variables)
{
  /** @var \Drupal\paragraphs\Entity\Paragraph $paragraph */
  $paragraph = $variables['paragraph'];
  if ($paragraph->getType() === 'image_text_full_width' || $paragraph->getType() === 'imaxe_texto_biografia_') {
    $variables['isEven'] = $variables['elements']['#isEven'];
  }
}

function fcjc_bootstrap_preprocess_field__field_image_text_section(&$vars)
{
  foreach ($vars['items'] as $delta => &$item) {
    $classname = ($delta % 2 == 0 ? 'even' : 'odd');
    $item['attributes']->setAttribute('class', $classname);
    $item['content']['#isEven'] = ($delta % 2 == 0);
    }
}

```
> 0 votes

---
Tags: theming
---


# Question
Title: View data export with custom table doesn't work if user is not admin
I'm working on a Drupal 9 website displaying custom table data and I need to provide CSV/XLS export links for it.
For the moment, I've defined a view consuming the custom table data thanks to the Views Custom Table module and it works fine. I've installed the Views Data Export module and configured a display to export data as CSV. This display is attached to the base display.
The CSV button is show on the view, and when I'm logged in as admin, everything works fine. When I'm just an authenticated user, and I click on the button, the display attached to the CSV export is rendered and exported in CSV (so there is all the HTML in the file).

I think it is a permission issue: Export uses REST core module and this one is performing permission check on the entity (for example, user is able to access the entity). In my view, there is no entity because data comes from the *View Custom Table* module (through `hook_data()`).

I'm not sure if there is a simple solution, or if I need to define my own endpoint (and find a solution to keep exposed filters). Moreover, the *Views Data Export PHPExcel* module is not available for Drupal 8 and Drupal 9.

# Answer
> 1 votes
If what you have done works when logged in as user 1 (Adminstrator), then that sounds like you need to tweak certain permissions and clear cache for it to take effect for the other "users" or "roles".

To test it out, i would create a test user and a role called "test role". Then make sure, you assign the test user to the test role. Then make sure, you give the "test role" what the module requires.... i see below in docs of view export table

You can also check if authenticated user/role has the following checked for it, if you don't want create the test user/role(/admin/people/permissions).

The below permissions come with the module, i suppose and you will see if after module install and cache clear etc.

##

* Configure user permissions in Administration » People » Permissions:

+ Add custom table in views

    Give user access to add his custom table to the system.
    + Administer all custom table in views

    Give user access to administer all the custom tables, added by all the users
    + Administer own custom table in views

    Give user access to administer own custom tables
* Manage custom tables in Administration » Structure » Views » View Custom Table men

##

Also, double check you have this configs for the data export module (specially #8)

Finally, login as the "test user" and check out out.

Check the logs if certain steps are not working (admin/reports/dblog)

---
Tags: views, 9, importing-exporting
---


title: How to pass Block ID to a view?

text:
# Question
Title: How to pass Block ID to a view?
I have a Custom Block type called HomeBlocks. This bundle has a paragraphs field which allows multiple paragraphs.

I then place (using Layout Builder) an instance of this block type on my home page (a node type called Landing Page). In the layout of the block type I have a View which lists some of the paragraphs added to that specific block. The view lists my paragraphs but lists all the paragraphs of that type. If I add a contextual filter for Parent ID to the view and set as Fixed with the value being the BlockID of the block which I placed on my home page; then it filters to only the ones added to that block. Perfect.

The question is then; how to dynamically set this contextual filter?

I can think of 2 approaches:

1. Create a contextual filter plugin which passes the BlockID.
2. Pass BlockID from the Layout to the View.

I looked at option 2 a while back and found some work being done to allow arguments to be passed back from LB; but it was only supporting static values (as opposed to tokens).

Option 1 seems pretty simple and I set that up. To start with I simply pass back the static ID value and this works as expected.

**The missing piece here is how to get a list of blocks (of a certain type) which are placed on a specific node?**

I tried doing this with a view and I can get a list of BlockIds of all the blocks of this type; but can't see how to filter to the the one used on the specific node.

If there will ever be only 1 instance of this block used on the site; then I can use my existing view (that lists the only block of this type). I am not concerned about having multiple versions of this block on a single page; but I am trying to accommodate that there could be multiple pages with this block added.

# Answer
So if I understand correctly, here's what you did:

1. Created some paragraph types.
2. Created a block type, with a paragraph field referencing the paragraph types in #1.
3. Created a view with a Block display of *Paragraphs*, with a contextual filter for Parent ID.
4. Added the view in #3 to a display of the block type in #2 via Layout Builder.
    * I'm assuming you have other things going on in the layout, otherwise, this would simply just be a View Block of Paragraphs or just added the paragraph field directly to the layout.
5. Created instances of the block type in #2 and added them on a page.

There's a couple of crucial steps that are easy to miss:

* In step 3 (creating the view), create a relationship to the Block entity type. Then, instead of creating a contextual filter for the paragraph's Parent ID, create a contextual filter for the related Block's *ID* field.
* In step 4 (adding view block to layout), when you add the View block onto the layout of the block, Layout Builder will ask you about the block title and its visibility. Right after that, and because of the previous changes to the view, *it will now ask you what value to pass as the contextual filter value*. There will be an option that represents the current block.

The end result should be a view inside the layout of a block filtering paragraphs by the ID of the block that contains it.
> 0 votes

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


# Question
Title: Changing the Moderation State Control Box input to a textarea
I wanted to change the moderation state control box input to a textarea like the image below shows. Currently the input only supports 128 characters but I believe log messages can hold much more in the database.

# Answer
I was able to achieve it with a hook. We can add the below PHP to a custom module. Make sure to change the name of `MYMODULE` below.

```
/**
 * Implements hook_form_FORM_ID_alter().
 */
function MYMODULE_form_content_moderation_entity_moderation_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  // Change log message input to textarea on content moderation control boxes.
  $form['revision_log'] = [
    '#type' => 'textarea',
    '#title' => t('Log message'),
  ];
}

```
> 1 votes

---
Tags: forms, 9
---


# Question
Title: How to solve "Mismatched entity and/or field definitions", specifically, "The URL alias field needs to be installed"?
After migrating from 7.89 to 9.3.12 this warning appears:

ENTITY/FIELD DEFINITIONS Mismatched entity and/or field definitions The following changes were detected in the entity type and field definitions. File The URL alias field needs to be installed.

How do I solve this?

# Answer
> 2 votes
This issue can only happen if you have two modules installed at the same time. Pathauto and File Entity. It is rare that you need File Entity in Drupal 9 because we have now Media entities. You are probably still using it because you've used it in Drupal 7. But it is very rare that you need the field "URL alias" in the File entity. See https://www.drupal.org/project/file\_entity/issues/2655844#comment-14212446

So try out this patch to remove this field:

https://www.drupal.org/project/file\_entity/issues/2655844#comment-14213753

---
Tags: database, migrations, 9
---


title: How to hide a fieldset

text:
# Question
Title: How to hide a fieldset
I am trying to use hook\_form\_alter() to change the way a form is displayed. The form has 4 fieldsets and I only want to display one of them. How can I make these fieldsets invisible using hook\_form\_alter()?

# Answer
It's really simple.

On Drupal 6/7, set the "#access" property of the fieldset to `FALSE`, or use logic to determine visibility.
This will also hide all the content of the fieldset, and yet keep the values intact so that when the form is submitted they are not cleared, but retained.
> 12 votes

# Answer
I found that you had to do the following:

```
$form['last_field_in_tabgroup']['#required'] = FALSE;

```

and

```
hide($form['last_field_in_tabgroup']);

```

to make sure an empty tab doesn't show.
> 2 votes

# Answer
I use the hide function, for instance

```
    hide($form['title']);

```

if you need to set certain parameters of the form before hiding it do it in this fashion

```
 $form['title']['#required'] = FALSE;

```
> 0 votes

# Answer
I have developed a module to do so: the Hide Group (fieldset) module.

The #access property has the effect to remove entirely the fieldset from the form; my module only set it to hidden via CSS styles.
> 0 votes

# Answer
Use `hide($form['element']);` and `show($form['element']);` if you want to be able to display the element later (for instance in a Dynamic / Ajax form).

Setting the `#access` property to False works for hiding the element, but it seems you can't subsequently set it True if you want to show it again.
> 0 votes

# Answer
When you unset the form fields inside fieldset it should not be shown automatically, but you can also implement `hook_field_widget_WIDGET_TYPE_form_alter()` in your module for other cases.

You can use this guide. https://3cwebservices.com/drupal/how-remove-fieldset-drupal-address-field
> 0 votes

---
Tags: forms
---


# Question
Title: Can paragraph fields in a node be sorted?
I have a node content type with a paragraph field with multiple values. The paragraph has a date and a text field. When I display the node, I'd like to sort the paragraph values by date. I've tried doing this in twig with the sort filter to no avail. Can this be done somehow, maybe with preprocessing the field?

# Answer
> 4 votes
This should be no problem sorting the field items in preprocessing the field, but since Drupal 9 this can also be done in Twig.

For example:

*field--node--field-my-paragraph-field.html.twig:*

```
{% set items = items|sort((a, b) => a.content['#paragraph'].field_date.date.gettimestamp() <=> b.content['#paragraph'].field_date.date.gettimestamp()) %}

```

See the Twig 2.x docs (available for Drupal \>=9): https://twig.symfony.com/doc/2.x/filters/sort.html

---

If the `.date` property doesn't work it's a different field type. Try the generic `.value` property:

```
{% set items = items|sort((a, b) => a.content['#paragraph'].field_foo.value <=> b.content['#paragraph'].field_foo.value) %}

```

This also applies to the Timestamp field type. Not often used for configured fields, most times for base fields like Created or Changed.

---
Tags: paragraphs
---


# Question
Title: Related content by taxonomy term but using a relationship between terms
There are many posts and tutorials for creating views with contextual filters to display content that shares the same taxonomy term, but my requirement is slightly different.

I want to create a view that displays content that is related to the content being viewed via taxonomy terms BUT I do not want the related content to be based on the SAME taxonomy term, but instead a related taxonomy term.

I think I need to create a term reference field on the actual term itself, so say its called 'Related Term', and in that field I reference the other term, so I have a relationship between the two terms.

The bit where I'm stuck is how then to create a view much like the contextual filter views that show content with the same term as the content being viewed, except it will instead show content of the related term referenced in the field described above.

The general idea is that if for example content with the term 'Car' is being viewed, that the view will list content with the term 'Car Accessories'.

Is this possible or is there a better way to approach this?

# Answer
> 0 votes
I solved this using Views Token Arguments - solution here:

https://www.drupal.org/forum/support/post-installation/2022-05-07/related-content-by-taxonomy-term-but-using-a-relationship-between-terms

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


# Question
Title: Unable to add newly created term to the node
I want to add new taxonomy term to group of nodes that have specific terms already.

To retrive them I use this function

```
function getNodesByTaxonomyTermIds($termIds){
    $termIds = (array) $termIds;
    if(empty($termIds)){
      return NULL;
    }

    $query = \Drupal::database()->select('taxonomy_index', 'ti');
    $query->fields('ti', array('nid'));
    $query->condition('ti.tid', $termIds, 'IN');
    $query->distinct(TRUE);
    $result = $query->execute();

    if($nodeIds = $result->fetchCol()){
      return Node::loadMultiple($nodeIds);
    }

    return NULL;
  }

```

then in foreach loop I'm adding im adding them to new term based on their creation date but adding does not work.

Here is my field structure:

Firstly I tried all of those:

```
$node->set('field_news_categories', ['target_id' => $termID])
$node->set('field_news_categories', $termID)
$node->set('field_news_categories', array($termID))
$node->field_news_categories->setValue(['target_id' => $termID])
$node->field_news_categories->setValue($termID)
$node->field_news_categories->setValue(array($termID))

```

none worked so I thought maybe I should pass whole field with exact same structure, so I wanted to get field and just append the id and then pass it as argument in set method, but I wasn't able to get field either. All I was receving were null values or empty arrays. I tried:

```
$node->field_news_categories->getValue()
$node->get('field_news_categories')->getValue()
$node->field_news_categories->value
$node->get('field_news_categories')->value
$node->field_news_categories
$node->get('field_news_categories')
$node->get('field_news_categories')->target_id
$node->get('field_news_categories')->entity
$node->get('field_news_categories')->referencedEntities()

```

Project is in drupal 9

# Answer
To append an entity reference item use:

```
$node->field_foo[] = ['target_id' => 123];

```

And as Kevin noted in the comments, make sure you save the entity.

```
$node->save();

```
> 1 votes

---
Tags: nodes, taxonomy-terms
---


# Question
Title: How to put a site in maintenance mode by non-admin
Is there a module (or other way) to give permission to non-admin-users to put the site offline (and only that permission)?

# Answer
> 6 votes
There is a module for that!

Maintenance Mode Permissions

> Placing a site in or removing it from maintenance mode is allowed under a permission that has wide spread administrative access (administer site configuration). Sometimes you'd like to give permission to put the site in maintenance mode to someone but not give them complete access. This modules enables this case.

# Answer
> 2 votes
On D6 and D7, there's no specific permission to give to a role to grant access to the Maintenance mode page (admin/config/development/maintenance). This is because it has the "Administer site configuration" that grants access to many other configs that important and should be restricted only to a few users/role.

You can use Drush to do it:

```
drush vset maintenance_mode 1

```

Or create a new permission for that path (admin/config/development/maintenance) with hook\_alter\_menu:

```
function {your module}_alter_menu(&$items) {
  // Site maintenance
  $items['admin/settings/site-maintenance']['access arguments'] = array('administer maintenance mode');
}

```

To create the new permission use hook\_permission:

```
function {your module}_permission() {
  return array(
    'administer maintenance mode' => array(
      'title' => t('Administer maintenance mode'),
      'description' => t('Perform administration on maintenance mode page.'),
  )
}

```

# Answer
> 1 votes
At the very end of **sites/default/settings.php**, add the code below:

```
$conf['maintenance_mode'] = 1;

```

Remove the line of code above, or change the value to 0 to put your site online again:

```
$conf['maintenance_mode'] = 0;

```

Thats all

# Answer
> 1 votes
For Drupal 7/8/9 you can use the module Custom Permissions for that.

You have to (Drupal ^8):

1. Install the module Custom Permissions
2. Go to settings page /admin/people/custom-permissions/list
3. Set the "Custom Permission" for Route "system.site\_maintenance\_mode"
4. Find and set your permission on /admin/people/permissions

That's it.

(If you have installed Devel, you can find a list of routes on the page /devel/routes)

# Answer
> 0 votes
You would need to give the permission "System \> Administer site configuration". You can give that permission basically to whatever role you like. This lets users with that role put your site into Maintenance Mode. But be aware that this is a **very powerful permission** and it comes along with other administrative rights. Also – if you give that permission to a role you should probably also give the permission to view the site, if it's in Maintenance Mode.

I would consider such practice actually **a security risk** and would recommend to only give that permission to an extra role like "co-admin" or the like.

Edit: there's a module that let's you split administrative permissions into smaller chunks called Custom Permissions. The project page also gives a good impression which administrative rights are connected to the permision "System \> Administer site configuration".

"*By default the following permissions are created:"*

```
administer administration theme
administer clean-urls
administer date-time
administer error reporting
administer file system
administer modules
administer performance
administer site information
administer site maintenance
display site building menu
display site configuration menu

```

---
Tags: 7, maintenance-mode
---


# Question
Title: AJAX in a plugin form results in "The specified #ajax callback is empty or not callable."
I have a configuration form for a Condition plugin I want to have ajax in. When selecting from this field, I want to get a list of displays for that View:

```
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildConfigurationForm($form, $form_state);
    $views = $this->entityTypeManager->getStorage('view')->loadMultiple();
    $options = [];

    /** @var \Drupal\views\Views $view */
    foreach ($views as $view) {
      $options[$view->id()] = $view->label();
    }

    $form['#prefix'] = '<div id="views-settings">';
    $form['#suffix'] = '</div>';

    $view_id = $form_state->getValue('view_id');

    if (empty($view_id)) {
      $view_id = $form_state->getUserInput()["conditions"]["sfp_condition_view_not_empty"]["view_id"] ?? NULL;
    }

    if (empty($view_id)) {
      $view_id = $this->configuration['view_id'] ?? NULL;
    }

    $displays = isset($view_id) ? $this->getViewsDisplays($view_id) : [];

    $form['view_id'] = [
      '#type' => 'select',
      '#title' => $this->t('View'),
      '#required' => TRUE,
      '#options' => $options,
      '#default_value' => $view_id ? $options[$view_id] : '',
      '#ajax' => [
        'wrapper' => 'views-settings',
        'callback' => '::updateViewsDisplay',
        'event' => 'change',
      ],
    ];

    if (!empty($displays)) {
      $form['view_display'] = [
        '#type' => 'select',
        '#title' => $this->t('View display'),
        '#required' => TRUE,
        '#options' => $displays,
        '#default_value' => $displays[$this->configuration['view_display']] ?? $displays['default'],
      ];
    }

    return $form;
  }

      /**
       * Trigger form rebuild.
       *
       * @param array $form
       * @param \Drupal\Core\Form\FormStateInterface $form_state
       * @return array
       */
      public function updateViewsDisplay(array $form, FormStateInterface $form_state) {
        return $form;
      }

```

Xdebug hits the method fine, but I get this AJAX error:

"The specified #ajax callback is empty or not callable."

and nothing happens after that.

I checked elsewhere where I have done this and the only difference I can see is the ones that worked are regular Drupal Form API forms, and this is a plugin form passed from buildConfigurationForm. Outside of that, I am not seeing the issue.

# Answer
Thanks to Clives link, for reasons I am not 100% on the configuration forms for a Context plugin the AJAX callback needs to do this:

```
  /**
   * Trigger form rebuild.
   *
   * @param array $form
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   * @return array
   */
  public function updateViewsDisplay(array $form, FormStateInterface $form_state) {
    $triggering_element = $form_state->getTriggeringElement();
    $parents = array_slice($triggering_element['#array_parents'], 0, -1);
    return NestedArray::getValue($form, $parents);
  }

```

Then it began to work.

Also, the AJAX declaration needed to be:

```
'callback' => [$this, 'updateViewsDisplay'],

```

I assume this has to do with it being a 'form within a form'.
> 3 votes

---
Tags: forms, ajax
---


# Question
Title: How to access node entity reference on comment save via rules?
I have a content type with a user reference field on it, the users are populated here by a view.

When a user saves a comment, I want to access that field and send an email to user in the entity reference field.

# Answer
Although the question is about doing this with rules, here is how you can do this with some custom code. There could be a rules based approach towards doing the same thing.

You can implement a hook\_ENTITY\_TYPE\_insert hook in your module which will get called when a comment is inserted and then from that comment, get the node and from there you can do whatever you want to do with the node.

```
function custom_module_comment_insert(\Drupal\Core\Entity\EntityInterface $entity) {
   // $entity will be a comment entity.
   $node = $entity->getCommentedEntity();
   if ($commented_entity && $commented_entity instanceof \Drupal\node\NodeInterface) {
     // Do what you want to do with the node
   }
}

```

Hope this helps somebody running into this post.
> -1 votes

---
Tags: rules, 9
---


# Question
Title: How do I use Feeds Tamper to process multiple CSV columns into a single field?
I have a CSV file that I import into my site using Feeds Tamper.

The CSV file has columns like

* URL path
* Favorite vegetable
* Favorite fruit
* Favorite pasta

In Drupal, my content type has a JSON Field, and I want to import "Favorite vegetable", "Favorite fruit", and "Favorite pasta" into the JSON field.

**Is there a way to map all three favorites columns in the CSV file to the Drupal JSON field and combine their values in a Tamper plugin?** I can't find any way to pull in data from multiple sources (the three CSV columns) in a Tamper plugin.

Here's the structure of a Tamper plugin.

```
<?php

namespace Drupal\tamper\Plugin\Tamper;

use Drupal\tamper\Annotation\Tamper;
use Drupal\tamper\TamperableItemInterface;
use Drupal\tamper\TamperBase;

/**
 * Plugin implementation for CSV import. Copied from the encode plugin.
 *
 * @Tamper(
 *   id = "json_import",
 *   label = @Translation("JSON Import"),
 *   description = @Translation("Custom import for JSON."),
 *   category = "Text",
 *   handle_multiples = TRUE
 * )
 */
class JsonImport extends TamperBase {

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    $config = parent::defaultConfiguration();
    return $config;
  }

  /**
   * {@inheritdoc}
   */
  public function tamper($data, TamperableItemInterface $item = NULL) {
    return $data;
  }

}

```

# Answer
Ok, here's the correct way to do this.

`getSource()` will return an array with keys for all the CSV columns.

The column names are processed as follows:

* single words: Capitalization is kept. (**yellow**, **wEiRd**
* multiple words: Spaces are replaced with \_, and all lowercase. (**Meta Tag** becomes **meta\_tag**)

```
/**
 * {@inheritdoc}
 */
public function tamper($data, TamperableItemInterface $item = NULL) {
  $csv_columns = $item->getSource();

  $json = [];
  $json['favoriteFruit'] = $csv_columns['favorite_fruit'];
  $json['favoriteVegetable'] = $csv_columns['favorite_vegetable'];
  $json['favoritePasta'] = $csv_columns['favorite_pasta'];
  $encoded_json = json_encode($json);
  return $encoded_json;
}

```
> 3 votes

# Answer
I haven't figured out how to access multiple CSV columns, but one workaround is to use Excel or other spreadsheet software to create a new column and generate the JSON values in Excel. This is not a good approach because you have to do all the escaping in Excel, which is not fun and error prone.

For example, in Excel, you can use a formula like this:

```
=CONCAT("{"+CHAR(34)+"favoriteFruit"+CHAR(34)+":"+CHAR(34)+J3+CHAR(34)+","+CHAR(34)+"favoriteVegetable"+CHAR(34)+":"++CHAR(34)+K3+CHAR(34)+","+CHAR(34)+"favoritePasta"+CHAR(34)+":"+CHAR(34)+C3+CHAR(34)+"}")

```

Then, in Feeds Tamper, you need to add the **Encode** plugin and "Decode JSON" followed by the **Encode** plugin again with "Encode JSON". If your JSON doesn't have any mistakes, it will be imported into Drupal.
> -1 votes

---
Tags: 9, feeds
---


# Question
Title: How can I detect when a stream wrapper is uninstalled?
Does Drupal provide an "uninstall" hook to get notified when a Drupal Stream Wrapper is removed/uninstalled?

Or, is there a way to prevent a custom Drupal stream wrapper from being removed/uninstalled while there is at least one Drupal File entity that is using the stream wrapper?

Currently, for example, a Drupal site will crash if I do the following:

1. Install a custom stream wrapper (e.g., https://www.drupal.org/project/s3fs)
2. Add a File field to a Node and configure the file field to use this stream wrapper
3. Store a file with the file field above
4. Uninstall the custom stream wrapper's module
5. Try to view the file field's contents by opening the node's page (which will attempt to fetch & render the file).

# Answer
Yes. The module providing the stream wrapper should implement an uninstall validator, that checks for usages.
> 2 votes

---
Tags: hooks, stream-wrappers
---


# Question
Title: "Items in your active configuration have changes"
I'm trying to setup configuration management for our team, so i test the workflow on my **local machine**:

Starting from a fresh copy of our website + database backup, with an empty /config folder ($settings\['config\_sync\_directory'\] = '../config';). When i use the command "drush config:export", the task runs and all the .yml files are generated in the /config folder. **I then change the websites name (system.site), just as a simple test**.

Then, when visiting the configuration management UI in drupal, i would expect to see only 1 change. And indeed that is the case but i also see a **huge list (all config)** of untouched settings and the warning "**The following items in your active configuration have changes since the last import that may be lost on the next import**"

If i just exported all my config, did 1 change, then why is it saying that i have changes in my db that don't match with .yml files in the /config folder?

However, if i first click on 'import all', do the 1 change, revisit the configuration management UI, then i also get the warning but only with the 1 change.

So why is that?

# Answer
It could be because of configuration sorting.
> 0 votes

---
Tags: configuration
---


title: Display node local tasks on custom page

text:
# Question
Title: Display node local tasks on custom page
I've created a custom route for each nodes, let's say /custom-page/{node}, which renders some specific stuff from a Controller.
On this custom page, I'd like to automatically display the same local tasks as displayed on nodes canonical pages (In my case : View, Edit, Delete, Devel)

I know I can set dynamic local tasks using a Deriver in links.task.yml but how can I load local tasks from another route ?
Or maybe there is a way to tell Drupal to display local tasks as if it was for the route "entity.node.canonical" ?

Thank you for your help !

# Answer
> 0 votes
Ok actually this was a stupid question... I was trying to add the node tabs on my custom page without adding a tab to this custom page on the node view itself (entity.node.canonical)
Simply adding the new local task on the node view automatically displays other tabs when viewing any of the tabs

my\_module.links.task.yml :

```
my_module.my_custom_tab:
  route_name: my_module.custom_page
  title: 'Custom'
  base_route: entity.node.canonical

```

# Answer
> 1 votes
CUSTOM\_MODULE\_NAME.links.task.yml

```
CUSTOM_MODULE_NAME.tab_view:
  title: 'TAB NAME'
  route_name: CUSTOM_MODULE_NAME.CUSTOM_PAGE
  base_route: entity.node.canonical
  weight: 5

```

CUSTOM\_MODULE\_NAME.routing.yml

```
CUSTOM_MODULE_NAME.CUSTOM_PAGE:
  path: 'node/{node}/abc'
  defaults:
    _controller: '\Drupal\MODULE_NAME\Controller\CONTROLLER_NAME::ACTION_NAME'
    _title: 'TITLE'
  options:
    parameters:
      nodeId:
        entity_type: node
  requirements:
    _permission: 'access content'

```

---
Tags: 8
---


# Question
Title: How to get parameter from dynamic route in route subscriber
I am trying to restrict access for non admin users on admin/structure/menu so that only admins can create any new links via admin/structure/menu.
Now I want that for one special menu with the ID "Focus" the "Add Link" button is available for another role too.

Here is a Screenshot of the actual backend with the "Add Link" still availabe. I want this to be gone for Hauptnavigation but not for Fokusnavigation.

Same thing when you click on a Menu. You get an "Add Link" button. I can disable this with me code below, but I don't know how to allow it for non Admin Roles again.

I can get the menu-\>id() in the my\_menu.module file, with the same code like in the routesubscriber below but somehow it doesn't work in the routesubscriber. Drush CR returns an

```
PHP Fatal error:  Uncaught Error: Call to a member function id() on null in /var/www/html/web/modules/custom/my_menu/src/Routing/RouteSubscriber.php:31
Stack trace:
#0 /var/www/html/web/core/lib/Drupal/Core/Routing/RouteSubscriberBase.php(37): Drupal\my_menu\Routing\RouteSubscriber->alterRoutes(Object(Symfony\Component\Routing\RouteCollection))
#1 [internal function]: Drupal\Core\Routing\RouteSubscriberBase->onAlterRoutes(Object(Drupal\Core\Routing\RouteBuildEvent), 'routing.route_a...', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher))
#2 /var/www/html/web/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(142): call_user_func(Array, Object(Drupal\Core\Routing\RouteBuildEvent), 'routing.route_a...', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher))
#3 /var/www/html/web/core/lib/Drupal/Core/Routing/RouteBuilder.php(189): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object(Drupal\Core\Routing\RouteBuildEvent), 'routing.route_a...')
 in /var/www/html/web/modules/custom/my_menu/src/Routing/RouteSubscriber.php on line 31

```

Are there other ways to get the value? What am I doing wrong.
Here is my code.

```
<?php

namespace Drupal\my_menu\Routing;

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

/**
 * Class RouteSubscriber
 *
 * hiding menu editing components for non-admins
 *
 * @package Drupal\hw_menu\Routing
 */
class RouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {

    if ($route = $collection->get('entity.menu.add_link_form')) {

  //    dpm($route->getRequirements());

      $menu instanceof \Drupal\system\Entity\Menu;
      $menu = \Drupal::routeMatch()->getParameter('menu');
      if($menu->id() != 'focus') {
        $route->setRequirement('_role', 'administrator');
      }
    //  dpm($route->getRequirements());
    }

  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    // Run after content_translation, which has priority -210.
    $events[RoutingEvents::ALTER] = ['onAlterRoutes', -230];
    return $events;
  }

}

```

# Answer
> 1 votes
Would say that you code is failing because there is no `menu` entity available since the menu parameter converter works when the route gets resolved as commented by @Clive not during route build, which is when the `alter` event is fired.

On the other hand, why don't you use the `Administer menus and menu links` permission from core to deny your non-admin user's access to the menu administration? Also you can use Simple Menu Permissions or the Menu Admin per Menu modules if you want more control over your menus.

But if you still want to handle the menu access by yourself you can do that implementing your own access check using the route subscriber you have already.

---
Tags: routes
---


# Question
Title: How do I get the raw field value in a twig template?
*myfield* is a plain text field. `{{ content.field_myfield }}` renders the field with HTML markup and the field label.

How do I render the raw value of the field? `{{ content.field_myfield.value }}` doesn't work.

# Answer
`{{ entity.field_name.value }}` to get the true raw value, includes tags and encoding.

* Example: `{{ node.body.value }}`
* result: `<p>Batman & Robin</p>`

`{{ content.field_name.0 }}` to get the raw value minus tags and encoding.

* Example: `{{ content.body.0 }}`
* result: `Batman & Robin`

> **raw**
>
> This filter should be avoided whenever possible, particularly if you're outputting data that could be user-entered. See this page for more information on auto-escape in Drupal 8.
>
> source: Filters - Modifying Variables In Twig Templates
>
> The raw filter marks the value as being "safe", which means that in an environment with automatic escaping enabled this **variable will not be escaped** if raw is the last filter applied to it
>
> source: Twig's official docs

---

For example, you can use:

```
{{ node.body.value|striptags }}

```

```
{{ paragraph.field_text.value|striptags }}

```

> The problem with using twig's **|striptags** is double encoding of html entities, not markup, so `&` becomes `&` and then `&amp;` – Berdir
> 78 votes

# Answer
Here is the code:

```
{{ content.field_title|render|striptags|trim|lower }}

```

it works fine.
> 14 votes

# Answer
You can use Twig Field Value module in this case. After install this module You will get access to partial data from field render arrays. For ex.

```
{{ content.field_name|field_value }}
content.field_image|field_target_entity.uri.value

```

etc. More info on projects page
> 8 votes

# Answer
None of the suggestions so far worked for my text field. My text field is not multivalue, just a simple text field. Here is what did work for me:

```
content.field_myfieldname['#items'].getString()

```
> 6 votes

# Answer
```
{{ content.body | raw }}

```

get the raw field value in a twig template
> 4 votes

# Answer
Another way is preprocess the plain text through a text\_filter. With this method you keep leveraging Drupal's text filters like basic\_html. So this way is more secure than rendering the plain text as html in twig.

In this example the field-name is 'field\_myfield'. The text-formatter is 'basic\_html'. But you could also use 'full\_html' or any other available formatter. And it is a paragraph of type 'hero' is preprocessed.

# In THEME.theme

```
/**
 * Implements TEMPLATE_preprocess_HOOK().
 */
function THEME_preprocess_paragraph__hero(&$variables) {
  $entity = $variables['paragraph'];

  $variables['content']['field_myfield'] = check_markup(
    $entity->get('field_myfield')->getValue()[0]['value'],
    'basic_html',
    $entity->language()->getId()
  );
}

```

And in Twig nothing has changed.

```
{{ content.field_myfield }}

```
> 2 votes

# Answer
In case this helps anyone, I wanted to only have the start year of a datetime range field displayed, instead of both parts of the range, within a field Twig template.

So I ended up overriding the usual field template with this:

```
{% if label_hidden %}
  {% if multiple %}
    <div{{ attributes.addClass(classes, 'field--items') }}>
      {% for key, item in items %}
        <h3{{ item.attributes.addClass('field--item') }}>{{ element['#items'][key].value|date('Y') }}</h3>
      {% endfor %}
    </div>
  {% else %}
    {% for key, item in items %}
      <h3{{ attributes.addClass(classes, 'field--item') }}>{{ element['#items'][key].value|date('Y') }}</h3>
    {% endfor %}
  {% endif %}
{% else %}
  <div{{ attributes.addClass(classes) }}>
    <div{{ title_attributes.addClass(title_classes) }}>{{ label }}</div>
    {% if multiple %}
      <div class="field--items">
    {% endif %}
    {% for key, item in items %}
      <h3{{ item.attributes.addClass('field--item') }}>{{ element['#items'][key].value|date('Y') }}</h3>
    {% endfor %}
    {% if multiple %}
      </div>
    {% endif %}
  </div>
{% endif %}

```
> 1 votes

# Answer
```
{{ entity.field_name.value }}

```

will give you either an empty array (if the field is not filled in) or a string (if it is). Therefore, you cannot assume this is a string.

For example, if you pipe it to a function which expects a string, like:

```
{{ entity.field_name.value|split(',') }}

```

This might work only if the field has data, but will throw a warning (in PHP 7) or an error (in PHP 8), such as `explode() expects parameter 2 to be string`.

Always test your template with empty fields and non-empty fields before using it. Always check your error log , and never assume entity.field\_name.value will be a string.

Also, note that this technique will show you the first value in a multi-value field.

See also https://www.drupal.org/project/drupal/issues/3215952#comment-14498809
> 0 votes

# Answer
I have found this useful article from Sarah Carney, in which she explains how to get the values from different field types: body, text, list, link, image, file, boolean, number, email, phone, date, and taxonomy/entity reference.

This is an example that she explains to get the name tags in a `ul` (Example 2)

```
{% if content.field_name[0] %}
  <ul>
    {% for key, item in content.field_name if key|first != '#' %}
      <li>{{ item['#title'] }}</li>
    {% endfor %}
  </ul>
{% endif %}

```
> 0 votes

---
Tags: 8, theming
---


# Question
Title: Additional old_XXXXXXtaxonomy_term__field_XXX Tables after upgrading
After Upgrading from Drupal 8.6 to 8.7 I have tons of new (garbage?) tables in the database. The naming schema for the tables is old\_XXXXXXtaxonomy\_term\__field\_XXX

Is there a drush command to remove them or can i just drop dem directly?

I tried `drush eval "field_purge_batch(5000)"` and `drush entity-updates` without success.

# Answer
Not sure there is an automatic way to do this, a manual way would be to use:

```
echo "Show tables;" | drush @alias sql-cli | grep old > drop_tables.sql

```

Edit the tables.txt file and add `drop table` and a ; after each table name. Each line should look like:

```
drop table old_XXXXXXXtaxonomy_term__field_XXXX;

```

Backup you database in case Murphy come's around and do:

```
drush @alias sql-cli < drop_tables.sql

```

That will remove them from the DB.

Alternative way to do it via a GUI would be to use MySQL Workbench and drop them thru the interface.
> 0 votes

# Answer
There is also another possibility how to delete the old\_\* tables:

```
drush sql-cli

SET @Drop_Stm = CONCAT('DROP TABLE ', (
  SELECT GROUP_CONCAT(TABLE_NAME) AS Old_Tables FROM information_schema.tables
  WHERE TABLE_NAME LIKE 'old_%'
));
PREPARE Stm FROM @Drop_Stm;
EXECUTE Stm;
DEALLOCATE PREPARE Stm;

```

(Do not forget to back up your database before deleting the tables. ;-)
> 0 votes

---
Tags: 8, updating
---


# Question
Title: Use a different twig media template if it is being rendered inside a WYIWYG
I have a twig template for a media entity that I wish to be able to embed into a WYIWYG. I am able to, however the entity has issues rendering when inside the ckeditor that aren't present when rendered on an actual page. I want to either use a different template or use some variable that detects whether the media is in an edit mode.

Is there a twig variable like {{ inEditor }} or is there a template I could use specific to wyiwygs like media--remote-video--WYIWYG.html.twig ?

When viewing the element in a preprocess function I do see there is a 'view\_mode' variable but that's always set to default.

# Answer
> 3 votes
You could check for the route name `media.filter.preview`:

```
if (\Drupal::routeMatch()->getRouteName() === 'media.filter.preview') {
  // media is rendered inside CKEditor
  $variables['inEditor'] = TRUE;
}
// add cache context
$variables['#cache']['contexts'][] = 'route.name';

```

---
Tags: media, 9
---


# Question
Title: Run into issues with Drush after updating from 8.9.20 to 9.3.13
I upgraded from 8.9.20 to 9.3.13 and i did an update.php after this. I do get an error:

> MISSING UPDATES FOR: VIEWS The installed version of the Views module is too old to update. Update to a version prior to 9.0.0 first (missing updates: views\_post\_update\_remove\_core\_key).

If i try to update the databse with drush updatedb i get an error too:

> In BootstrapHook.php line 36: Bootstrap failed. Run your command with -vvv for more information.

Is there any chance to solve this issue?

This is the status: Drupal version : 9.3.13
Site URI : http://default
DB driver : mysql
DB hostname : localhost
DB port : 3306
DB username : xxx
DB name : xxx
PHP binary : /usr/local/Cellar/php/8.0.3/bin/php
PHP config : /usr/local/etc/php/8.0/php.ini
PHP OS : Darwin
Drush script : /usr/local/bin/drush
Drush version : 11.0.9
Drush temp : /tmp
Drush configs : /Users/mb/Sites/vendor/drush/drush/drush.yml /Users/mb/drush/drush.yml
Drupal root : /Users/mb/Sites
Site path : sites/default

Thanks for helping!

# Answer
The function views\_post\_update\_remove\_core\_key was introduced in Drupal 8.8 and was removed in Drupal 9.0. See views\_removed\_post\_updates.

To avoid this error and probably other similar errors you have to run update.php or `drush updb` at least one time with Drupal 8.8.12 or Drupal 8.9.20 (make sure it runs without errors while you are still on Drupal 8) before you can upgrade the code to Drupal 9. Then running update.php on Drupal 9 shouldn't throw this error.

---

You can add missed post updates to the state of your Drupal installation

```
$key_value = \Drupal::service('keyvalue');
$existing_updates = $key_value->get('post_update')->get('existing_updates', []);
$post_updates = [
  'update_test_postupdate_post_update_foo',
  'update_test_postupdate_post_update_bar',
  'update_test_postupdate_post_update_pub',
  'update_test_postupdate_post_update_baz',
];
$key_value->get('post_update')->set('existing_updates', array_merge($existing_updates, $post_updates));

```

(Code is from UpdatePostUpdateTest)

and then run the missed updates yourself. In this example you could simply re-save all Views by hand.
> 1 votes

---
Tags: views, drush
---


# Question
Title: $form_state->setValue() doesn't save value
I have an validate code:

```
public function validateForm(array &$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);

    $form_state->setValue('my_variable', $form_state->getValue('my_variable') + 1);
    $form_state->setRebuild();
}

```

And I previously set `my_variable` to `1` if it's `NULL`:

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

    if($form_state->getValue('my_variable') == NULL){
        $form_state->setValue('my_variable', 1);
    }
...

```

I use ajax callback for form submission and the validation works fine. After click on submit button I display `my_variable` and I see `2` (before submission it's `1`).

But when I hit the submit button again I see `2` again, instead of `3`. Also, when I re-load the page the data is missing (so it's get value `1` again).

How to prevail the value? It looks like I am operating on copy of `$form_state` instead of reference but I cannot write **&$form\_state** (`public function validateForm(array &$form, FormStateInterface &$form_state)`) because it gives me an error (as it's not the correct declaration of validateForm method).

# Answer
> -3 votes
The value in the `$form_state` (actually everything) is lost after the PHP process ends. So there is no way to preserve your `my_variable` value via the `$form_state`. Your best option is to store this value in the session I guess.

**Example:**

```
  public function validateForm(array &$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);

    $session = \Drupal::request()->getSession();
    $session->set('my_variable', $session->get('my_variable') + 1);
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    $session = \Drupal::request()->getSession();

    if (empty($session->get('my_variable'))) {
      $session->set('my_variable', 1);
    }
  }

```

Do note that the data gets lost as soon as the user clears his cookies and/or the sessions gets invalidated. If you need a permanent global storage (for all users) use the State API. For a permanent storage per user use the Database API.

# Answer
> 10 votes
If it is a custom variable, you should use `$form_state->set('property_name', 'value')` (instead of "`$form_state->setValue(...)`").

## Example:

```
public function validateForm(array &$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);

    // Update custom variable (in PHP "null + 1" equals one).
    $form_state->set('my_variable', $form_state->get('my_variable') + 1);

    // Below is only required when your "buildForm(...)" depends on the variable.
    $form_state->setRebuild();
}

```

# Answer
> 2 votes
Just to add if you'd like to actually save a form value. I do the following when using webform, I imagine it's easily modified for a usual form.

`$form['elements']['form_element']['#default_value'] = 'my_value'`

# Answer
> 0 votes
You can use

```
$form_state->setValue('VALUE_NAME', VALUE_PASSING);

```

Like -

```
public function validateForm(array &$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);
    $form_state->setValue('csvupload', $file->destination);
    $form_state->setValue('fid', $file->fid);
    $form_state->setRebuild();
}

```

---
Tags: 8, forms
---


# Question
Title: Drupal migrate - "--limit" option works only for first run?
I have custom source plugin (imports from MongoDB) and when I run migration for the first time like:

```
drush mim article --limit=10

```

it works well: 10 articles are being imported and process stops.

But if I repeat that command then only 1 article is imported.

And if I have like 10 imported articles and run again with limit=20 then 10 new ones are going to be imported.

And if I set limit smaller than current number of imported ones then only 1 new row will be imported.

Should command I specified import always 10 new rows (if there are available, unprocessed)?

Any hint is welcome!

(using drush 11.0.7 and Drupal 9.3.12) (edited)

Update:

So it looks like that code which is counting number of processed rows and checking if limit parameter is reached is not working well, that is, it counts also previously processed rows which should not be the case.

# Answer
I solved it this way:

Original next() of SourcePluginBase has checking if row processing is needed or not this way:

```
  if (!$row->getIdMap() || $row->needsUpdate() || $this->aboveHighWater($row) || $this->rowChanged($row)) {
    $this->currentRow = $row->freezeSource();
  }

```

Now, in my class that inherits that SourcePluginBase I added to it prepareRow override:

```
  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    if (!$row->getIdMap() || $row->needsUpdate() || $this->aboveHighWater($row)) {
      return parent::prepareRow($row);
    }
    return FALSE;
  }

```

I noticed that for previously imported rows condition $this-\>rowChanged($row) is true and for new rows that really needs to be processed $this-\>rowChanged($row) is true. So I removed first one and kept second one.

I'm aware that this is kind of workaround and that there is probably some incompatibility between drush and drupal, but this is the best solution I could do. If someone has better solution/explanation I will be glad to hear it.
> 0 votes

---
Tags: migrations
---


# Question
Title: Why don't users with the "Create new content" permission for a custom bundle cannot access /node/add, but they can access /node/add/author?
If I give to a custom role the *Article: Create new content* permission, users can access the */node/add* page. However, if I give the same permission for a custom bundle, for example *Author: Create new content*, users can't access that page, but yet can access /node/add/author.

What should I try to address the problem? I've tried to debug `NodeAccessControlHandler::createAccess()`, but this code doesn't show anything wrong.

```
$result = parent::createAccess($entity_bundle, $account, $context, TRUE)->cachePerPermissions();
return $return_as_object ? $result : $result->isAllowed();

```

# Answer
> 0 votes
After some test, I discovered it was due to some incompatibility between form mode manager and entity limit

---
Tags: entities, 9
---


# Question
Title: Import single view configuration fail - layout_builder__layout will not exists after import
I have Drupal 8.9.13 and I want to export/import single views configuration to other Drupal 8.9.13. I can select single view to export, but when I import it I get the next error:

```
The configuration core.entity_view_display.node.page.default depends on the configuration of field.field.node.page.layout_builder__layout that will not exists after import.

```

This is one of the views I want to import. The problem happens with all views:

```
uuid: xxxxx
langcode: es
status: true
dependencies:
  config:
    - field.storage.user.field_documento
    - user.role.administrator
  module:
    - mycustommodule
    - file
    - rest
    - serialization
    - user
id: custom_user_files
label: 'User files'
module: views
description: 'REST Export user files'
tag: ''
base_table: file_managed
base_field: fid
display:
  default:
    display_plugin: default
    id: default
    display_title: Master
    position: 0
    display_options:
      access:
        type: role
        options:
          role:
            administrator: administrator
      cache:
        type: tag
        options: {  }
      query:
        type: views_query
        options:
          disable_sql_rewrite: false
          distinct: false
          replica: false
          query_comment: ''
          query_tags: {  }
      exposed_form:
        type: basic
        options:
          submit_button: Apply
          reset_button: false
          reset_button_label: Reset
          exposed_sorts_label: 'Sort by'
          expose_sort_order: true
          sort_asc_label: Asc
          sort_desc_label: Desc
      pager:
        type: mini
        options:
          items_per_page: 10
          offset: 0
          id: 0
          total_pages: null
          expose:
            items_per_page: false
            items_per_page_label: 'Items per page'
            items_per_page_options: '5, 10, 25, 50'
            items_per_page_options_all: false
            items_per_page_options_all_label: '- All -'
            offset: false
            offset_label: Offset
          tags:
            previous: ‹‹
            next: ››
      style:
        type: serializer
      row:
        type: fields
        options:
          inline: {  }
          separator: ''
          hide_empty: false
          default_field_elements: true
      fields:
        filename:
          id: filename
          table: file_managed
          field: filename
          relationship: none
          group_type: group
          admin_label: ''
          label: ''
          exclude: false
          alter:
            alter_text: false
            text: ''
            make_link: false
            path: ''
            absolute: false
            external: false
            replace_spaces: false
            path_case: none
            trim_whitespace: false
            alt: ''
            rel: ''
            link_class: ''
            prefix: ''
            suffix: ''
            target: ''
            nl2br: false
            max_length: 0
            word_boundary: false
            ellipsis: false
            more_link: false
            more_link_text: ''
            more_link_path: ''
            strip_tags: false
            trim: false
            preserve_tags: ''
            html: false
          element_type: ''
          element_class: ''
          element_label_type: ''
          element_label_class: ''
          element_label_colon: false
          element_wrapper_type: ''
          element_wrapper_class: ''
          element_default_classes: true
          empty: ''
          hide_empty: false
          empty_zero: false
          hide_alter_empty: true
          click_sort_column: value
          type: file_filemime
          settings:
            link_to_entity: 0
          group_column: value
          group_columns: {  }
          group_rows: true
          delta_limit: 0
          delta_offset: 0
          delta_reversed: false
          delta_first_last: false
          multi_type: separator
          separator: ', '
          field_api_classes: false
          entity_type: file
          entity_field: filename
          plugin_id: field
        field_documento:
          id: field_documento
          table: user__field_documento
          field: field_documento
          relationship: reverse_field_documento_user
          group_type: group
          admin_label: ''
          label: ''
          exclude: false
          alter:
            alter_text: false
            text: ''
            make_link: false
            path: ''
            absolute: false
            external: false
            replace_spaces: false
            path_case: none
            trim_whitespace: false
            alt: ''
            rel: ''
            link_class: ''
            prefix: ''
            suffix: ''
            target: ''
            nl2br: false
            max_length: 0
            word_boundary: true
            ellipsis: true
            more_link: false
            more_link_text: ''
            more_link_path: ''
            strip_tags: false
            trim: false
            preserve_tags: ''
            html: false
          element_type: ''
          element_class: ''
          element_label_type: ''
          element_label_class: ''
          element_label_colon: false
          element_wrapper_type: ''
          element_wrapper_class: ''
          element_default_classes: true
          empty: ''
          hide_empty: false
          empty_zero: false
          hide_alter_empty: true
          click_sort_column: target_id
          type: astec_fichero_base64
          settings: {  }
          group_column: ''
          group_columns: {  }
          group_rows: true
          delta_limit: 0
          delta_offset: 0
          delta_reversed: false
          delta_first_last: false
          multi_type: separator
          separator: ', '
          field_api_classes: false
          plugin_id: field
        fid:
          id: fid
          table: file_managed
          field: fid
          relationship: none
          group_type: group
          admin_label: ''
          label: ''
          exclude: false
          alter:
            alter_text: false
            text: ''
            make_link: false
            path: ''
            absolute: false
            external: false
            replace_spaces: false
            path_case: none
            trim_whitespace: false
            alt: ''
            rel: ''
            link_class: ''
            prefix: ''
            suffix: ''
            target: ''
            nl2br: false
            max_length: 0
            word_boundary: true
            ellipsis: true
            more_link: false
            more_link_text: ''
            more_link_path: ''
            strip_tags: false
            trim: false
            preserve_tags: ''
            html: false
          element_type: ''
          element_class: ''
          element_label_type: ''
          element_label_class: ''
          element_label_colon: false
          element_wrapper_type: ''
          element_wrapper_class: ''
          element_default_classes: true
          empty: ''
          hide_empty: false
          empty_zero: false
          hide_alter_empty: true
          click_sort_column: value
          type: number_integer
          settings:
            thousand_separator: ''
            prefix_suffix: false
          group_column: value
          group_columns: {  }
          group_rows: true
          delta_limit: 0
          delta_offset: 0
          delta_reversed: false
          delta_first_last: false
          multi_type: separator
          separator: ', '
          field_api_classes: false
          entity_type: file
          entity_field: fid
          plugin_id: field
      filters: {  }
      sorts: {  }
      header: {  }
      footer: {  }
      empty: {  }
      relationships:
        reverse_field_documento_user:
          id: reverse_field_documento_user
          table: file_managed
          field: reverse_field_documento_user
          relationship: none
          group_type: group
          admin_label: field_documento
          required: true
          entity_type: file
          plugin_id: entity_reverse
      arguments:
        uuid:
          id: uuid
          table: users
          field: uuid
          relationship: reverse_field_documento_user
          group_type: group
          admin_label: ''
          default_action: default
          exception:
            value: all
            title_enable: false
            title: All
          title_enable: false
          title: ''
          default_argument_type: query_parameter
          default_argument_options:
            query_param: uuid
            fallback: ''
            multiple: and
          default_argument_skip_url: false
          summary_options:
            base_path: ''
            count: true
            items_per_page: 25
            override: false
          summary:
            sort_order: asc
            number_of_records: 0
            format: default_summary
          specify_validation: false
          validate:
            type: none
            fail: 'not found'
          validate_options: {  }
          glossary: false
          limit: 0
          case: none
          path_case: none
          transform_dash: false
          break_phrase: false
          entity_type: user
          entity_field: uuid
          plugin_id: string
      display_extenders: {  }
    cache_metadata:
      max-age: -1
      contexts:
        - 'languages:language_content'
        - 'languages:language_interface'
        - request_format
        - url
        - url.query_args
        - user.roles
      tags:
        - 'config:field.storage.user.field_documento'
  rest_export_1:
    display_plugin: rest_export
    id: rest_export_1
    display_title: 'REST export'
    position: 1
    display_options:
      display_extenders: {  }
      path: custom-user-files
      pager:
        type: none
        options:
          offset: 0
      style:
        type: serializer
        options:
          formats:
            json: json
      row:
        type: data_field
        options:
          field_options:
            filename:
              alias: ''
              raw_output: true
            field_documento:
              alias: ''
              raw_output: false
            fid:
              alias: ''
              raw_output: true
            uuid:
              alias: ''
              raw_output: true
      auth:
        - basic_auth
        - key_auth
        - cookie
    cache_metadata:
      max-age: -1
      contexts:
        - 'languages:language_content'
        - 'languages:language_interface'
        - request_format
        - url
        - user.roles
      tags:
        - 'config:field.storage.user.field_documento'

```

I don't use layout builder templates. *field\_documento* is a field in the user profile. How could I solve this issue?.

# Answer
> 1 votes
I have found how to solve the problem. I put here the solution, and It could help someone else with this error.
It's very easy. You have to check "Use layout builder" on the "manage presetation" tab for the "page" content type. After done it, I can export and import views without problem.

# Answer
> 1 votes
Yes the accepted answer would work - on the basis that checking Use layout builder would create the active config which is the dependency required and so the import can succeed. Though I guess beforehand a config export would then be needed (`drush cex`) to write out the created layout field - which would mean overwriting any other config in code to then be imported.

My case was a very similar problem.

```
 [error]  Drupal\Core\Config\ConfigImporterException: There were errors validating the config synchronization.
Configuration <em class="placeholder">core.entity_view_display.node.page.default</em> depends on the <em class="placeholder">field.field.node.page.layout_builder__layout</em> configuration that will not exist after import. in Drupal\Core\Config\ConfigImporter->validate() (line 750 of web/core/lib/Drupal/Core/Config/ConfigImporter.php).

```

And I am seeing this in Drupal 9 - 9.3.12.

However, I have done a different approach: I deleted the dependency in the yml file. This dependency was themselves another config file which did not exist, so it's no wonder the config import (`drush cim`) is going to fail with the above error - it will look for the file as dependency and won't find it!

So if it doesn't exist then might as well delete it!

Here is a snippet (a partial excerpt) of the config file - `core.entity_view_display.node.page.default.yml` \- that lists the other file as dependency

```
dependencies:
  config:
    - field.field.node.page.body
    - field.field.node.page.field_content
    - field.field.node.page.layout_builder__layout
    - node.type.page
  module:
    - entity_reference_revisions
    - layout_builder
    - layout_discovery
    - text
    - user
third_party_settings:
  layout_builder:
    enabled: false
    allow_custom: false

```

This file listed above did not exist:

```
    - field.field.node.page.layout_builder__layout

```

Which is mentioned in the error. No wonder the error occured.

**Solution**

Delete the line for it listed as a dependency in `core.entity_view_display.node.page.default.yml` and run config import (`drush cim`).

My approach has the potential benefit of being a bit more "surgically" targeted, which is particularly handy if you have other config to import and don't want to lose that by first doing an export to resolve this issue.

I think there is a bug here in Drupal - this issue seems to track it: https://www.drupal.org/project/drupal/issues/3068260

If you look at my snippet, you can see that the layout field is listed as a dependency, yet under third party settings in that snippet, layout builder is switched off - i.e. false! Surely not right - why would there be layout field yml if the layout builder itself wasn't enabled - that's an inconsistency.

---
Tags: 8, configuration, layout-builder
---


title: Why is my Permissions page empty?

text:
# Question
Title: Why is my Permissions page empty?
We are developing a Drupal 9 site on Acquia. When I go to /admin/people/permissions there are no permissions listed. But when I go to /admin/people/roles I can edit the permissions on a given role and see all the permission checkboxes as normal. /admin/people looks fine. Any clues as to what happened to the Permissions page?

# Answer
I was getting blank page, wsod, on the permissions page (/admin/people/permissions).

So, i changed the below values in php.ini + Apache restart

max\_input\_vars = 3000

memory\_limit = 512M

After changing the values in php.ini, make sure its reflected by pulling (/admin/reports/status/php) in there, you can also see which php.ini file is being used.

In my case: /admin/reports/status/php kept showing the old values even after Apache restart, so i had to do the following which solved it and forced the new values to take effect:

systemctl restart php-fpm (if you're using this )
> 0 votes

---
Tags: 9
---


# Question
Title: How to hide the fields in manage display when layout module is installed and display when module is uninstalled programmatically?
In the below config I want to remove the body field from **content** and add it in **hidden** as **body: true** when I uninstall the layout module. *Basically when I install the layout module the fields in manage display should get disabled/hidden and when I uninstall the module the fields should be displayed.* How can I achieve this programatically?

This config code is of `entity_view_display.node.article.default`

```
  uuid: eedc35e4-0592-4f1a-bdc6-47dbf60fa929
    langcode: en
    status: true
    dependencies:
      config:
        - field.field.node.article.body
        - field.field.node.article.comment
        - field.field.node.article.field_image
        - field.field.node.article.field_media
        - field.field.node.article.field_sample_text
        - field.field.node.article.field_tags
        - node.type.article
      module:
        - layout_builder
        - text
        - user
    third_party_settings:
      layout_builder:
        enabled: false
        allow_custom: false
    id: node.article.default
    targetEntityType: node
    bundle: article
    mode: default
    content:
      body:
        type: text_default
        label: above
        settings: {  }
        third_party_settings: {  }
        weight: 0
        region: content
    hidden:
      comment: true
      field_image: true
      field_media: true
      field_sample_text: true
      field_tags: true
      langcode: true
      links: true
      search_api_excerpt: true

```

# Answer
I have solved the issue. Instead of `\Drupal::entityTypeManager()` I used

```
$articleDefaultLayout = LayoutBuilderEntityViewDisplay::load(
    'node.article.default'
);
$articleDefaultLayout->setComponent('body');

```
> 1 votes

# Answer
To disable the body field when you install the custom module:

*mymodule.install*

```
/**
 * Implements hook_install().
 */
function mymodule_install() {
  \Drupal::entityTypeManager()
    ->getStorage('entity_view_display')
    ->load('node.article.default')
    ->removeComponent('body')
    ->save();
}

```

How to enable the field see 8 - How do i programmatically enable a user field under manage form display and manage display?
> 0 votes

---
Tags: entities, configuration
---


# Question
Title: Clarify difference between hook_form_TYPE_alter and hook_form_TYPE_EDIT_alter
I have a site with a lot of hook form alters for node forms and I'm finding that I have to create two separate hook functions to affect **both** the node create and node edit forms.

For example, I have to put both:

```
module_events_form_node_event_form_alter()

```

and

```
module_events_form_node_event_edit_form_alter()

```

With the same functionality in both functions so that it covers both new and edited nodes. Is there a way to have one hook\_form\_alter() to cover both form conditions?

# Answer
> 3 votes
You can either use the full form ID with content type and operation or the base form ID `node_form`. This is without the operation but also missing the content type. So when you alter the base form you have to check for a specific content type if you don't want to alter all node forms:

```
/**
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function mymodule_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $node = $form_state->getFormObject()->getEntity();
  if ($node->getType() == 'event') {
    // change the node form for the content type event and any operation
  }
}

```

---
Tags: hooks
---


title: Getting current node id in views

text:
# Question
Title: Getting current node id in views
I'm on drupal 8, and I'm trying to figure out how to get the current node id in an override of views-view-unformatted.html.twig.

I have a view filled with titles with added links and I want to add a class to the one the corresponds to the current node id.

# Answer
> 2 votes
You will get the node id in an override of `views-view-unformatted.html.twig`. Find below code

```
{% for row in rows %}
  {% set nid  = row.content['#row']._entity.nid.value %}
{% endfor %}

```

# Answer
> 1 votes
You'll find the node id from each row in `_entity`:

```
{{ row._entity.id }}

```

# Answer
> 1 votes
I did this in preprocess
In your .theme file :

```
function YOURTHEME_preprocess_views_view_unformatted(&$variables) {
  foreach($variables['rows'] as $key => $row){
    if(is_object($row['content']['#node'])){
      $variables['rows'][$key]['nid'] = $row['content']['#node']->id();
    }
  }
}

```

And then in your template file

```
{{ row.nid }}

```

Will output the NID.

# Answer
> 0 votes
Added class "**active**", if node\_id same.

In your .theme file :

```
function THEME_preprocess_views_view_unformatted__YOUR_NAME_VIEW__block_1(&$variables) {
  $node = \Drupal::request()->attributes->get('node');
  $node_id = $node->id();

  $view = $variables['view'];
  $rows = $variables['rows'];
  $id_view = $view->storage->id();

  if ($id_view == 'YOUR_NAME_VIEW' && $view->current_display == 'block_1') {
    $variables['#cache']['contexts'][] = 'url.path';

    foreach ($rows as $id => $row) {
      $view_node_id = $row['content']['#node']->id();

      if ($view_node_id == $node_id) {
        $variables['rows'][$id]['attributes']['class'][] = 'active';
      }

    }
  }

}

```

**There is one condition!!!** You need add any class in 'Row class' in your view.

**FORMAT** \- Settings - Row class(The class to provide on each row.)

---
Tags: views, theming
---


# Question
Title: How to add new fields to the 'edit media' dialog box on media embeds
I'm attempting to add a new select box to the dialog box that pops up when choosing 'edit media' on a media embed in a WYSIWYG. I'm referring to the dialog box that presents options like 'caption' and 'alignment'

I was able to make the field appear by using

```
function mymodule_form_alter(array &$form, FormStateInterface $form_state, string $form_id)  {
if($form_id=='editor_media_dialog'){
  $form['size'] = [
    '#title' => t('Size'),
    '#type' => 'select',
    '#options' => [
      '' => t('Default'),
      '-small' => t('Small'),
      '-medium' => t('Medium'),
      '-large' => t('Large'),
    ],
  ];
 }
}

```

but I can't seem to be able to make that value save in anyway. When saving and reopening the dialog box there is no reference to the new value in $form\_state.

What would be the proper way to add fields to the 'edit media' dialog box of embedded media entities in a WYSIWYG?

# Answer
These dialogs work like so:

* When you save the form, everything inside `attributes` in the form state is added as a literal HTML attribute to the `<drupal-media>` element which the modal was launched for. So the data gets saved in the markup itself.
* When you load the form again, all of the HTML attributes currently on the element are passed through to the form, so the inputs can be populated.

So all you need to do is:

1. Get your form element into the `attributes` array, so it will be applied to the markup automagically. You can do this by setting the `#parents` on the element.
2. Set the `#default_value` to the one passed in from the editor. Those values are available from the user input, rather than the form state values.

Your final code might look like this:

```
$size = $form_state->getUserInput()['editor_object']['attributes']['size'] ?? '';

$form['size'] = [
  '#title' => t('Size'),
  '#type' => 'select',
  '#options' => [
    '' => t('Default'),
    '-small' => t('Small'),
    '-medium' => t('Medium'),
    '-large' => t('Large'),
  ],
  '#parents' => ['attributes', 'size'],
  '#default_value' => $size,
];

```
> 1 votes

---
Tags: media, 9, wysiwyg
---


# Question
Title: How do I get the submitter of a webform submission?
I'm developing my first webform handler and I need to access the submitter of the webform submission in the `postSave` method.

I know I can get the webform submission ID with `$webform_submission->id()`, but I can't figure out how to get the submitter. As far as I know, `$webform_submission->getWebform()->getOwner()` is NOT what I'm looking for, because it tells me the owner of the form, not the "owner" of the submission. I found How do I find out which what fields are available? but it's not as detailed as I need.

The reason why I need to know the submitter is the following:

* I want to develop some kind of "wallet" for my website. For that purpose, I have installed the "profiles" module and I have created a "wallet" profile type with a single field: "Balance". So every user will have a "balance".
* I have also created a webform called "New transaction" where users will submit deposits and/or withdrawals. This webform has, among other fields, a field "status" and a field "amount".
* When a user submits a "new transaction", the webform submission gets stored with a status "VERIFYING" and an email handler sends an email to the administrator of the website (no WebformHandler is involved here).
* The administrator receives the email and reviews the deposit/withdrawal. If it is OK, the administrator updates the status of the submission to "ACCEPTED". It is in that moment (when the administrator updates the submission) when the WebformHandler does its magic. It adds/substracts the amount to the balance of the wallet profile that belongs to the user that made the submission. This is why I need to know the user that created the webform submission. I need to do the following to retrieve the wallet profile of the user:

```
$wallet_profiles = \Drupal::entityTypeManager()->getStorage("profile")
  ->loadByProperties(['uid' => $user->id(),
    'type' => 'wallet_profile',
    'is_default' => 1,
  ]);

```

If anyone knows of a more elegant way to achieve this "wallet" concept, please let me know.

# Answer
> 2 votes
OK. I think I can answer myself: `$webform_submission->getOwnerId()` is what I need.

---
Tags: webforms
---


title: Get an entity URL, not its path alias

text:
# Question
Title: Get an entity URL, not its path alias
How can I get the URL of an entity without its alias?

This code just gives me the path alias, but what I actually want would be, for example, /en/node/1 instead of /en/node/my-title.

```
$entity->toUrl('canonical', ['absolute' => true, language' => $entity->language()])
  ->toString(true)
  ->getGeneratedUrl());

```

# Answer
You can add the option `'alias' => TRUE` to your route. See how the shortlink is tested in core

```
  // \Drupal\Tests\node\Functional\NodeViewTest
  public function testLinkHeader() {
    $node = $this->drupalCreateNode();

    $expected = [
      '<' . Html::escape($node->toUrl('canonical')->setAbsolute()->toString()) . '>; rel="canonical"',
      '<' . Html::escape($node->toUrl('canonical', ['alias' => TRUE])->setAbsolute()->toString()) . '>; rel="shortlink"',
    ];

    $this->drupalGet($node->toUrl());

    $links = $this->getSession()->getResponseHeaders()['Link'];
    $this->assertEquals($expected, $links);
  }

```
> 4 votes

---
Tags: entities, uri, 9
---


# Question
Title: How to ignore block region placements during config sync?
When we perform config export and import our block placements are getting hosed. Is there a way to no export block placements/regions?

# Answer
The Config Ignore module lets you configure configs to ignore during import and export.
> 2 votes

---
Tags: configuration
---


# Question
Title: What is the stable9 theme? When should I use it instead of stable?
https://www.drupal.org/node/3066038

Has this cryptic statement:

> However, defaulting to base theme: stable prevents automatic updates to the next major version of Drupal, since each major version may have a different version of "the stable theme"

and proceeds to list these without any explanation.

The READMEs in the relevant directories are no help.

> Warning: Themes that opt out of using Stable as a base theme will need continuous maintenance as core changes, so only opt out if you are prepared to keep track of those changes and how they affect your theme.

> Warning: Themes that decide to not use Stable 9 as a base theme will need continuous maintenance as core changes, so only opt out if you are prepared to keep track of those changes and how they affect your theme.

I have a Drupal 8 theme, I am upgrading to Drupal 9 should I specify stable or stable9? This is really confusing.

# Answer
> 2 votes
> **My theme is extending Drupal 8 Stable, what should I do?**
>
> Upgrading to a Stable 9 can be a tedious task. Therefore, we have decided to continue to support previous versions of Stable. Drupal 8 Stable will be shipped in Drupal 9 along Stable 9. Drupal 8 Stable will be deprecated during the Drupal 9 lifecycle to be removed in Drupal 10 so that the theme can be moved into a contrib project.

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

# Answer
> -1 votes
If you want to use it you have to enable the theme before using it.

e.g. drush theme:enable stable9

From the .info

description: A base theme using Drupal 9.0.0's core markup and CSS.

So in other words all the new markup in html plus the old markup, css etc in d9+

---
Tags: theming, 9
---


title: Meta content type

text:
# Question
Title: Meta content type
Drupal core allows creating content types. I wish to have several different content types, all with the same structure.

For example:

* Food
* Italian food
* Sicilian food

Each content type would share the same structure; if I add, or remove, a field the change should be reflected to each content type.

The reason I seek to use a parent content type, instead of using a taxonomy term field is that I could then adjust blocks to each child content type (for example a block about food in general, a block about general Italian food, a block about Sicilian food).

Is there a core way to do that?

# Answer
> 1 votes
I think you can use the Entity Inherit module which will allows entities to inherit certain fields from another entity.

> **How it works**
>
> You tell Entity Inherit, in /admin/config/entity\_inherit which fields are used to define an entity’s parent. For example you might create an entity reference field named field\_entity\_inherit\_parent for this purpose.
>
> Then, every time any entity is modified:
>
> If other entities inherit from it, and have the same fields, and the child’s field has the same values as the parent field before it was changed, the “child” entities’ fields are updated to reflect the parent entity’s new value.

---
Tags: 8, entities
---


# Question
Title: Disable a field if another field is disabled
I need to disable field **A** if field **B** is disabled too. Actually, my current field **A** has the following #states (altered using hook\_alter\_form) to disable it if field **B** or field **C** are empty:

```
/**
 * Implements hook_form_alter().
 */
function my_module_form_alter(&$form, $form_state, $form_id) {

  $form['field_a']['#states'] = [
    'disabled' => [
      [':input[name="field_b[0][value][date]"]' => ['empty' => TRUE]],
      'or',
      [':input[name="field_c[0][value][date]"]' => ['empty' => TRUE]],
    ],
  ];
}

```

And it works perfectly, but I need to add the condition mentioned before. I found this in the official documentation: https://www.drupal.org/docs/drupal-apis/form-api/conditional-form-fields and I tried to use some of them like 'readonly' or 'readwrite' but this didn't work. Can I evaluate properties like '#disabled' from here? something similar to this:

```
function my_module_form_alter(&$form, $form_state, $form_id) {

  $form['field_a']['#states'] = [
    'disabled' => [
      [':input[name="field_b[0][value][date]"]' => ['empty' => TRUE]],
      'or',
      [':input[name="field_c[0][value][date]"]' => ['empty' => TRUE]],
      'or',
      [':input[name="field_b"]' => ['#disabled' => TRUE]],
    ],
  ];
}

```

# Answer
> 0 votes
You can't do this with states here is what the docs says

> The following states may be used when checking values of other fields:
>
> ```
> empty
> filled
> checked
> unchecked
> expanded
> collapsed
> value
>
> ```

So, for this particular feature you will need to use some javascript or jquery.

---
Tags: 8, forms
---


title: How to remove undesired local task tabs

text:
# Question
Title: How to remove undesired local task tabs
I have a node type 'faq'. For node type 'faq' I need to remove the tab 'node clone'.

For that I have done the following codes. In node\_clone.routing.yml I have the following code

```

node_clone.prepopulate_node:
  path: '/node/{node}/clone/prepopulate'
  defaults:
    _title: 'Clone content'
    _controller: 'node_clone.form_controller:getContentResult'
  requirements:
    _custom_access: 'node_clone.form_controller:access'
    #_node_add_access: 'node:{node_type}'
    node: '\d+'
  options:
    _node_operation_route: TRUE
    parameters:
      node:
        type: 'entity:node'
```

In my controller file

```
public function access(AccountInterface $account, NodeInterface $node) {

      $node_type = ($node->getType());
      if($node_type=="faq")
      {
          $access = new AccessResultForbidden();

      }

    if ($account->hasPermission('clone node') || ($node->uid->value === $account->id() && $account->hasPermission('clone own nodes'))) {
      $access = new AccessResultAllowed();
    }

    else {
      $access = new AccessResultForbidden();
    }
    $access->addCacheableDependency($node);
    $access->cachePerPermissions();
    if ($access->isAllowed()) {
      $access = $access->andIf($node->access('view', $account, TRUE));
    }
    if ($access->isAllowed()) {
      $node_type = NodeType::load($node->getType());
      $access = $access->andIf($this->nodeAddAccessCheck->access($account, $node_type));
    }
    return $access;
  }

```

Please help me to find out what's wrong with my code? Is this enough or I should do something else?

# Answer
To completely remove the tab from all pages you can use hook\_local\_tasks\_alter().

```
function mymodule_local_tasks_alter(&$local_tasks) {
  unset($local_tasks['local_task_to_remove']);
}

```

Where `local_task_to_remove` is the tab you want to remove.

To have it removed from some pages you could use hook\_menu\_local\_tasks\_alter() instead. Something like:

```
function mymodule_menu_local_tasks_alter(&$data, $route_name) {
  $routes = ['entity.entity_view_display.node.default', ...]; // put other routes in place of '...'
  if (in_array($route_name, $routes)) {
    unset($data['tabs'][0]['local_task_to_remove']);
  }
}

```
> 14 votes

# Answer
Your `$access` variable is overwritten with the original Node Clone logic that looks at whether the user has the permission. Hence, it will never return an `AccessResultForbidden` object on the `faq` content type and deny access to the route.

You should avoid hacking the Node Clone module, the module has incomplete feature to add/exclude node types (the project is still in the dev phase). Looking at the project, it looks like all that's needed is update the setting form (to update the per-node type settings) and `_custom_access` function to read in those settings. You should utilize that and create a patch for the project if you're going down that that route.

However, if you're insistent on overriding Node Clone's route permissions, you can override it's access permission using a `RouteSubscriber`:

```
  // see link for an example RouteSubscriber.php & example.services.yml

  /**
   * Inside your module's RouteSubscriber::alterRoutes method
   */
  public function alterRoutes(RouteCollection $collection) {
    if ($route = $collection->get('node_clone.prepopulate_node')) {
      $route->setRequirement('_custom_access', '\Drupal\example\Routing\RouteSubscriber::nodeCloneAccessOverride');
    }
  }

  /**
   * An example override _custom_access override.
   */
  public static function nodeCloneAccessOverride(AccountInterface $account, NodeInterface $node) {
    if ($node->getType() == 'faq') {
      return new AccessResultForbidden();
    }
    else {
      return new AccessResultAllowed();
    }
  }

```
> 1 votes

# Answer
If using drupal 8/9 you can enable or disable them from the block layout. The blocks for these are:

* Tabs
* Primary Tabs
* Secondary Tabs

Also make sure that the block region you assign to is being outputted in your twig template.

e.g. for the header region it is something like {{ page.header }}
> -1 votes

---
Tags: 8
---