# Question
Title: correct syntax for feeding lat/long to geofield_latlon in migration
I have a drupal 6 site I wish to migrate to drupal 8.

My configuration includes:

**migrate\_plus.migration.upgrade\_d6\_node\_complete\_club.yml**

```
# ...
class: Drupal\node\Plugin\migrate\D6NodeTranslation
field_plugin_method: null
cck_plugin_method: null
# ...
source:
  plugin: d6_node_complete
  node_type: club
# ...
process:
  # ...
  field_latitude:
    -
      plugin: get
      source: field_latitude
  field_longitude:
    -
      plugin: get
      source: field_longitude
# ...

```

When I run `drush migrate:import`, the `club` content is correctly migrated.

I wish the drupal 8 `club` content to include a geofield.

Following https://www.drupal.org/node/2866147, I modified the configuration to be:

```
# ...
process:
  # ...
  field_latitude:
    -
      plugin: get
      source: field_latitude
  field_longitude:
    -
      plugin: get
      source: field_longitude
  field_geofield:
      plugin: geofield_latlon
      source:
        - field_latitude
        - field_longitude
# ...

```

I manually added (using the web ui) a new `field_geofield` to the drupal 8 `club` content-type. Then I did `drush migrate:rollback upgrade_d6_node_complete_club` and `drush migrate:import upgrade_d6_node_complete_club`.

However, the drupal 8 `club` new geofield always just has latitude:longitude coordinates of 1:1.

---

I looked at `web/modules/contrib/geofield/src/Plugin/migrate/process/GeofieldLatLon.php` and saw:

```
  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    $value = array_map('floatval', $value);
    list($lat, $lon) = $value;

```

I added a `var_dump($value)` at the top. It shows that with the process YAML as above, `transform()` receives `$value` like:

```
array(2) {
  [0]=>
  array(1) {
    [0]=>
    array(2) {
      ["value"]=>
      string(9) "50.854334"
      ["delta"]=>
      string(1) "0"
    }
  }
  [1]=>
  array(1) {
    [0]=>
    array(2) {
      ["value"]=>
      string(9) "-0.553837"
      ["delta"]=>
      string(1) "0"
    }
  }
}

```

I don't need the geofield\_latlon plugin anywhere else for the migration, so I could just prefix `transform()` with:

```
$value = array_map(function($k){return $k[0]['value'];}, $value);

```

Is there a way to adjust just the YAML, without having to write any code, so that geofield\_latlon receives its data in the correct format?

I feel that using something like the extract plugin ought to be possible but am having difficulty finding any good description of the semantics of migrate YML config files.

# Answer
this may be too late. But I had a similar issue. The latittude and longitude was not getting set in the geofield. I had named the fields coming in from source as lat and lng. So I had:

```
field_event_geo:
    -
      plugin: geofield_latlon
      source:
        - lat
        - lng

```

Looking at the transform() function in modules/contrib/geofield/src/Plugin/migrate/process/GeoField.php, I realized that it was looking for value\['lon'\]. So I changed my migrate yml to:

```
field_event_geo:
    -
      plugin: geofield_latlon
      source:
        - lat
        - lon

```

(after changing the source field from lng to lon ofcourse) and it sets the geofield's lat,lon correctly.
> 0 votes

---
Tags: 8, migrations
---


# Question
Title: Primary tabs display differently for different roles?
In my Drupal 8 site (using the Seven theme), the primary tabs navigation are displaying differently for different roles. See screenshots below.

It would appear that for the limited Editor role, it's showing the tabs in some sort of space saving '...' dropdown menu (all the other tabs are hidden underneath the '...').

The browser windows are the same size and there is clearly plenty of room for all of the tabs as you can see in the Admin view.

What's going on here? How can I make the tabs on the Editor role look like they do on the Admin role?

Here's how it looks for the Admin role (good):

Here's how it looks for a limited Editor role (bad):

# Answer
> 1 votes
Apparently, this is known thing with the Seven theme where if the browser is zoomed in, this collapsed tabs view will trigger. Here is more info:

Tabs may not display correctly in seven theme if browser zoom is set

> Per several comments this is occurring when the browser zoom function is in use. Display works as expected when browser zoom is set to 100%.

Resetting browser zoom to 100% solves issue... temporarily anyway. Once the user zooms in/out or has their browser's default zoom set to anything other than 100%, the collapsed tab view will be shown.

Seeking a permanent fix!

---
Tags: 8, navigation
---


# Question
Title: Module is not longer supported on Drupal 8 but requires 8?
I'm updating a Drupal 8 site that hasn't been touched in about a year (just updated to 8.9.12). One of the module updates is Menu Token.

The module page reads:

> **Drupal 7.x and 8.x versions**
> No longer supported.

But for the latest version (9.1.0-alpha1), it reads:

> Requires Drupal: ^8 || ^9

So... I'm confused. Is this safe to install on D8? 8 isn't supported, but it requires 8?

---

*Screen shot of Menu Token page:*

# Answer
> 2 votes
Yes, it should be fine to install.

**Then why does it say "no longer supported"?**

Drupal 8 is end of life, so it is no longer receiving feature fixes or security patches. As a result, work on Drupal 8 (but not 9) modules is no longer being done. So, there is "no support" because "only the Drupal 9 version is supported."

However, the module still works just as well as it did before support ended for Drupal 8-- it's safe to install.

In other words, "not supported" can be interpreted as "please don't file bug reports/feature requests if you are still on Drupal 8."

**What does "requires" mean?**

"Requires" in the **Downloads** section is a hard technical requirement-- you must have one of the listed versions of Drupal to install the module.

# Answer
> 4 votes
Drupal 8 releases have been programmatically marked as unsupported, in the same way it was done for Drupal 6 releases time ago. They are marked as unsupported because, once a Drupal branch is unsupported, no security issue will be handled by the Drupal.org Security Team, for that Drupal branch and any module compatible with that Drupal release.

What reported as *Requires Drupal: ^8 || ^9* isn't the required Drupal versions but, more exactly, the Drupal versions with which the module is compatible. A release that is compatible with Drupal 8 and Drupal 9 is usually necessary to migrate a site to Drupal 9.
That doesn't mean a module that is compatible with Drupal 8 is always safe to be installed on Drupal 8; it could contains a security issue when the module runs on Drupal 8 that nobody discovered. In the case a security issue is reported, it's up to the project maintainers fix it for Drupal 8.

Notice also that, when a release isn't covered by the security advisory policy, security issues could still be reported. What changes is how those security issues are reported: For releases covered by the security advisory policy, users are required not to report them publicly, but report them to the Drupal Security Team, privately; that isn't required for releases not covered by the security advisory policy, which include the alpha, beta, and release candidate releases.
The 9.1.0-alpha1 release shown in the screenshot isn't covered by the security advisory policy, which means that release is secure to be used on Drupal 8 in the same way it's secure to be used on Drupal 9.

# Answer
> 0 votes
I think it's just some clumsy wording. It's the **module's** versions 7.\* and 8.\* that are no longer supported. The module's version 9.\* is supported and would run on core versions 8 and 9.

---
Tags: updating
---


# Question
Title: how to know if a form_alter is being invoked through an ajax request?
I am altering a node add form using hook\_id\_form\_alter and inside that i am doing a drupal\_goto, if query parameter is missing a mandatory token value. Now, in the add node form, there is an image field. When i'm trying to upload that image, which is an ajax request without the token, the form\_alter function is invoked and hence fails.

Any help is appreciated!

# Answer
This is likely an AHAH issue. See Adding dynamic form elements using AHAH. The form is loaded from the cache and then the form alter is called irrespective of whether it is full post request or via Ajax. You might want to change the logic in a way to save the result of checking the token the first time the form\_alter is called in a $\_SESSION variable (Save the token in the session variable). And change the logic to include an additional check for the presence of the same $\_SESSION variable if there is no token value, and if present if that token is valid (for security reasons).
> 0 votes

# Answer
You can detect ajax request with this code...

```
   if(!empty($_SERVER['HTTP_X_REQUESTED_WITH'])&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])=='xmlhttprequest'){
     // logic
   }

```

then setup variable with :

```
    drupal_add_js(array('myVar' => TRUE), 'setting');

```

This will be available in your js code as:

```
    Drupal.settings.myVar

```

So you can check if your variable is set before ajax callback will execute your code

```
  if(Drupal.settings.myVar == true) {
      return true;
  }

```

Hope this helps.
> 0 votes

# Answer
**Drupal 7**: For anyone still trying to figure out how to check whether `hook_form_alter` is being called by an AJAX request (like file uploader), you can use this:

```
$ajax = isset($form_state['input']['ajax_page_state']) && !empty($form_state['input']['ajax_page_state']);
if (!$ajax) {
  // ..anything that should not be called for AJAX should go here..
}

```
> 0 votes

---
Tags: ajax, forms
---


# Question
Title: Setting $order_item->setUnitPrice($price, TRUE);) stops cart items being merged, how to prevent this?
Drupal Commerce 2, with Drupal 9.

In the CART\_ENTITY\_ADD event, if i set $order\_item-\>setUnitPrice($price, TRUE); identical items added to the cart get added as new order items, but I want them to be merged.

If I comment out this line in my code the items get merged as expected and their quantity is summed.

How do i set the unit price without the order items being treated as distinct order items?

Relevant code of the CART\_ENTITY\_ADD event:

```
public function addToCart(CartEntityAddEvent $event) {
    $order_item = $event->getOrderItem();
    // update order item
    $order_item->setUnitPrice($price, TRUE);
    $order_item->save();
}

```

# Answer
> 0 votes
Hmmmmmmm rather than `order_item->save();`, try using the cart manager

```
// get the cart
$cart_provider = \Drupal::service('commerce_cart.cart_provider');
$cart = $cart_provider->getCart('default');
// update the cart
$cart_manager = \Drupal::service('commerce_cart.cart_manager');
$order_item->setUnitPrice($price, TRUE);
$cart_manager->updateOrderItem($cart, $order_item);

```

<sub>**Bonus:** Some methods/functions you might find useful.</sub>

---
Tags: commerce
---


# Question
Title: How can I specify the relation type between two entities?
I am new two Drupal

Trying to create two entities, `Post` and `Category` (This is for tests purposes)

A `Post` can have one `Category`, and a `Category` can have multiple `Post`

Here is my implementation of the field `category_id` on the `Post` entity:

```
  $fields['category_id'] = BaseFieldDefinition::create('entity_reference')
  ->setLabel(t('Category'))
  ->setDescription(t('The Name of the associated category.'))
  ->setSetting('target_type', 'test_category')
  ->setSetting('handler', 'default');

```

My questions are:

1. is There a way to define the type of relationship (hasOne in this case)
2. What is the purpose of the handler? if someone can point me to a documentation explaining what we can do with a handler in this kind of situations.
3. On `Category` entity, Should I reference the `Post` entity to get posts of a category for example.

I am using Drupal 9.3, I've a Symfony backgroud

# Answer
> 3 votes
1. No, entity references are not synonymous with DB relationships; in my experience it rarely helps to think about them as such.
2. It's the entity selection handler; the plugin which manages which entities are available to be added to the field instance. See https://www.axelerant.com/blog/writing-entity-reference-selection-plugin for an example.
3. You could, but there might not be any point - the fields won't know about each other or interact with each other, so you'd end up having to manage to separate fields for the same relationship, which is just awkward. Views does have a reverse entity reference relationship feature, so depending on requirements the functionality you need might already be there.

---
Tags: entities, 9
---


# Question
Title: Updated from Drupal 8.9.20 to 9.0.0, but can't run update.php due to errors
Here's what I get when attempted to run update.php:

**Requirements problem**

Errors found

**MISSING UPDATES FOR: SYSTEM** The installed version of the System module is too old to update. Update to a version prior to 9.0.0 first (missing updates: system\_post\_update\_layout\_plugin\_schema\_change, system\_post\_update\_entity\_reference\_autocomplete\_match\_limit).

**MISSING UPDATES FOR: TAXONOMY** The installed version of the Taxonomy module is too old to update. Update to a version prior to 9.0.0 first (missing updates: taxonomy\_post\_update\_configure\_status\_field\_widget).

**MISSING UPDATES FOR: TEXT** The installed version of the Text module is too old to update. Update to a version prior to 9.0.0 first (missing updates: text\_post\_update\_add\_required\_summary\_flag).

**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\_limit\_operator\_defaults, views\_post\_update\_remove\_core\_key).

# Answer
> 0 votes
The answer is in the messages: "Update to a version prior to 9.0.0 first". Upgrade to the newest version of Drupal 8 first before upgrading to Drupal 9.

"Update" means also executing schema updates, either with update.php or with `drush updatedb`.

---
Tags: views, updating
---


# Question
Title: Creating config schema file for mutable data
I have a custom module where I need to have a couple different types of configuration, both immutable and mutable. The immutable portion contains a feed URL for a couple different sites, so I have `/my_module/config/install/my_module.settings.yml` set up like this:

```
sites:
  site1:
    channel_url: 'http://www.site1.org/feed/channels'
  site2:
    channel_url: 'http://www.site2.com/feed/channels'
list_time: 24

```

That works fine, and I can read from it via `$config-get();`.

The second part of my settings involves mapping of tids between the two sites (used for importing video nodes from one site to another. My initial thought was to modify the settings like so:

```
sites:
  site1:
    channel_url: 'http://www.site1.org/feed/channels'
    mappings:
      1: 1
      2: 2
      3: 3
  site2:
    channel_url: 'http://www.site2.com/feed/channels'
    mappings:
      7: 7
      8: 8
      9: 9
list_time: 24

```

However, since this is mutable, it appears that this isn't allowed (based on the error messages I get when I try to run `$config->set()`.

From what I'm finding, it looks like I need to have a separate schema config file for my mapping data. I'm still wading through docs, but if someone could verify if I'm correct in my thinking and maybe provide a sample of what my schema should look like, I'd appreciate it.

**UPDATE:** Reading through this change record, it appears that I can write to my settings file if I declare it in my form class in `getEditableConfigNames()`, which I've done:

```
protected function getEditableConfigNames() {
  return ['my_module.settings'];
}

```

It also appears that, according to the error message I get, I need to retrieve it with `\Drupal\Core\Config\ConfigFactoryInterface::getEditable()`

```
Drupal\Core\Config\ImmutableConfigException: Can not set values on immutable configuration my_module.settings:sites. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object in Drupal\Core\Config\ImmutableConfig->set() (line 27 of core/lib/Drupal/Core/Config/ImmutableConfig.php).

```

Just keep swimming....

**UPDATE2:** Base on @berdir's comment below, I'm showing what I have, since in my original question, I didn't state that I am already using the ConfigFormBase class:

```
class MyModuleAdminForm extends ConfigFormBase {

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

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

    // build form here

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

  /**
   * {@inheritdoc}.
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {

  }

  protected function getEditableConfigNames() {
    return ['my_module.settings'];
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();
    $config = $this->config('my_module:settings');

    foreach($values as $site => $mappings) {
      if (is_array($mappings)) {
        foreach ($mappings as $source_channel => $target_channel) {
          $config->set('sites',[$site => ['mappings' => [$source_channel => $target_channel]]]);
        }
      }
    }
     $config->save();

    parent::submitForm($form, $form_state);
  }
}

```

However, this still gives me the same error. Am I using $this-\>config() incorrectly? Or do I still need to use getEditable() somewhere?

# Answer
I got past this error with the code I had above after figuring out one tiny issue. The code in `ConfigFormBaseTrait::config()` (called with `$this->config()` in a form that uses `ConfigFormBase`) has the following code:

```
if (in_array($name, $this->getEditableConfigNames())) {
  // Get a mutable object from the factory.
  $config = $config_factory->getEditable($name);
}
else {
  $config = $config_factory->get($name);
}

```

For some reason `in_array()` was returning FALSE, even though I had `my_module.settings` returned from `getEditableConfigNames()`. The eagle eyed will note that in my last update in the original question I had

```
$this->config('my_module:settings');

```

but in `getEditableConfigNames()` I had

```
return ['my_module.settings'];

```

The difference was the period vs the colon in the config value. Sigh.

With that change, `config()` loads `getEditable()` instead of `get()`, and I'm off and running.
> 0 votes

# Answer
Mutable or Immutable has nothing to do with config schema, that's something else.

`getEditableConfigNames()` only works if you actually implement \Drupal\Core\Form\ConfigFormBase and $this-\>config().

Otherwise you need to explicitly get the config.factory service or \Drupal::configFactory() and then call getEditable() on that, instead of get().
> 2 votes

# Answer
when it's immunable you should use configFactory.
for example:

```
$alertConfig = \Drupal::configFactory()
  ->getEditable('sitewide_alert.settings');

$alertConfig->set('alert_styles', "test|TestValue")->save();

```
> 0 votes

---
Tags: 8, configuration
---


title: Applying a patch - how?

text:
# Question
Title: Applying a patch - how?
Im trying to install Radix on Drupal 9 (Drush 10) - Installation keeps failing in composer / drush en radix and I have tracked it down to a current "bug" (or atleast a closed bug now) which someone wrote a patch for (#12) - I feel daft but how do one apply this patch?

I read somewhere on another post that I need to add this to my composer.json, but I am not sure to which section or required syntax. Sorry I cannot be more helpful with more information but hoping someone in the community can assist?

# Answer
It's super easy - you don't need to go through composer or anything like that (although if you maintain a website and need a lot of patches to keep it working, it's useful to learn how to use composer in the long run).

Here's how you do it:

Go to the directory where the 'radix' module is installed. Relative to web root, this should be something like `/modules/radix` or `/modules/contrib/radix`. Download the patch into that directory - for example, you can use `wget https://www.drupal.org/files/issues/2022-01-11/3173811.patch` or you can use ftp or any other method you like.

Then, in the same directory where you download the patch, use the command `patch -p1 < 3173811.patch`.

This assumes you are using a variety of Unix for your website - these commands are available on most distributions. If you are on Windows, you can also find these exact commands but you might have to install the commands yourself.

If that is still too big a barrier, for this patch at least, fixing the code manually is always an option. The patch just corrects two "use" statements:

```
-use Robo\Task\Archive\loadTasks as ArchiveTaskLoader;
-use Robo\Task\Filesystem\loadTasks as FilesystemTaskLoader;
+use Robo\Task\Archive\Tasks as ArchiveTaskLoader;
+use Robo\Task\Filesystem\Tasks as FilesystemTaskLoader;

```

The patch is saying that the first two lines need to be deleted (that's what the minus sign means) and the second two lines need to be added in the same place (that's what the plus sign means). The format of the patch uses the first column to show you what to change - if there is nothing in the first column, the line doesn't get changed. If there is a - in the first column, the line gets deleted. If there is a + in the first column, the line gets added. That first column is only used in the patch, it should not appear in the code either before or after you change it.
> -2 votes

---
Tags: 9, composer
---


title: How do you implement a breadcrumb?

text:
# Question
Title: How do you implement a breadcrumb?
I've tried to define a new breadcrumb override, but I'm still getting the site default.

I've created a custom module, foo\_breadcrumb:

```
   - modules/custom/foo_breadcrumb
     - foo_breadcrumb.info.yml
     - foo_breadcrumb.services.yml
     - src/
         - BreadcrumbBuild.php

```

Here's the `foo_breadcrumb.services.yml`:

```
services:
    foo_breadcrumb.breadcrumb:
        class: Drupal\foo_breadcrumb\BreadcrumbBuild
        tags:
            - { name: breadcrumb_builder, priority: 100 }

```

Inside `src/BreadcrumbBuild.php`, I have:

```
<?php

namespace Drupal\foo_breadcrumb;

use Drupal\Core\Breadcrumb\BreadcrumbBuilderBase;

class BreadcrumbBuild implements BreadcrumbManager {
    /**
     * {@inheritdoc}
     */
    public function applies(array $attributes) {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function build(array $attributes) {
        $breadcrumb[] = $this->l($this->t('Test'), NULL);
        $breadcrumb[] = $this->l($this->t('Test2'), 'test');
        return $breadcrumb;
    }
}
?>

```

I started working off the only writeup I could find on Drupal 8 breadcrumbs, but the thing is it appears to be using an older version of the PSR-4 autoloading that is no longer in place (for the record I'm on 8.0.0-dev-beta3), and so I went by how all the other modules work in the codebase.

Now I'm fairly certain this correct to get the module to load; however I'm not sure if

```
class BreadcrumbBuild extends BreadcrumbBuilderBase

```

is correct. The problem is that the old tutorial I linked to mentions extending from `BreadcrumbBuilderBase`, but the more current docs don't seem to mention it and I wonder if it's out of date - and how I should do this.

Likewise, I don't really understand what the `services.yml` file is doing in this regard, there's no documentation anywhere for this.

# Answer
> 8 votes
Yeah breadcrumb changed and the documentation must be update.

> Likewise, I don't really understand what the services.yml file is doing in this regard, there's no documentation anywhere for this.

For Drupal 8: The Crash Course | DrupalCon Amsterdam 2014, awesome presentation, about 47:02:

Drupal 8 in 2 steps:

1. Build a tool
2. Wire it up

The wiring may vary, the approach is the same.

How we "Wire it up" the breadcrumb:

For http://www.palantir.net/blog/d8ftw-breadcrumbs-work:

> Now we need to tell the system about our class. To do that, we define a new service (remember those?) referencing our new class. We'll do that in our \*.services.yml file, which exists for exactly this purpose
>
> Similar to an "info hook" in previous Drupal versions, we're defining a service named mymodule.breadcrumb. It will be an instance of our breadcrumb class. If necessary we could pass arguments to our our class's constructor as well. Importantly, though, we also tag the service. Tagged services are a feature of the Symfony DependencyInjection component specifically and tell the system to automatically connect our builder to the breadcrumb manager. The priority specifies in what order various builders should be called, highest first. In case two applies() methods might both return true, whichever builder has the higher priority will be used and the other ignored.

You can use this code for you aim:

Structure (not matter much):

```
- modules/custom/foo_breadcrumb
  - foo_breadcrumb.info.yml
  - foo_breadcrumb.services.yml
  - src/
    - Breadcrumb/
      - BlogBreadcrumbBuilder.php

```

foo\_breadcrumb.services.yml:

```
services:
  foo_breadcrumb.breadcrumb_blog:
    class: Drupal\foo_breadcrumb\Breadcrumb\BlogBreadcrumbBuilder
    tags:
      - { name: breadcrumb_builder, priority: 100 }

```

BlogBreadcrumbBuilder.php:

```
class BlogBreadcrumbBuilder implements BreadcrumbBuilderInterface {
  use StringTranslationTrait;
  use LinkGeneratorTrait;

  /**
   * @inheritdoc
   */
  public function applies(RouteMatchInterface $route_match) {
    // This breadcrumb apply only for all articles
    $parameters = $route_match->getParameters()->all();
    if (isset($parameters['node'])) {
      return $parameters['node']->getType() == 'article';
    }
  }

  /**
   * @inheritdoc
   */
  public function build(RouteMatchInterface $route_match) {
    $breadcrumb = [Link::createFromRoute($this->t('Home'), '<front>')];
    $breadcrumb[] = Link::createFromRoute($this->t('Blog'), '<<<your route for blog>>>');
    return $breadcrumb;
  }
}

```

**Remember, clear cache at the end.**

# Answer
> 10 votes
Here we go again. These answers are mostly right. One thing you can't forget about is "cache tags" and "cache contexts".

I was setting up a taxonomy term on a node as a breadcrumb.

I got it working with advice from this post, but then I clicked around and noticed the same breadcrumbs on every page.

Long story short, make sure to set some cache contexts and tags.

Here's my service in a gist: https://gist.github.com/jonpugh/ccaeb01e173abbc6c88f7a332d271e4a

Here's my build() method:

```
/**
 * {@inheritdoc}
 */
public function build(RouteMatchInterface $route_match) {
  $node = $route_match->getParameter('node');
  $breadcrumb = new Breadcrumb();

  // By setting a "cache context" to the "url", each requested URL gets it's own cache.
  // This way a single breadcrumb isn't cached for all pages on the site.
  $breadcrumb->addCacheContexts(["url"]);

  // By adding "cache tags" for this specific node, the cache is invalidated when the node is edited.
  $breadcrumb->addCacheTags(["node:{$node->nid->value}"]);

  // Add "Home" breadcrumb link.
  $breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));

  // Given we have a taxonomy term reference field named "field_section", and that field has data,
  // Add that term as a breadcrumb link.
  if (!empty($node->field_section->entity)) {
    $breadcrumb->addLink($node->field_section->entity->toLink());
  }
  return $breadcrumb;
}

```

# Answer
> 8 votes
# **Update 2016 Drupal 8**

The Documentation states that you must return an instance of the breadcrumb class. If you are having trouble getting it to work. here is the solution that worked for me.

```
<?php

//modules/MY_MODULE/src/MyBreadcrumbBuilder.php

namespace Drupal\registration;

use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Link;

class MyBreadcrumbBuilder implements BreadcrumbBuilderInterface {

    /**
     * @inheritdoc
     */
    public function applies(RouteMatchInterface $route_match) {
        /* Allways use this. Change this is another module needs to use a new custom breadcrumb */
        return true;
        /* This code allows for only the registration page to get used by this breadcrumb
         * $parameters = explode('.', $route_match->getRouteName());
         * if ($parameters[0] === 'registration') {
         *     return true;
         * } else {
         *     return false;
         * }
         */
    }

    /**
     * @inheritdoc
     */
    public function build(RouteMatchInterface $route_match) {
        $parameters = explode('.', $route_match->getRouteName());
        $b = new Breadcrumb();
        if ($parameters[0] === 'registration') {
            /* If registration page use these links */
            $b->setLinks($this->buildRegistration($parameters[1]));
        }
        return $b;
    }

    /**
     * Creates all the links for the registration breadcrumb
     * @param type $page
     * @return type
     */
    private function buildRegistration($page) {
        return [
            Link::createFromRoute(t('Step One'), 'registration.one'),
            Link::createFromRoute(t('Step Two'), 'registration.two'),
            Link::createFromRoute(t('Step Three'), 'registration.three'),
            Link::createFromRoute(t('Step Four'), 'registration.four'),
            Link::createFromRoute(t('Step Five'), 'registration.five'),
            Link::createFromRoute(t('Step Six'), 'registration.six'),
            Link::createFromRoute(t('Step Seven'), 'registration.seven')
        ];
    }

}

```

Then the yml file

```
# modules/MY_MODULE/registration/MY_MODULE.services.yml
services:
  registration.breadcrumb:
    class: Drupal\registration\MyBreadcrumbBuilder
    tags:
      - { name: breadcrumb_builder, priority: 100 }

```

PS: if you are using **bootstrap** go to your `/admin/appearance/settings` settings page and look at the breadcrumbs settings. `Show 'Home' breadcrumb link` should be checked on. And `Show current page title at end` should be checked off.

After all this is done clear your cache. Everytime you change a YML file, even in debug mode, you need to clear your cache. you can go to `/core/rebuild.php` if you get stuck and can't rebuild.

# Answer
> 7 votes
## Don't forget caching

The render cache was changed fairly late in the D8 development cycle, and so it's not mentioned in the d8ftw series, or the other answers to this question.

The Cache API documentation refers specifically to render arrays, but all of those instructions apply equally to Breadcrumbs. Breadcrumbs have a `toRenderable()` method, Drupal will try to cache them in the render cache, and that means you **must** specify enough information to allow Drupal to do it properly.

The details are in the docs, but the short version is that `Breadcrumb` implements the `RefinableCachableDependencyInterface`. In your builder class, you'll want to call `addCachableDependency()` with any and all entities or configuration objects that are used to build the breadcrumb. The documentation for 'CacheableDependencyInterface & friends' goes into more detail of how and why.

If there are other contexts where the breadcrumb might change, you'll also need to manually use `addCacheContexts()` to make sure the block varies, `addCacheTags()` to make sure the cache entry can be correctly invalidated, and `mergeCacheMaxAge()` if the cache is time-sensitive and needs to expire.

If this isn't done properly, one of your custom Breadcrumb builder services will 'win', and the breadcrumbs for that one specific page will be served on every page, to all visitors, forever.

# Answer
> 5 votes
There is another way to achieve this.

```
/**
 * Implements hook_preprocess_breadcrumb().
 */
 function theme_name_preprocess_breadcrumb(&$variables){
  if(($node = \Drupal::routeMatch()->getParameter('node')) && $variables['breadcrumb']){
    $variables['breadcrumb'][] = array(
     'text' => $node->getTitle()
   );
  }
}

```

And then create another file in your theme's template folder named as "breadcrumb.html.twig" and put below code in this file :

```
{% if breadcrumb %}
  <nav class="breadcrumb" role="navigation" aria-labelledby="system-breadcrumb">
    <h2 id="system-breadcrumb" class="visually-hidden">{{ 'Breadcrumb'|t }}</h2>
    <ul>
    {% for item in breadcrumb %}
      <li>
        {% if item.url %}
          <a href="{{ item.url }}">{{ item.text }}</a>
        {% else %}
          {{ item.text }}
        {% endif %}
      </li> /
    {% endfor %}
    </ul>
  </nav>
{% endif %}

```

Thats it. Now flush the cache and you will get breadcrumb with current page title like Home/Current Page Title. You can change the separator by replacing "/" with the desired one.

# Answer
> 2 votes
You should use a contrib module to add the current page title to the breadcrumb such as Current Page Crumb: https://www.drupal.org/project/current\_page\_crumb

If wanted to hand-code it, you can pull the code from the src folder of that module. You can find more details about Drupal 8 breadcrumbs here: http://www.gregboggs.com/drupal8-breadcrumbs/

# Answer
> 1 votes
One of best guide at https://www.drupal.org/node/2876622

Specifically caching is missing in many of the answers which should be added in the build function

```
// Don't forget to add cache control by a route.
// Otherwise all pages will have the same breadcrumb.
$breadcrumb->addCacheContexts(['route']);

```

# Answer
> 0 votes
I had used Custom Breadcrumbs using token in Drupal 7 and when that module was not available for Drupal 8 I ended up creating views for my individual content types using the fields that were originally the token fields. Using it as a block and disabling the normal breadcrumb. It was a bit more work than Custom Breadcrumbs but it works.

---
Tags: 8, breadcrumbs
---


# Question
Title: The values returned from hook_node_access_records() aren't considered to allow access
I am implementing a solution in Drupal 9 where users are allowed to see only the nodes that belongs to their same group. If a node doesn't belong to any group, t hey should be able to see it. I've used `hook_node_grants()` to assign the right grants to the current user and `hook_node_access_records()` to set the view grant per node, as suggested in How do I filter a view by the results of hook\_node\_access?

When visiting a node a user isn't supposed to see, the user gets a 403 error, as expected result. On a view, the node is visible, though.

As workaround, I could implement `hook_views_query_alter()` and add an access condition, but I prefer more generic solution.

This is the code I am using.

```
 function mymodule_node_access_records(NodeInterface $node) {
  if ($node->hasField('field_group') && !empty($term = $node->field_group->getValue())) {
    $term = reset($term);
    $grants[] = [
      'realm' => 'mymodule_realm',
      'gid' => $term['target_id'],
      'grant_view' => 1,
      'grant_update' => 0,
      'grant_delete' => 0,
      'priority' => 0,
    ];

    return $grants;
  }
}

 function mymodule_node_grants(AccountInterface $account) {
  $grants = [];
  if ($group = checkGroupHelper($account)) {
    $grants['mymodule_realm'] = $group;
  }
  return $grants;
}

```

# Answer
I've managed to get this working by adding Query tag **node\_access** under my view's Query settings. It started filtering results based on the node\_access table. Never seen it as a requirement, so that's a bit strange, but hopefully it can help others wondering like me.
> 0 votes

---
Tags: views, nodes, hooks
---


# Question
Title: $group->addContent() in hook_node_insert() doesn't update the access permissions for the node
I have a content type with a field that lets the users decide which group to add the content to.

The content is added to the group via `hook_node_insert()`.

```
function tm_wiki_node_insert(NodeInterface $node) {
  $type = $node->getType();
  if ($type == 'mycontent') {
    $group = Group::load('1');
    $group->addContent($node, 'group_node:mycontent');
  }
}

```

It works: I can see the node is properly added to the group. However, users who aren't members of the group can still view the content, even though group permissions would not allow this.

When I manually edit and save the node once, the permissions are correctly set; users who aren't group members cannot view the node.

What code should I add to make the node only viewable from group members?

I don't understand the problem, since `hook_node_insert()` should be invoked after the entity is saved, and `$group->addContent()` should not require an additional save to set permissions properly.

# Answer
> 0 votes
I found the problem - it probably has to do with social\_groups submodule, which adds a field for content visibility (field\_content\_visibility) - this field is not set properly when just adding the content via group-\>add content.

---
Tags: nodes, 9, group
---


# Question
Title: Media migration results in numerous unexpected file usage records (CSV source): How to do this correctly?
I'm migrating lots of records from a non-Drupal site into Drupal 9. The records have file 'attachments,' and I want these to be media in the Drupal site.

I have all the files already on the server where they need to permanently live and have all the paths/URI's stored with all the other site data in CSV files.

Successful so far: I can migrate the URIs into file entities without errors, using the migrate\_source\_csv module (along with migrate\_plus and migration\_tools)

The media items have some meta data, so I need to migrate them in separately. This is where results have been interesting.

* I can migrate the media in from the same source CSV file and use the migration\_lookup plugin to create the media entities and relate them to their files.
* I can also migrate the media in using entity\_lookup plugin with very similar results.

In both cases, everything seems normal except that many thousands of file uses of generic.png are generated. Generic.png is not in my source data. I think it comes from the media module.

I can remove these uses from the file\_usage table without any *apparent* negative consequences, but I'm uneasy doing that. This is a partial migration for test purposes, so... 12,552 items created. I hesitate to do the whole thing and move on to migrating in the 'nodes' until I understand what's going on here and potential consequences.

At this stage, I'm using a custom media type called 'document'

The file+media with dependency and migrate\_lookup configuration files look like this:

The files file...

```
uuid: 1bcec3e7-0a49-4473-87a2-6dca09b91abjan-docf
id: docfiles_import
label: "Import files for doc media type"
migration_group: docfilesmedia
source:
  plugin: 'csv'
  path: '/srv/imports/docmedia122.tab'
  delimiter: "\t"
  enclosure: '"'
  header_offset: null
  ids: [filename]
# not using most of these fields in the file import
# but including because maybe needed for grouping
# and migrate_lookup in the media import
  fields:
    0:
      name: filename
      label: 'Unique filename'
    1:
      name: title
      label: 'description'
    2:
      name: doctype
      label: 'document type'
    3:
      name: formflag
      label: 'FormYN'
    4:
      name: newpath
      label: 'path'

process:
  uid:
    plugin: default_value
    default_value: 2
  uri: newpath
  status:
    plugin: default_value
    default_value: 1
 # 1 equals 'permanent'
destination:
  plugin: entity:file

```

The media file...

```
uuid: 1bcec3e7-0a49-4473-87a2-6dca09b91abjan-docmed
id: docmedia_import
label: Import media of document type
migration_group: docfilesmedia

source:
  plugin: 'csv'
  path: '/srv/imports/docmedia122.tab'
  delimiter: "\t"
  enclosure: '"'
  header_offset: null
  ids: [filename]
  fields:
    0:
      name: filename
      label: 'Unique filename'
    1:
      name: title
      label: 'description'
    2:
      name: doctype
      label: 'document type'
    3:
      name: formflag
      label: 'FormYN'
    4:
      name: newpath
      label: 'path'

process:
  name: title
  uid:
    plugin: default_value
    default_value: 179
  field_media_document/target_id:
  # above is name of the file entity ref field
    plugin: migration_lookup
    migration: docfiles_import
    source: filename
    # Unclear how this works. I think it means
    # 'create target ids, using filename field to determine
    # which row to use in the csv file'
  field_doctype_select:
    plugin: entity_generate
    source: doctype
    value_key: name
    bundle: document_type
    entity_type: taxonomy_term
    ignore_case: true
  field_formcheckbox: formflag

migration_dependencies:
  required:
    - docfiles_import
  optional: []

destination:
  plugin: entity:media
  default_bundle: document

```

The files & media migration examples I've been able to find all have assumptions that differ from my situation (not csv, files need to be moved or created or copied, Drupal to Drupal, etc.). So I'm sure I've just made errors in adapting the guidance.

Ideas on how to do to it right or understand what's wrong? If a solution preventing the phantom file-usage items can't be found, am I probably safe removing these from the file\_usage table and acting like it never happened?

I'm also seeing this error intermittently. I don't know if it's related. Since the mysql seems to work fine, I've been assuming it has something to do with using a csv rather than database source?

\[error\] Message: Failed to connect to your database server. The server reports the following message: /No database connection configured for source plugin variable/. * Is the database server running? * Does the database exist, and have you entered the correct database name? * Have you entered the correct username and password? * Have you entered the correct database hostname?

# Answer
I have come to believe this is normal behavior. The media system uses thumbnails, and the thumbnails count as file uses. The result is that if the imported media are documents, a generic document thumbnail is used once for each imported item.

If the imported media are images, the generic thumbnail isn't used because the image file is used. So the uses column in the admin/content/files list will show 2 uses for each imported image (assuming no other content is yet using them).

Removing the uses from the file\_usage table (in mysql) doesn't seem to hurt anything, so far. But leaving them there doesn't seem to hurt anything either.
> 0 votes

---
Tags: media, migrations, 9
---


# Question
Title: print description and field value directly in taxonomy-term--drzava.html.twig
First I disable view for taxonomy-term, so I can use taxonomy-term--drzava.html.twig, where drzava is name of vocabulary.

How to print description and filed value for taxonomy-term directly, without using

```
field--taxonomy-term--description--drzava.html.twig

```

`{{ content.description }} or {{ content.field_flag_code}}`

I have problem to analyze devel output. I try `{{ content.description.value }}` but its do not work.

and for field, I try something like this but its do not work. `{{ content.field_flag_code.0.value }}`

In Devel there is **Definition**, **Render** and **Load**, what from this tri tabs I need to look for twig?

Thanks for the help in advance.

# Answer
The description field is a formatted text field which should be printed as processed text render element:

**taxonomy-term.html.twig**:

```
{{ {
  '#type': 'processed_text',
  '#text': term.description.value,
  '#format': term.description.format,
} }}

```

If you want to get rid of the `<p>` tag you have to configure the field with a a different text format or use `|render|striptags` on a variable stored like in the linked topic.

The other field value:

```
{{ term.field_flag_code.0.value }}

```
> 1 votes

# Answer
I remembered. I hadn't used drupal for a while, so I forgot.

I use Devel:

```
{{ kint(content.description['#items'].getValue()|first.value) }}

```

and in `taxonomy-term--drzava.html.twig`, I Use

```
{{ content.description['#items'].value }}

```

This is my output. But I don't understand why its display `<P></P>`
> 1 votes

---
Tags: taxonomy-terms, 9
---


title: How do I update a Lightsail server?

text:
# Question
Title: How do I update a Lightsail server?
I have decided I want to learn Drupal. To that end, I fired up an AWS Lightsail server with a Drupal site, to play around with. Having taken AWS's default Drupal 9 install and logged in, it is displaying this message in the config screens:

> There is a security update available for your version of Drupal. To ensure the security of your server, you should update immediately! See the available updates page for more information and to install your missing updates.

This default site is running Drupal 9.3.2, but apparently the latest security update is 9.3.3.

I can download the tarball, but how do I now apply this update without destroying my site?

I've been googling away, but there doesn't appear to be clear instructions that I can locate.

# Answer
> 2 votes
*I can download the tarball, but how do I now apply this update without destroying my site?*

You delete (very important not to overwrite!) and replace certain directories and files. See https://www.drupal.org/docs/updating-drupal/updating-drupal-core-manually

```
cd /path/to/your/drupal/directory
rm -rf core vendor
rm -f *.* .[a-z]*
wget https://ftp.drupal.org/files/projects/drupal-x.y.z.tar.gz
tar zxf drupal-x.y.z.tar.gz
cd drupal-x.y.z
cp -R core vendor /path/to/your/drupal/directory
cp *.* .[a-z]* /path/to/your/drupal/directory

```

Using your browser, run update.php by visiting http://www.example.com/update.php

---
Tags: 9, updating
---


# Question
Title: How to do views bulk operations on all matches, not just a page
I have a lot of nodes to delete on a Drupal 9 site. I thought I could use the Content view, select the node type, click select all and Delete.

However it seems that select all only selects the visible nodes, i.e. page 1. I have many pages of results!

Is there a way to select *all* matched rows?

# Answer
> 2 votes
Do not be confused between "node operations bulk form" and "views bulk operation form".

In Drupal 9 (probably 8, can't recall), Views got incorporated into core. Knowing this, and seeing "node operations bulk form" on the *view* which now in D9 is used for the `/admin/content` page I thought the Views Bulk Operations (VBO) module must also be included. But it's not.

So you still need to install VBO if you need this functionality.

Then you need to add the Views Bulk Operations field to the Content view, and remove the Drupal core one named "node operations bulk form" (otherwise it crashes).

---
Tags: views, 9
---


# Question
Title: How do I install my own, custom module dependant on Composer?
I've looked all over, but there seems to be no advice on this online.

I've recently updated a Drupal 8 site to Drupal 9. I wasn't using composer before, and so I've used composerize-drupal to make the site composer compatible.

I have my own custom module on the site, and I had to uninstall it to get the composerize-drupal and then the upgrade to work.

I'm now trying to reinstall it, but there is a complete lack of guidance on this coming up in google searches, and if I just upload it to the site as before, the site breaks.

Can anybody please help shed some light on how this can be done on a Compserized Drupal 9 site?

# Answer
In `composer.json` you tell Composer in which directories it should put certain types of dependencies.

```
"installer-paths": {
    "web/core": ["type:drupal-core"],
    "web/libraries/{$name}": ["type:drupal-library"],
    "web/modules/contrib/{$name}": ["type:drupal-module"],
    "web/profiles/contrib/{$name}": ["type:drupal-profile"],
    "web/themes/contrib/{$name}": ["type:drupal-theme"],
    "drush/Commands/contrib/{$name}": ["type:drupal-drush"]
},

```

These directories are now managed by Composer. For example `web/modules/contrib` for type `drupal-module` dependencies. While at the same time everything put in `web/modules/custom` or any other custom location will be preserved.

Your repo in the end basically only contains the `composer.json/lock` files at the repo root and all custom code (custom themes, custom modules, custom scripts, custom patches etc.) and config YAML files in their desired directories.

---

You should gamble around a bit with the official recommended-project template or the community drupal-project template. Learn to read the `composer.json` file. Run `composer install`, manually delete certain directories, `composer install` again and observe what happens.
> 2 votes

# Answer
`composerize-drupal` creates the following directories for Composer dependencies:

* `[drupal-root]/modules/contrib`
* `[drupal-root]/themes/contrib`
* `[drupal-root]/profiles/contrib`

By convention (or at least the convention I follow), custom stuff goes in a `custom` directory.

* `[drupal-root]/modules/custom`
* `[drupal-root]/themes/custom`
* `[drupal-root]/profiles/custom`
> 1 votes

---
Tags: 9, composer
---


title: How do I control config names?

text:
# Question
Title: How do I control config names?
When creating a config entity, we get an example\_entity.schema.yml file:

```
example_module.example_entity.*:
  type: config_entity
  label: 'Example config'
  mapping:
    id:
      type: string
      label: 'ID'
    label:
      type: label
      label: 'Label'
    uuid:
      type: string

```

Creating entities of this type will result in config names, where the asterisk is replaced with the "id" property of the entity:

```
example_module.example_entity.name_1
example_module.example_entity.name_2
...

```

But how to control, which property is used and how to add support for more properties? For example, in core's `core.entity_form_display.*.*.*`, what is mapping the entity type to first wildcard, the entity bundle to second and the display mode to third?

# Answer
> 1 votes
The remainder of the config name is by definition the ID:

*core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php*

```
 * Configuration object names of configuration entities are comprised of two
 * parts, separated by a dot:
 * - config_prefix: A string denoting the owner (module/extension) of the
 *   configuration object, followed by arbitrary other namespace identifiers
 *   that are declared by the owning extension; e.g., 'node.type'. The
 *   config_prefix does NOT contain a trailing dot. It is defined by the entity
 *   type's annotation.
 * - ID: A string denoting the entity ID within the entity type namespace; e.g.,
 *   'article'. Entity IDs may contain dots/periods. The entire remaining string
 *   after the config_prefix in a config name forms the entity ID. Additional or
 *   custom suffixes are not possible.

```

However, it is possible for the config entity class to override `id()` with a computed compound ID. Like in the example you've mentioned:

*core/lib/Drupal/Core/Entity/EntityDisplayBase.php*

```
  public function id() {
    return $this->targetEntityType . '.' . $this->bundle . '.' . $this->mode;
  }

```

---
Tags: entities, configuration, importing-exporting
---


# Question
Title: Frontpage title outputs a node's title and ADDS quotation marks
If a given node (page, article, etc) is visited, their site title (generated by {{ head\_title|safe\_join(' | ') }} is displayed correctly:

```
My Page Title | Sample Website

```

If the same node is then configured to be the **frontpage** and is visited as such `/`, the title of the node gets pretty quotation marks added to it:

```
“My Page Title” | Sample Website

```

I've NO idea where these are coming from. I have been able to confirm this only happens in the front page node by changing the assigned node. This happens regardless of the type of node or content in it.

Dumping the head\_title variable reveals that the quotation marks are already present when twig receives them. When looking at Devel, it shows that the title contains no quotes. I've already looked for custom code in the theme that would cause this with no luck. Of course, I can address this by replacing the characters in twig but it doesn't seem like the right way to go here.

My suspicion is that this is being caused by drupal/metatag but I've been unable to identify a configuration or line of code that may be causing this.

How would you go about troubleshooting/tracing this?

I'm running Drupal 9.3.3.

# Answer
Contrary to what I had initially thought, this *was* coming from a template. In this case, the `field__node__title.html.twig` file was adding these but it was only displaying in certain cases due to the theme. This was resolved by making this template more specific. Thanks to the Drupal Slack channel for helping bounce some ideas!
> 0 votes

---
Tags: meta-tags
---


# Question
Title: Why do some Drush commands only run from docroot?
Wondering if anyone knows why some Drush commands (with file parameters) only run from the docroot and won't run from the project/composer root?

Commands such as `drush sql-query` and `drush locale-import` are among these.

For example, with standard Drupal folder structure:

/ (composer root)

* composer.json
* vendor
* translations
    + translations.fr.po
* web (docroot)

running from composer root:

* `vendor/bin/drush locale-import fr translations/translations.fr.po`

gives file not found error. Even using `./translations/translations.fr.po` gives same error

but going to docroot and running:

* `../vendor/bin/drush ../translations/translation.fr.po`

works fine.

Our deploy scripts always run `composer`, `drush` and other commands from the composer root folder. So a bit of a pain to have to `cd /web` and then `cd ..` for these couple "special" Drush commands. Guessing there must be something I am doing wrong.

# Answer
> 0 votes
Clive didn't post as an answer so I will just copy here:

Drush commands run as if from the web root (not execution path) as the working directory. So even though running command from the project root; argument paths have to be entered as if coming from the web root.

vendor/bin/drush locale-import fr ../translations/translations.fr.po

* from the project root

David's answer would also work if you were using aliases (which I am not).

# Answer
> 0 votes
If you use a drush alias, it shouldn’t matter where you run the command from e.g

```
drush @site some-command

```

The webroot is specified in the alias.

More info https://www.drush.org/latest/site-aliases/

---
Tags: 8, drush
---


# Question
Title: How do I use "DOES NOT CONTAIN" with \Drupal\Core\Entity\Query\QueryInterface?
I have a node with a list field of text values. I want to write a query that gets all nodes that don't have one of the selected values.

How do I write this query?

```
$query->condition('field_states_excluded', $state, 'DOES NOT CONTAIN');

```

# Answer
You can make use of NOT REGEXP if we assume that `$state` is an array of multiple states.

I will explain with example:
for example if want to get all nodes with the **field title** **DOES NOT CONTAIN** `page`, `hello`, and `test`.

**Sql statement** should be something like:

```
SELECT * FROM `node_field_data` WHERE `type` = 'page' AND `title`  NOT REGEXP '^.*page.*$|^.*hello.*$|^.*test.*$';

```

**Drupal Code**:

```
  $excluded_strings = array('page', 'hello', 'test');
  //- Add regex prefix and suffix
  $excluded_strings_with_regex = array_map(function ($val) {
    return '^.*' . $val . '.*$';
  }, $excluded_strings);
  //- Join array elements with a string | glue
  //- result $regex_p_string = "^.*page.*$|^.*hello.*$|^.*test.*$"
  $regex_p_string = implode("|", $excluded_strings_with_regex);
  //-Build Query
  $query = \Drupal::entityQuery('node');
  $query->condition('status', 1);
  $query->condition('type', 'page');
  //- Add regex Condition.
  $query->condition('title', $regex_p_string, 'NOT REGEXP');
  $nids = $query->execute();

```
> 3 votes

# Answer
The only operators supported by `QueryInterface::condition()` are the following:

* `=`, `<>`, `>`, `>=`, `<`, `<=`, `STARTS_WITH`, `CONTAINS`, `ENDS_WITH`
* `IN`, `NOT IN`
* `BETWEEN`

You cannot use `NOT REGEXP`, since Drupal 8 doesn't support it, but you can use NOT IN, as @Clive and @Berdir suggested, if you have an array of values the field should not have.
Since you are talking of states, I agree with @Berdir it's more probable that is your case. I think more difficult somebody would exclude states (which are a limited set of values) using regular expressions.
> 2 votes

# Answer
It is possible to use `NOT LIKE`.

Entity Query version:

```
$database = \Drupal::database();
$query = \Drupal::entityQuery('node')
 ->condition('field_states_excluded', "%" . $database->escapeLike($state) . "%", 'NOT LIKE');
$node__ids = array_values($query->execute());

```

Raw Database query - by title.

```
$database = \Drupal::database();
$result = $database->select('node_field_data', 'n')
  ->fields('n', ['nid', 'title'])
  ->condition('title', "%" . $database->escapeLike($state) . "%", 'NOT LIKE')
  ->execute()
  ->fetchAllAssoc('nid');
$node_ids = array_keys($result);

```

Raw Database query - by a field value.

```
$database = \Drupal::database();
$field_name = 'field_states_excluded';
$query = $database->select('node_field_data', 'n')
    ->fields('n', ['nid', 'title']);
$query->join("node__{$field_name}", 'field', 'n.nid = field.entity_id');
$result = $query->condition("field.{$field_name}_value", "%" . $database->escapeLike($state) . "%", 'NOT LIKE')
    ->execute()
    ->fetchAllAssoc('nid');
$node_ids = array_keys($result);

```
> 0 votes

---
Tags: 8, database
---


# Question
Title: Migration bringing in duplicate taxonomy terms
I have a very simple taxonomy term migration (migrate module, that lets in duplicate terms for no reason I can figure out. I have tried explicitly setting allow\_duplicates to False, even though that should be the default behavior, but nothing changes. The base migration that this migration inherits from just sets up a db connection object, sets up team description variables, and sets some configuration variables. It also sets up a few helper methods that are not used in this migration.

Here is the migration class:

```
class EnviroscopeKeywordMigration extends BaseEnviroscopeMigration
{
    public function __construct($arguments)
    {
        parent::__construct($arguments);

        $this->description = t('import Keyword data');
        $query = $this->getConnection()
            ->select('doc_keyword', 'k')
            ->fields('k', array('ID', 'NAME'));

        $this->dependencies = array("GeoArea");

        $this->source = new MigrateSourceSQL($query, array(), NULL, array('map_joinable' => FALSE));

        $this->destination = new MigrateDestinationTerm('keywords');
        $this->map = new MigrateSQLMap($this->machineName,
            array(
                'ID' => array(
                    'type' => 'int',
                    'length' => 11,
                    'not null' => TRUE,
                    'description' => 'Keyword ID',
                ),
            ),
            MigrateDestinationTerm::getKeySchema()
        );

        $this->addFieldMapping('name', 'NAME');

        $this->addUnmigratedDestinations(array(
            'description',
            'parent',
            'parent_name',
            'format',
            'weight',
            'path',
            'pathauto',
        ));
    }

}

```

Can somebody, PLEASE help me debug why this might be bringing in duplicate terms like this:

# Answer
I ended up biting the bullet and writing it myself. I still don't know what was causing it to not work in the first place, but I replicated the desired behavior with this helper method in the migration class:

```
public function check_for_existing_term($taxonomy, $term) {
    $query = db_select('taxonomy_vocabulary', 'v')
        ->condition('machine_name', $taxonomy);
    $query->innerJoin('taxonomy_term_data', 'td', 'v.vid=td.vid');
    $new_tid = $query->fields('td', array('tid'))
        ->condition('td.name', $term)
        ->execute()
        ->fetchField();
    return ($new_tid) ? $new_tid : False;
}

```

In the constructor of the migration class I set `$this->taxonomy = 'keywords';` and I used that in `$this->destination = new MigrateDestinationTerm($this->taxonomy);`, then I added the following prepareRow:

```
    public function prepareRow($row)
    {
        $new_tid = $this->check_for_existing_term($this->taxonomy, $row->NAME);
        if ($new_tid) {
            $this->map->saveIDMapping($row, array($new_tid),
                MigrateMap::STATUS_IGNORED, MigrateMap::ROLLBACK_DELETE);
            $this->rollbackAction = MigrateMap::ROLLBACK_DELETE;
            return FALSE;
        } else {
            return TRUE;
        }
    }

```

This tries to find a matching term in the database for each row. If it finds it, it adds an entry in the map table and then returns FALSE so the migration won't do anything further for that row. If it is a new term it returns True, and the migration continue happily, adding in the new term.
> 2 votes

# Answer
One way I used to do this was use the built in prepareRow method. I would query and check for term exists by name for the vocabulary I am importing to. If I got a result, I would return false, which prevents that record from being migrated. Taxonomy terms are tricky.

In this case it does not sound like you have unique terms in the source database, so I'm not sure how you can flatten multiples down to just one term while preserving relational data on content that used those terms (who's ID has changed in Drupal).
> 0 votes

# Answer
There are two ways to eliminate duplicates. First the select-statement should have the "DISTINCT" qualification. Second there is a dedupe method for the proces. Online documentation will help you further, i.e. http://blog.studio.gd/node/5. But you must use the database-wrapper supplied by Drupal. Also adjust settings.php with a $databases 'migrate', 'default' declaration.
> 0 votes

# Answer
Just in case someone else would have the same problem on a drupal 9, I developed a small module containing a migrate process for that: https://www.drupal.org/project/migrate\_merge\_duplicated\_terms
> 0 votes

---
Tags: 7, migrations
---


# Question
Title: Ignore UUIDs when comparing the difference between configuration exports
When building Features, i find it useful to keep a 'backup' of the full configuration and commit it to version control.

If something breaks when i package a feature after i test how it works by doing a full re-install of the profile that brings together the feature modules, i can restore things i missed from the configuration export.

Unfortunately, every site install produces different UUIDs in every configuration file, so i cannot use a diff to determine if there are missing or unexpected changes in the site-install version of the configuration i packaged up. Drush does not have an export option to strip UUIDs on export.

In the past we used a script to delete all the UUID lines, but not being built into Drush, it was Python or Bash i think, it was awkward to use. But if i find it i'll post it.

How can i get a clean diff of changes that filters out the noise of the UUID changes?

# Answer
> 4 votes
For that interim step, when you just need to glance over the changes in your exported config, `git diff -I"^uuid: " -- config/sync` will return a succinct list that ignores the changes in any line starting with 'uuid: '.

from the doc page on Git-diff:

```
-I<regex>
--ignore-matching-lines=<regex>

    Ignore changes whose all lines match <regex>. This option may be specified more than once.

```

## but wait... there's more!

The deluxe version of this command ALSO filters out file deletions & the config\_hash, making the diff up to 76.3% more succinct (heh) -- all for FREE:

```
git diff -I"^uuid: " -I"config_hash" --diff-filter=MRC -- config/sync

```

And here's the doc reference for `--diff-filter`:

> --diff-filter=\[(A|C|D|M|R|T|U|X|B)…\[\*\]\] Select only files that are Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R), have their type \[...\]

# Answer
> 1 votes
The use case in question here is for building features; the `config/sync` directory is never used to import, but it can be used to check if the result of a `site install` is about what we expect (and to copy wanted files or changes we wanted to keep, and missed, from a saved version).

The meaningless UUID changes in every file, however, make it impossible to find that information in all the noise.

Here is a workaround that presumes you are using Git for version control, exporting configuration and committing it, then running a site install, and re-exporting the configuration (but not yet committing it):

```
git diff -G '^[^u]*([^u][^i][^d][^:]).*'

```

will show only files with non-uuid changes. If there's a change to a uuid other than the one for the configuration as a whole (that is, indented under some other part of the configuration), that will be shown.

Super unsure about the regex in this but it's not had a false negative or positive yet.

Here's what i have in my .bashrc to make this easier to use:

```
# Diff that ignores config files whose only change is the UUID (ignores lines
# starting with 'uuid:' and probably other stuff but it's solid so far.)
alias gdu="git diff -G '^[^u]*([^u][^i][^d][^:]).*'"

```

Took me forever to come up with this workaround; hope it helps others.

---
Tags: 8, features
---


# Question
Title: How to filter a View by Date Range (start, end)?
In Drupal 7 with Views an Date module enabled, it was pretty easy to filter a view by Date: The UI just gave you the option to do so.

In Drupal 8, however, the date field and views are part of core, but if you choose a date **range** field as filter in views it does not offer you date specific options anymore, but shows you only filtering options for text fields:

The date specific options, however, are available for internal date values like ´Content: Changed´

As I would like to show only specific nodes, with a date before or after the actual date, where the date is specified by a custom date range field, this does not suit my needs.

How can I filter a view in Drupal 8 by a date field with date specific operations?

# Answer
Surprisingly this is not possible with Drupal 8 yet. But there is a long history of trying to make it work: https://www.drupal.org/node/2786577 The last patch, you find in this post, seems to work. You can download and apply it, using the following commands:

```
wget https://www.drupal.org/files/issues/improve_the_views-2786577-76-core.patch
git apply improve_the_views-2786577-76-core.patch

```

If `git` isn't available on your server, try:

```
patch -p1 < improve_the_views-2786577-76-core.patch

```

TO apply the patches you have to navigate to the `core` folder first. And be aware that you have to reapply this patch, after committing a core update. (This sucks!) So let us hope, the Drupal Gods will get this into core soon!
> 14 votes

# Answer
I had to filter a content type containing the dates of auctions into three groups (now online, upcoming and ready to register). As this involved multiple daterange, I wrote a plugin based on this article: https://www.webomelette.com/creating-custom-views-filter-drupal-8

Basically is does three things: \- Convert the dates in the field to local date and time. \- The filter has three possible settings 'now online','upcoming' and 'other' \- Based on the settings it adds the possible where-clauses to the query

It works and seems robust to future updates.

```
    <?php

    /**
     * @file
     * Definition of Drupal\d8views\Plugin\views\filter\NodeTitles.
     */

    namespace Drupal\d8views\Plugin\views\filter;

    use Drupal\views\Plugin\views\filter\FilterPluginBase;
    use Drupal\views\Plugin\views\filter\InOperator;
    use Drupal\views\Plugin\views\filter\ManyToOne;
    use Drupal\views\ViewExecutable;
    use Drupal\views\Views;
    /**
     * Filters by given list of node title options.
     *
     * @ingroup views_filter_handlers
     *
     * @ViewsFilter("d8views_node_titles")
     */
    class NodeTitles extends FilterPluginBase {
        // exposed filter options
        protected $alwaysMultiple = TRUE;

        /**
         * Provide simple equality operator
         */
        public function operatorOptions() {
            return [
                'nu_online' => $this->t('Nu online'),
                'binnenkort' => $this->t('Binnenkort'),
                'anders' => $this->t('Anders'),
            ];
        }

        public function query() {
            //Get the current domain.
            //$domain = domain_get_domain();
            $nu_in_utc = new \DateTime('now', new \DateTimezone('UTC'));
            $nu_in_utc_in_iso = $nu_in_utc->format('Y-m-d\TH:i:s');
            $nu_date = $nu_in_utc->format('Y-m-d');
            /*
            * Voeg relatie met datum veiling toe
            */
            $configuration = [
                'table'      => 'node__field_datum_veiling',
                'left_table' => 'node_field_data',
                'left_field' => 'nid',
                'field'      => 'entity_id',
                'type'       => 'LEFT',
                'extra_operator'   => 'AND',
            ];
            $join = Views::pluginManager('join')->createInstance('standard', $configuration);
            $this->query->addRelationship('node__field_datum_veiling', $join, 'node_field_data');

            /*
            * Voeg relatie met online datum van de veiling
            */
            $configuration = [
                'table'      => 'node__field_datum_online',
                'left_table' => 'node_field_data',
                'left_field' => 'nid',
                'field'      => 'entity_id',
                'type'       => 'LEFT',
                'extra_operator'   => 'AND',
            ];

            $join = Views::pluginManager('join')->createInstance('standard', $configuration);
            $this->query->addRelationship('node__field_datum_online', $join, 'node_field_data');
            switch($this->operator) {
                case 'nu_online':
                    /*
                    * Condities voor 'Nu online'
                    */
                    //dpm('Nu online');
                    $this->query->addWhere('AND', 'node__field_datum_veiling.field_datum_veiling_end_value', $nu_in_utc_in_iso, '>');
                    $this->query->addWhere('AND', 'node__field_datum_online.field_datum_online_value', $nu_date, '<=');
                    break;
                case 'binnenkort':
                    /*
                    * Condities voor 'Binnenkort'
                    */
                    //dpm('Binnenkort');
                    $this->query->addWhere('AND', 'node__field_datum_veiling.field_datum_veiling_end_value', $nu_in_utc_in_iso, '>');
                    $this->query->addWhere('AND', 'node__field_datum_online.field_datum_online_value', $nu_date, '>');
                    break;
                case 'anders':
                    /*
                    * Condities voor 'Anders' (dwz online, binnenkort, maar nog niet geweest)
                    */
                    $this->query->addWhere('AND', 'node__field_datum_veiling.field_datum_veiling_end_value', $nu_in_utc_in_iso, '>');
                    break;
            }
        }
    }

```
> 1 votes

# Answer
Using interval-filter plugin you can choose two fields to be used respectively as minimum and maximum date, this introduces the concept of range. Then you can filter the views by specifying a date that must be contained or not contained in the range.

Take a look at: https://github.com/barsan-ds/interval-filter for examples
> 0 votes

# Answer
Currently Views is not very aware of date ranges. It can filter on the start or end date as separate filters but not the date range as a whole.

To enable filtering based on the date range I created the module Views Date Range Filters. Currently it has 3 additional filters for Datetime Range fields:

**Includes**

Filters by date ranges which include the supplied date.

**Overlaps**

Filters by date ranges which overlap with the supplied date range.

**Ends by**

Filters by date ranges which end by the supplied date. Equivalent to "End date \<= supplied date". Useful for grouped filters when using "Start date".
> 0 votes

# Answer
Custom Views Filter Module works well for me:
https://www.drupal.org/project/custom\_view\_filters

It adds a date range filter to a view. See this screenshot from the project page on drupal.org.
> -1 votes

# Answer
Date popup This module serve the purpose.
> -3 votes

---
Tags: views, 8, datetime
---


# Question
Title: How can I set validation rules on my entity fields and get errors if the data isn't valid
I have this entity which got the link field

This link is mandatory, has to be more than 3 chars and less than 255 Also it has to be a valid URL

```
class Myentity extends ContentEntityBase implements BaseEntityInterface {

  use EntityChangedTrait;

  public static function baseFieldDefinitions( EntityTypeInterface $entity_type )
  {
    $fields = parent::baseFieldDefinitions($entity_type);

    $fields['link'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Url'))
      ->setDescription(t('The entity url.'))
      ->setSettings(
        [
          'default_value' => '',
          'min_length' => 3,
          'max_length' => 255,
          'text_processing' => 0,
        ]
      )->setRequired(true)
      ->addConstraint('Length', ['min' => 3, 'max' => 255]);

  }

}

```

And then somewhere in the application, I want to save that entity

```
$data = ['link': 'X'];

$entity = Myentity::create($data);

$violationList = $entity->validate();

echo $violationList->count(); //Prints 0 ! although the length isn't good!

```

`setRequired(true)` guarantees me that the field `link` is mandatory

`addConstraint('Length', ['min' => 3, 'max' => 255])` Doesn't seem to work, As I didn't get any error while validating my data

So I've some questions about this code:

1. How do we set the validation rules for an entity, I saw two functions `addConstraint` and `setPropertyConstraints`. which one to use or there is another way ?
2. After validating data, and if `$violationList->count()` is positive, How do we get the rules that failed, I know `$violationList->getFieldNames()` returns the invalid field but not the rule that failed.
3. And last, what are the rules that Drupal 9 provides, are they the ones that are shipped with the Symfony Validator components as stated in Drupal's documentation OR there is a defined list.

# Answer
> 2 votes
I use addConstraint in my custom entities and haven't had a problem. I see your field definition is for "name" but your data says "link", maybe that's why?

Here's a snippet for getting the errors:

```
    $violations = $entity->validate();
    $errors = [];
    foreach ($violations as $violation) {
      $property = $violation->getPropertyPath();
      $field = explode('.', $property)[0];
      $label = $entity->get($field)->getFieldDefinition()->getLabel();
      $errors[] = $label . ': ' . $violation->getMessage();
    }

```

There's a list of core constraints here:

https://api.drupal.org/api/drupal/vendor!symfony!validator!ConstraintValidator.php/class/uses/ConstraintValidator/9.3.x

---
Tags: entities, 9
---


# Question
Title: Vague error message on config import: Config x depends on x that will not exist after import
I don't understand what is missing. It's just a simple blogpost content type that I created before I reset the db and tried to re-import it. All the modules requires are enabled and I did try to clear the cache. Run updb Tried `drush cim --partial`. nothing has worked. This is the error:

```
Import the listed configuration changes? (y/n): y
Drupal\Core\Config\ConfigImporterException: There were errors validating the config synchronization.                                                         [error]
Configuration <em class="placeholder">field.field.node.blog_post.field_post_category</em> depends on the <em
class="placeholder">field.storage.node.field_post_category</em> configuration that will not exist after import.
Configuration <em class="placeholder">field.field.node.blog_post.field_post_featured_images</em> depends on the <em
class="placeholder">field.storage.node.field_post_featured_images</em> configuration that will not exist after import.
Configuration <em class="placeholder">field.field.node.blog_post.field_post_video</em> depends on the <em
class="placeholder">field.storage.node.field_post_video</em> configuration that will not exist after import. in Drupal\Core\Config\ConfigImporter->validate()
(line 737 of /var/www/localvolumes/html/core/lib/Drupal/Core/Config/ConfigImporter.php).
The import failed due for the following reasons:                                                                                [error]
Configuration <em class="placeholder">field.field.node.blog_post.field_post_category</em> depends on the <em
class="placeholder">field.storage.node.field_post_category</em> configuration that will not exist after import.
Configuration <em class="placeholder">field.field.node.blog_post.field_post_featured_images</em> depends on the <em
class="placeholder">field.storage.node.field_post_featured_images</em> configuration that will not exist after import.
Configuration <em class="placeholder">field.field.node.blog_post.field_post_video</em> depends on the <em
class="placeholder">field.storage.node.field_post_video</em> configuration that will not exist after import.

```

# Answer
> 2 votes
The simple answer for this issue is, with your idea search for the missed configuration.

for example in

> Configuration core.entity\_form\_display.node.tool.default depends on the field.field.node.tool.field\_sha256sum configuration that will not exist after import.

search for `field.field.node.tool.field_sha256sum` on your idea and remove them from the dependencies of other file. Before

```
dependencies:
  config:
    - field.field.node.tool.body
    - field.field.node.tool.field_file
    - field.field.node.tool.field_tags
    - field.field.node.tool.field_sha256sum
    - node.type.tool

```

After:

```
dependencies:
  config:
    - field.field.node.tool.body
    - field.field.node.tool.field_file
    - field.field.node.tool.field_tags

```

then try to `drush cim` again.

just bear in mind you should remove all the missed configuration dependencies.

# Answer
> 0 votes
Answering my own question, hoping it may help others. The error message above, in my case, indicates a missing configuration file.

My workflow usually involves switching between branches and re-setting the database to its pristine state. Then I try to import the configuration before finishing a piece of work.

It turns out I did not commit some `field.storage.*` configuration files before I switched branches and re-set the database. Then the import failed and complained about missing configuration. Re-reading the error messages more carefully allowed me to understand the underlying issue.

I used my IDE (phpstorm) local history feature to search for the missing files and restore them. This fixed the issue.

# Answer
> 0 votes
I was getting this error when attempting to create a field without the "field\_" prepend on machine name. I went about the process by creating field as normal. Then I did a config export for the field and removed the field\_ from all the files modified/added.

What I missed that brought me to this error was simply that I forgot to rename the field and storage files. i.e. renaming those 2 files such as field.field.commerce\_order.default. **field\_** syncdb\_id.yml to field.field.commerce\_order.default.syncdb\_id.yml was all that was left to successfully import.

---
Tags: configuration
---


# Question
Title: Display Fulltext search query string on Search Results page
This is probably much simpler than I'm imagining.

Client wants to display the user-entered search query string, with a label (like **Search Query** or **You Searched For**), at the top of the search results page.

Currently, the search query is displayed in the form input field (a Views exposed form, in a block) but it has `<input size="25">`, so many queries are too wide to display.

I've been looking at the fields available in Views. Some contain the query data or are based upon it, such as "Search: Solr score debugging (indexed field)" and "Search: Excerpt" (with "Use highlighted field data" checked). But I have not been able to find the straight query string, unaltered. Nor does it appear that this is a field I can add to the Default Solr Index.

This question is a bit old (Drupal 7) but it does make it seem like this is going to be *way* more trouble than it should be, especially considering that this string is already being rendered on the Search Results page (just not where the client wants to see it).

This question is an apparent duplicate, but it is unanswered. And this question from 2011 concerns Drupal 6 and is old enough that it's likely irrelevant.

I don't think these software versions will make much of a difference, but just in case:

```
Solr 8.8.2
Drupal 9.3.3
Search API Solr 4.2.6

```

**Update** (January 25, 2022)

I edited the View for "Search (Index Default Solr content index)" and added a Header of type `Global: Text area`.

In the configuration for this Header, I made sure to check the box for "Use replacement tokens from the first row".

In order to access the user-entered value for the Fulltext search input, I set the Header Content to the following Basic HTML:

```
<p>
  <strong>You searched for:</strong>
  {{ raw_arguments.search_api_fulltext }}
</p>

```

Here's a screenshot of the Views config:

This is literally all the client asked for, just about as simple as can be.

Unfortunately, it only works in the Views preview with contextual filters. I can't get the string to render on the actual Search Results page.

Here's a screenshot of a query string in the Preview with contextual filters:

And here's a detail showing the way this is actually rendered:

Note that the user-entered string is still visible in the Fulltext search input field, but not in the Header.

I do note that the actual search results page is at the path:

```
/search?search_api_fulltext="coding+standard"

```

In the Views preview, however, the path is shown as:

```
/search/%22coding%20standard%22

```

If I manually enter that path instead of the one obtained by submitting the Fulltext search, the header shows the expected results, but the form input field is not used at all!

What am I missing here? I feel certain that I am very close.

# Answer
> 1 votes
Search API Fulltext passes the value as a query parameter, with the URL path:

```
/search?search_api_fulltext="coding+standard"

```

Using the View Contextual Filter instead, however, the path uses URL segments instead of query parameters:

```
/search/%22coding%20standard%22

```

With the path parameter, I could use the Token to provide the value for "You searched for:" but the "Search documentation ..." text input field could not access the value.

With the query string, the "Search documentation ..." text input field could access the value, but the Token couldn't.

The solution, obvious in hindsight, was to configure Views so that when the filter value is not in the URL, the contextual filter falls back on the default value provided by the query parameter `search_api_fulltext`:

With this fallback in place, the Token value is now available in the header, and the "Search documentation ..." text input field still contains the previous search string as a default value.

---
Tags: views, search, 9
---


# Question
Title: How can I access or expose the Commerce data in $order->data[] to the Rules module?
Following this old checkout\_pane\_example.module tutorial, I created a custom Drupal 7 Commerce checkout pane. It's simply a text field to collect special order instructions from the customer.

```
function checkout_pane_example_pane_checkout_form($form, &$form_state, $checkout_pane, $order) {

  $pane_form['nickname'] = array(
    '#type' => 'textfield',
    '#title' => t('Your nickname'),
    '#description' => t("We'd like to call you by your nickname."),
    '#default_value' => !empty($order->data['nickname']) ? $order->data['nickname'] : '',
    '#required' => TRUE,
  );

  return $pane_form;
}

```

The pane works fine. Anything that's saved in the text area is then stored in `$order->data['nickname']`.

The problem is that I need to access the data in Rules so I can attach it to the existing email that's sent out on order completion email.

How can I access or expose that data via the Rules module?

# Answer
You can't really expose `data` as such, but you can define your own order property via `hook_entity_property_info()` with a custom callback that returns the specific value from the `data` array you want.

For an example, take a look at `commerce_order_entity_property_info()`'s definition of the `mail_username` property and the related `commerce_order_get_properties()` callback.
> 1 votes

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


title: Custom styled tables

text:
# Question
Title: Custom styled tables
I am trying to figure out a way for a content editor (with little to no coding experience) to add and style tables within their content. I was planning on creating a paragraph type where the editor could choose the various options to style their table and then add the table content via CKEditor.

Where I'm running into trouble is figuring out how to add classes to `<table>` that gets generated by CKEditor. Is there a way to do this? Or, alternatively, is there a different way I should be following to create and style tables within the content?

# Answer
> 0 votes
I was able to solve this issue by using the "Styles" dropdown.

Using the "Full HTML" text format (Configuration \> Content authoring \> Text formats and editors) you can drag the "Styles" dropdown from the available tools into the toolbar. You'll then have the option to add classes under CKEditor plugin settings \> Styles dropdown.

When a user is editing content (using a text format that has this enabled), they'll be able to click on a table and choose a class from the Styles dropdown.

---
Tags: theming
---


# Question
Title: Which is better way of injecting service to controller with __construct or $instance = parent::create($container)
I'm always using this way of injecting service to controller:

```
<?php
namespace Drupal\TestModule\Controller;

    use Drupal\Core\Controller\ControllerBase;
    use Symfony\Component\DependencyInjection\ContainerInterface;

    class TestModuleController extends ControllerBase {

      protected $testModule;

        public function __construct(TestModule $testModule) {
        $this->testModule = $testModule;
      }

      public static function create(ContainerInterface $container) {
        return new static(
          $container->get('testModule.service')
        );
      }

      public function testModule() {
        return [
          '#type' => 'markup',
          '#markup' => $this->testModule->getTestModule(),
        ];
      }
    }

```

But with drupal console I generate Controller with service (drupal gcon command) and get different code:

```
<?php
    namespace Drupal\TestModule\Controller;

    use Drupal\Core\Controller\ControllerBase;
    use Symfony\Component\DependencyInjection\ContainerInterface;

    class TestModuleController extends ControllerBase {

      protected $testModule;

      public static function create(ContainerInterface $container) {
        $instance = parent::create($container);
        $instance->testModule = $container->get('testModule.service');
        return $instance;
      }

      public function testModule() {
        return [
          '#type' => 'markup',
          '#markup' => $this->testModule->getTestModule(),
        ];
      }
    }

```

Is this second way better than first and which should I use?

# Answer
TL;DR: The second way is better.

The constructor method `__construct()` is considered internal, you can not *(savely)* overwrite it. E.g. the number or type of mandatory function parameters might change. Therefore the first version's code might break even within a minor update of Drupal core. Only the second version is guaranteed to work at least until the next major version release.

For more information I'd suggest reading this Change record from the Webform module.
> 3 votes

---
Tags: 9, services, dependency-injection
---


title: Debug "Access Denied"

text:
# Question
Title: Debug "Access Denied"
Is there a way for debugging "Access Denied" errors in Drupal 8? I'm having some routing/permission issues, and I would like to be able to debug why i'm getting "Access Denied".

# Answer
> 12 votes
Install the devel module and then Web Profile module which is bundled with it. You will then see the Symfony web profiler bar below the browser screen. Click on a Request gear icon, and it will show you the route and the controller class. You can start there.

You can also search your code base for that route name and see, if there are additional cases when it is handled.

# Answer
> 3 votes
This is super old, but in case anybody, like me, is looking for an answer to this, here's how I did it.

During development, I create a page that allows me to play with and investigate various Drupal services. I'll just give the code I have for that page controller.

```
<?php

/**
 * @file
 * Contains \Drupal\my_module\Controller\MyControllerClass
 */

namespace Drupal\my_module\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Routing\AccessAwareRouterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MyControllerClass extends ControllerBase implements ContainerInjectionInterface {

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

  /**
   * The router service.
   *
   * @var \Drupal\Core\Routing\AccessAwareRouterInterface
   */
  protected $router;

  /**
   * The access manager.
   *
   * @var \Drupal\Core\Access\AccessManagerInterface
   */
  protected $accessManager;

  /**
   * The controller class for my testing page.
   *
   * @return array
   */
  public function page() {
    // I create a user account that has the permission(s) I need.
    $account = $this->entityTypeManager->getStorage('user')->load(2);

    // If you need to get the route name:
    $route_name = $this->router->match('/the/path/to/check')['_route'];

    // You can create route parameters if any are needed.
    $parameters = [];

    // Checking the access.
    $debug = $this->accessManager->checkNamedRoute($route_name, $parameters, $account, TRUE);

    ksm($debug);

    return ['#markup' => $this->t('The page markup.')];
  }
}

```

When you view the page created by the above controller, it should give you an object with the information about the access check. You can see which AccessResult is returned, and one of the properties of the object is 'reason'.

It will most likely not give you all the answers you need, but it's a place to start.

This should work on both Drupal 8 and Drupal 9. If using Drupal 9, be aware that the Kint module is not part of the Devel module. It is part of the PHP required by Drupal 9. You can check out How to properly setup Devel and Kint on Drupal 9? • AltaGrade. More information about the checkNamedRoute() method: AccessManager::checkNamedRoute | AccessManager.php | Drupal 9.0.x | Drupal API

---
Tags: 8, routes, debugging
---


# Question
Title: Link to images in form view creates wrong url
I noticed this after drupal 9 update, but I've tried to find the exact moment when it was broken and I couldn't find it. I use S3 and cloudfront for images so maybe the problem is related with that config.

Apparently, the images work well (that's why I didn't realize it was broken). Images load correctly in my frontend and even the little preview in the backend is correctly shown. The problem is the link to the original file.

For instance, as you can see, the twitter image is working correctly (it's been shown in the backend) but if I follow the "twitter.jpg" link above the image, it sends me to:

```
<a href="/https%3A//test-web-development.s3.eu-west-1.amazonaws.com/s3fs-public/2022-01/twitter.jpg" type="image/jpeg">twitter.jpg</a>

```

The big problem is it's adding a "/" before the image link itself and instead of just using the url itself. On top of that, it's writing a "url-safe" so the "https://" is transformed into "htttps%3A//".

According to debug, it's using this template and I don't see anything strange in it (I tried a different theme too, but still failed):

```
<!-- BEGIN OUTPUT from 'core/themes/claro/templates/field/file-link.html.twig' -->

```

Any idea on what can be causing this?

# Answer
> 2 votes
I think your issue is the same as the one described here: https://www.drupal.org/project/drupal/issues/3254553

It seems to be fixed now with this commit: https://git.drupalcode.org/project/drupal/-/commit/879b39ee5c5

If the Drupal core update will not help you, try to use some of the working patches in the issue thread temporary until Drupal core itself will not fix this issue for you.

---
Tags: views, theming, forms, files
---


# Question
Title: Drupal 7 and/or CKEditor adding paragraphs to code breaking styling
I've recently started a new job where I'm managing a Drupal 7 website for the first time. We will be moving away from this platform soon, but I have to maintain this site for the time being.

I'm trying to add a new form to one of our pages, but paragraph tags are being added after saving the code in the CKEditor which is breaking my styling.

Here is the relevant code added to CKEditor with rich text disabled:

```
<select id="scopeSelecter" name="scopeSelecter" onchange="primoScopeSwitch(this)">
<option value="Everything">Everything</option><option value="LibraryCatalog">Library Catalog</option>
<option value="CourseReserves">Course Reserves</option>
<option value="Theses">Theses</option></select>
<input id="primoQueryTemp" size="55" type="text" value="">
<input alt=" Search " id="go" onclick="searchPrimo()" title="Click to Search" type="button" value="Search">

```

When I inspect the output of the saved code, I see that it has place the input elements within a paragraph element:

```
<select id="scopeSelecter" name="scopeSelecter" onchange="primoScopeSwitch(this)">
<option value="Everything">Everything</option><option value="LibraryCatalog">Library Catalog</option>
<option value="CourseReserves">Course Reserves</option>
<option value="Theses">Theses</option></select>
<p><input id="primoQueryTemp" size="55" type="text" value="" placeholder="Discover books, articles, videos, etc.">
<input alt=" Search " id="go" onclick="searchPrimo()" title="Click to Search" type="button" value="Search"> </p>

```

Thanks for any advice.

# Answer
> 1 votes
This has to do with your CKEditor configuration and the fact that CKEditor tries to wrap tags around inline contents to help ensure the integrality of your content. I believe it is the config.autoParagraph option.

I tried reproducing your issue and globally disable this option (under the CKEditor profile edition page, section "Advanced options") but with no success.

Here, I give you two options to solve your issue:

* **Option1** \- Simple workaround - Wrap your input elements in any other tag not affected by the style to prevent CKEditor adding the `<p>` tag.

e.g. with a `<div>` tag:

```
<select id="scopeSelecter" name="scopeSelecter" onchange="primoScopeSwitch(this)">
    <option value="Everything">Everything</option><option value="LibraryCatalog">Library Catalog</option>
    <option value="CourseReserves">Course Reserves</option>
    <option value="Theses">Theses</option>
</select>
<div> <!-- Use this tag to wrap your input elements -->
    <input id="primoQueryTemp" size="55" type="text" value="">
    <input alt=" Search " id="go" onclick="searchPrimo()" title="Click to Search" type="button" value="Search">
</div>

```
* **Option 2** \- In your text format edition page (e.g. `admin/config/content/formats/filtered_html`), **untick** the box *Convert line breaks into HTML*. **I do not recommend this solution**, though, as it will impact all your content using this text format. Or, you might create a new text format to be used when the editor contains a form.

---
Tags: nodes, wysiwyg
---


# Question
Title: ERROR 1062 (23000): Duplicate entry '/-de' for key 'PRIMARY'
When importing a dump from a production site with mysql in a xampp environment I got this error:

```
ERROR 1062 (23000): Duplicate entry '/-de' for key 'PRIMARY'

```

These lines are affected:

```
ALTER TABLE `redirect_404`
ADD PRIMARY KEY (`path`,`langcode`);

```

Strangely when importing the sql file into another database on the production server, it doesn't show any error.

# Answer
There are many many posts about this error on the internet, but only in one I found the solution: https://dba.stackexchange.com/questions/46803/1062-duplicate-entry-but-there-are-no-duplicates/202891#202891

Apparently there was a value that should be entered in the path column which is longer than the defined 191 bytes, so it was truncated to that length, which caused duplicate values. So the solution is to clear all 404 log entries on /admin/config/search/redirect/settings and export the database again.
> 1 votes

---
Tags: 8, database, redirection
---