# Question
Title: How to use field value to set custom class and apply it to a html element in node.html.twig without using attributes and addClass()
I have tried to apply my custom class to an image tag

I have set classes for it

```
{% set imgClass = [
        'img-shape-' ~ (node.field_image_animation_shape.value|clean_class)
      ] %}

```

and have tried to apply to image as attributes

```
 attributes.addClass(imgClass)

```

that is renders all attributes for the node which duplicating on main node div so i need to avoid using attributes... How do i do it?

# Answer
You simply create your own attributes. Read \[Documentation\] Using attributes in templates. It's much easier to maintain in the long run. Especially if you start to use conditions to add or remove attributes.

> This provides a new blank Attribute object to use to build up attributes.
>
> ```
> {% set my_attribute = create_attribute() %}
> {%
>   set my_classes = [
>     'kittens',
>     'llamas',
>     'puppies',
>   ]
> %}
> <div{{ my_attribute.addClass(my_classes).setAttribute('id', 'myUniqueId') }}>
>   {{ content }}
> </div>
>
> ```
> 3 votes

# Answer
I have workaround this without using attributes and that how i did it:

```
 {% set imgClass = node.field_image_animation_shape.value|clean_class %}

```

created variable from the list text field - used key value for it

and then printed in hard way in to image classes

```
<img class="img-fluid img-shape-{{ imgClass }}" src="..." />

```

and this is result :

hope it will help to anybody :)
> 0 votes

---
Tags: theming, 9
---


# Question
Title: How to get menu Attributes from a theme's preprocess function?
I am developing a theme and trying to send custom vars to a twig menu template (since it pulls data from config) and have a loop to add variables in preprocess:

```
foreach($attributes as $attribute => $values){

    $variables[$element . '_attributes']->SetAttribute(
        $attribute,
        $values
    );
    // Also tried:
    $variables[$element]['#attributes'][$attribute][] = $values;
}

```

This function passes data to the template $variables as confirmed by kint, but SetAttribute returns a protected class property instead of the render array, while pushing to \['#attributes'\] returns the attribute keys correctly but the arrays are empty...

### How can I render the Attribute array in a menu?!

# Answer
The issue was accessing variables inside of the menu {%macro%}... to pass variables to a menu you need to pass `$variables['name']` to the menu before the macro and add a parameter to the macro, i.e.:

```
// preprocess

$variables['custom_attributes'] = array(
  'class' => ['myclass']
);

```

```
//template.html.twig

{{ menus.menu_links(items, attributes, 0, custom_attributes) }}
{% macro menu_links(items, attributes, menu_level, twigvars) %}

{{dump(twigvars.class)}}

```
> 0 votes

---
Tags: 8, theming, navigation
---


# Question
Title: Where in the MySQL database schema is the URL alias for a group relation?
I am building a report outside of Drupal that pulls data from a Drupal 8 database. The report shows titles of different nodes and I want to link those titles to the web page for that content. This is working fine if I use the standard /node/X path, but I would like to use the URL alias. I don't want the url alias of the node itself (which I did find thanks to this Which mysql tables contain the URL Alias path data? post). Our content is related to groups, so I want to use the URL alias that is created as part of the group entity relation.

At first I checked the url\_alias table, using this query to look for the node id in the source field, but I didn't find the alias set up for that node :

```
select u.alias
from url_alias u
where u.source LIKE '%4806%'

```

Then I tried to check the group tables. I only find 5 tables starting with group in the MySQL schema, and I didn't find the URL alias for the entity reference in any of them:

* group\_content
* group\_content\__group\_roles
* group\_content\_field\_data
* groups
* groups\_field\_data

Does anyone know where that URL alias from the group relation is stored in the MySQL schema?

# Answer
> 0 votes
As Clive stated in the comment, all aliases are in the url\_alias table.

You should join it with the og\_membership table, to take the url alias of the node's group.

So, for a node with id 100, the script should look like:

```
select u.alias
from og_membership og, url_alias u
where concat('node/', og.gid) = u.source
and og.etid = 100 and og.group_type like 'node'

```

# Answer
> 0 votes
url\_alias is path\_alias in drupal 8

```
select n.nid, n.vid, n.type, pa.path, pa.alias, pa.status
from node n
inner join path_alias pa on pa.path = concat('/node/', n.nid);

```

---
Tags: 8, database, path-aliases, group
---


title: How to insert nodes into a Views result

text:
# Question
Title: How to insert nodes into a Views result
In Drupal 7, I have a View that works great but I'd like to add a few nodes into the result arbitrarily outside of the scope of the View.

Basically, let's see the View returns Content Type X, I want to include a few nodes from Content Type Y that are in addition to whatever the View generates from Content Type X.

My preliminary thought was to use hook\_views\_pre\_render but I'm not convinced that is the best solution....yet.

# Answer
You may want to use `hook_views_pre_execute` (see example) or `hook_views_post_render()` where you can add arbitrarily content (new rows or html code) into the view to fake the nodes.

Please check the following code example to give you some idea.

You may also compare how other Views-based modules doing non-database query results, such as Search API Views or YQL Views Query Backend.
> 1 votes

# Answer
Maybe Views Field View module can help with that, you can create a view for X content type, and embed a another view in it as a field that show Content type Y.
> 0 votes

# Answer
The module that works best for this in my experience is Views Row Insert. Also available for modern Drupal (Drupal 8+).

Currently it supports blocks and custom text, so you would have to get your nodes as blocks first— this could be done easily with another view producing block displays.
> 0 votes

---
Tags: views, hooks
---


# Question
Title: How can I pull Salesforce objects as users, updating existing accounts when the email address matches?
I have a Drupal install that has been live for many years with over 200 thousand users.

We are currently trying to sync our salesforce users with our Drupal users but we only need to do this for certain user roles which would only be about 3000 or so.

I am using Drupal 9, the Salesforce Suit Module v:5.0.0, and I am using the salesforce\_pull submodule that is part of that.

My user mapping is working for importing only the new users we want into Drupal; however, Drupal is creating duplicate users even if a user already exists with the same email as what is being pulled over. About half of those 3000 need to be new, the other half will already exist in the Drupal system.

What I am trying to achieve is for Drupal to find a user with that email, and update that record to be connected with salesforce and update new fields as needed.

I have run into many walls with trying to get this to work and any suggestions would be greatly appreciated.

I have also tried setting the upsert key to be the email; however, that key only seems to apply once the Salesforce connection has been made as it doesn't seem to affect the original binding of the Salesforce object with pre-existing entities.

# Answer
> 1 votes
The answer was to use an Event Subscriber.

Here is a generic form of my code for anyone else who may have this question. This code is working but there seems to be another event that is in the process of creating a new user which is never completed. I was getting a simple notice log that the user was not able to be created (Which is what I want); however, I would ideally be able to abort this process in the event somehow instead of letting it fail gracefully elsewhere.

Critiques and improvements are welcome!

```
<?php

namespace Drupal\my_module\EventSubscriber;

use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\salesforce\Event\SalesforceEvents;
use Drupal\salesforce_mapping\Event\SalesforcePullEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Class MyNewSubscriber.
 */
class MyNewSubscriber implements EventSubscriberInterface {

  use StringTranslationTrait;

  public function pullPrepull(SalesforcePullEvent $event) {

    /** @var \Drupal\user\Entity\User $account */
    $account = $event->getEntity();
    $mapping = $event->getMapping();
    $salesforceObj = $event->getMappedObject();

    // check if the mapping matches the one I want to revise
    switch ($mapping->id()) {
      case 'my_salesforce_mapping':
        if($account->isNew()) {
          // Be mindful that your salesforce fields may be different. Mine are "Email" and "Name"
          $sf_email = $event->getMappedObject()->getSalesforceRecord()->field('Email');
          if(empty($sf_email)) {
            $event->disallowPull(); // We will reject any salesforce records that don't have an email associated with it. You may want to do something different here
            break;
          }

          $drupal_user = user_load_by_mail($sf_email);

          // Find if a user with that email exists
          if($drupal_user != false) {
            $salesforceObj->setDrupalEntity($drupal_user);
            \Drupal::logger('salesforce')->debug("Update the user with email {$sf_email} instead of creating a duplicate");
          } else {
            \Drupal::logger('salesforce')->debug("There was an issue when updating the user - Unknown email for {$event->getMappedObject()->getSalesforceRecord()->field('Name')}");
          }
        } else {
          // I don't need to do anything because the entities are already mapped
        }
        break;
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events = [
      SalesforceEvents::PULL_PREPULL => 'pullPrepull',
    ];
    return $events;
  }
}

```

---
Tags: crm
---


# Question
Title: How to display the TID of a term reference field in a content type?
In **Drupal 8**, I have a blog content type with a taxonomy term reference field called category.

How can I print out the Term ID of the taxonomy term of the category field in my **node.html.twig** file.

I can print the term name using **{{ content.field\_category }}** but I also want to print out the term ID which should be a unique number. How should I go about doing this as I have search for days without any clue?

# Answer
I figured it out, I was able to print the term ID of the category field using:

**{{ node.field\_category.entity.tid.value }}** as I realised I was looking in the wrong direction. Drupal 8 use entity reference only so I needed to call the TID from the referenced entity which of course is a taxonomy term in my category field.
> 3 votes

# Answer
One "hacky" way to do this:

```
{# First step: capture the rendered output of the internal path link for a term #}
{% set tid %}{{ content.field_category.0['#url'] }}{% endset %}

{# Second step: do some string processing on the captured output, removing the /taxonomy/term/ prefix and getting the TID #}
{{ tid|trim|replace({ '/taxonomy/term/' : '' }) }}

```

Good luck!
> 1 votes

# Answer
Another option is using the following

```
{{ content.field_category[0]['#options']['entity'].id() }}

```
> 1 votes

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


# Question
Title: How can I setRequired() for a BaseFieldDefinition per entity bundle?
I have an entity type **animal** with the following bundles:

* cow
* pig
* sparrow
* anteater

In the **Animal.php** entity type definition, I create some base fields, one of which is an entity reference to **Habitat**.

```
BaseFieldDefinition::create('entity_reference')
  ->setLabel(t('Habitat ID'))
  ->setCardinality(1)
  ->setSetting('target_type', 'habitat')
  ->setDisplayConfigurable('form', FALSE)
  ->setDisplayConfigurable('view', TRUE);

```

I want to require this entity reference for cows and pigs, but I don't want it to be required for sparrows and anteaters.

So, I can't use `->setRequired()` in `BaseFieldDefinition::create()` because that will apply to all the bundles.

What's the simplest way to require a field created by `BaseFieldDefinition::create()` in some bundles but not others?

# Answer
> 0 votes
I haven't done it, but I believe you can override ContentEntityBase::bundleFieldDefinitions(), returning the fields based on the bundle type.

---
Tags: entities, 9
---


# Question
Title: How do I set the custom Gutenberg font size?
Mythemename.gutenberg.yml allows setting custom font size, but it doesn't work on Drupal 9. (It works on my old Drupal 8 site.)

Basing on Creating custom font size presets in a Theme, custom font sizes could be added in the .gutenberg.yml file for the theme.

The colors appear on the Gutenberg with the following settings, but the "Mega" font size doesn't.

### Mythemename.gutenberg.yml

```
theme-support:
  colors:
    - slug: "black"
      name: "Black"
      color: "#000000"
    - slug: "dark-grey"
      name: "Dark Grey"
      color: "#555555"
  fontSizes:
    - slug: "mega"
      name: "Mega"
      size: 72

```

# Answer
1. Create a settings.js in your theme your JS file should look like this:

```
(function (Drupal) {

  var settings = {};

  window.DrupalGutenberg = window.DrupalGutenberg || {};
  window.DrupalGutenberg.defaultSettings = settings;

})(Drupal);

```
2. Add it your themename.libraries.yml
3. In your themename.gutenberg.yml attach the library you created ex. `libraries-edit: themename/gutenberg`

After that clear cache and you'll able to see your custom fontsize preset.
> 2 votes

---
Tags: 9, wysiwyg
---


# Question
Title: How can I collaborate with multiple developers?
I am developing a website on Drupal with 2 other developers. What would be the best way to collaborate? We plan to work on different git branches and there will be a dev and production branch as well. How can we keep in sync with the database structure without overwriting each others' work?

# Answer
> 1 votes
It can be done with Drupal's configuration management system. Have a read of https://www.drupal.org/docs/configuration-management to get started

Essentially any site changes apart from content can be stored in .yml files which you can import/export on each environment (storing them in GIT)

I wouldn't recommend trying to synchronize content and this is better done manually on your dev/stage/prod environment. But if you really wanted to there is the default content module which allows for content to go into .yml files too https://www.drupal.org/project/default\_content

---
Tags: database, importing-exporting, version-control
---


# Question
Title: No content but empty row outputted by view
I have a view as follows:

* Display: Master
* Format: Unformatted list
* Fields: Content: Images
* Filter criteria: Content type, published
* Contextual filter: Content: Nid with 'Provide default value' set to 'Content ID from URL'

The view is placed on the node using Panels and Panalizer modules.

The node in question had no images uploaded to the image field but the view is outputting an empty row as follows:

```
<div class="view view-case-study-images view-id-case_study_images view-display-id-default view-dom-id-0c286f7a769d643d2e0cf9709edc0c79">
  <div class="view-content">
    <div class="views-row views-row-1 views-row-odd views-row-first views-row-last"> </div>
  </div>
</div>

```

I have checked and unchecked the 'Count the number 0 as empty' and ' Hide if empty' on the 'Content: Images' field but the view still shows.

How can I hide the view (by removing this empty row) if there are no images on a node?

Happy to attach any additional information you require to this post. Thanks.

# Answer
> 2 votes
You need to set a filter value on the image field.

Open your view, then edit as follows:

Enable 'Use Aggregation'.

Make sure that the image field is aggregating on 'Group Result together', using Group column 'Entity ID'. Sometimes views gives an error here, so just remove and re-add the image field with these settings.

Add a Filter criteria using 'field\_image:fid', set its aggregation to COUNT, and choose the operator 'Is greater than' with value 0.

You might have to remove all of your sort criteria and re-add them as switching on aggregation mid stream can cause issues with sorting.

Basically, what you have done is to do a count on the image primary key (fid) for each node, and if the count is 0 to exclude the record from the result.

This should work for an image field that has either a single, or multiple values.

I you are uncomfortable working with aggregation, then have a look at the Field Count Formatter module. It adds a views field that simply count the number of values contained in a multi-value field. I would imagine it providing a filter in views as well.

# Answer
> 0 votes
May be the content is not NULL, but it is equal to '' (empty string) or ' ' (space) Try to add a filter on field "Images" and test for lenght \>0 (or 1)

---
Tags: 7, views, panels
---


# Question
Title: How to alter 'not null' value of field after creation
I have a custom module that defines a field wherein I erroneously set the 'not null' value to be FALSE when I should have set it to TRUE. Ideally I would like to remedy this by means of an update hook. How can I do that?

```
function MYMODULE_field_schema($field) {
  $columns = array(
    'payments' => array(
      'type' => 'varchar',
      'length' => 20,
      'not null' => FALSE,
      'description' => 'Number of payments made',
    ),
  );
  return array('columns' => $columns);
}

```

From reading the documentation it looks like I could do it by passing a field structure to field\_update\_field, but I don't know what to put in the field structure

```
function MYOTHERMODULE_update_70xx() {

 $field = array(
    // What should I put in here in order to change 'not null' to FALSE
    // and as a bonus, change the type from 'varchar'
    // to an integer (number_integer?)
);

 field_update_field($field);
}

```

Am I over-simplifying things? I know it's often not possible to modify fields if they contain data, and in this particular case I can delete and re-create the content type without too much difficulty, but no point doing all of that if there's no need.

# Answer
You need to ud db\_change\_field function to change structure of table field.

```
function MYOTHERMODULE_update_70xx() {
  db_change_field('tablename', 'payments', 'payments', array(
    'not null' => TRUE,
  ));
}

```
> 1 votes

# Answer
In case of Drupal 9, db\_change\_field is deprecated. You can use Schema::changeField() instead.

```
function hook_update_n() {
  $fieldName = 'field_price_amount';
  $spec = [
    'type' => 'int',
    'size' => 'normal',
    'unsigned' => TRUE,
    'not null' => FALSE,
    'default_value' => NULL
  ];
  $schema = \Drupal::database()->schema();
  $schema->changeField('tableName', $fieldName, $fieldName, $spec);

```

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Database%21Schema.php/function/Schema%3A%3AchangeField/9.0.x
> 1 votes

# Answer
For anyone who might stumble upon this in future, @vgoradiya pointed me in the right direction by mentioning the db\_change\_field function but what ultimately happens is the function creates a SQL 'ALTER TABLE' command, which has syntax like this:

```
ALTER TABLE table_name CHANGE field_name field_name  VARCHAR(20) NOT NULL DEFAULT '0';

```

So, in your call to db\_change\_field, you must provide the values that enable Drupal to build the SQL command. Also, if you have revisions enabled, you must apply the change to the revision table as well as the field table. This is what worked for me:

```
  $tables = array('field_data_field_stations',
                  'field_revision_field_stations');
  $column = 'payments';
  $column_spec = array(
    'not null' => TRUE,
    'type' => 'varchar',
    'length' => '20',
    'default' => '0',
    );

  foreach ($tables as $table) {
    db_change_field($table, $column, $column, $column_spec);
  }

```
> 0 votes

---
Tags: entities, database
---


# Question
Title: How do I retrieve the tokenised path for the Files Directory setting configured via the fields settings?
I'm using this code to retrieve a remote file, during the process of creating a new a media entity.

```
$url = 'https://example.com/example.jpg';
$image = system_retrieve_file($url, NULL, TRUE);
$entity_array['field_example'] = [
  'target_id' => $image->id(),
];

```

The second parameter in `system_retrieve_file()` determines that the file is stored in the public:// directory.

How can I retrieve the tokenised defined in the file fields settings?

# Answer
So I had to make a function that I pass a bundle and field name too. Both are in the form of strings. The function then returns a uri with the tokens replaced.

```
function getFileDirectory($media_type, $field_name) {

        // Fetch all field definitions for the media bundle.
        $fields = \Drupal::service('entity_field.manager')->getFieldDefinitions('media', $media_type);
        foreach ($fields as $field => $field_definition) {
            $bundle = $field_definition->getTargetBundle();

            // Look for the field we need
            if ($bundle == $media_type && $field == $field_name) {

                // Get the settings for the field, in order to start building the directory path
                $settings = $field_definition->getSettings();
                $file_directory_path_tokens = $settings['file_directory'];
                $uri_scheme = $settings['uri_scheme'];

                // Convert tokens in files directory string
                $token = \Drupal::token();
                $directory_path = $token->replace($file_directory_path_tokens);

                // If there is a value for the file directory setting on the file field, ensure the directory exists,
                // if not create it.
                if ($directory_path) {
                    $directory = $uri_scheme . '://' . $directory_path;
                    /** @var \Drupal\Core\File\FileSystemInterface $file_system */
                    $file_system = \Drupal::service('file_system');
                    $file_system->prepareDirectory($directory, FileSystemInterface:: CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
                    return $directory;
                }
                // Otherwise just return the uri_scheme ie public:// or private://
                else {
                    return $uri_scheme . '://';
                }
            }
        }
    }

```

This is specific for media entities. It wouldn't be too much bother to extend it to be more generic to cover all entities.

I hope this saves someone some pain.
> 0 votes

---
Tags: media, files, 9
---


# Question
Title: How to return different entity reference fields from multiple bundles using the same name with JSON:API?
## The Goal

My site structure looks like this:

* Node content type **A** with entity reference field **groupA** pointing to a term with field **groupAfield**
* Node content type **B** with entity reference field **groupB** pointing to a term with field **groupBfield**

I want to be able to get content types A and B from a single JSON:API endpoint, and I want this endpoint to return groupB as groupA (rename groupB to groupA for nodes of content type B in the output).

This is to simplify the output for clients consuming JSON:API.

## What I have tried

JSON:API usually only returns one bundle at a time. However, using the JSON:API Resources module, you can create your own custom resource that returns multiple entity types (using an entity query).

So I made a custom resource type.

I need to include the field values for both groupA and groupB, which I did like this:

```
$request->query->set('include', 'nodeTypeA.groupA.groupAfield','nodeTypeB.groupB.groupBfield');

```

This correctly gets all the data I need. So the last step is to rename `groupB` to `groupA` in the output. This is where I'm having trouble.

Normally, I would use the JSON:API Extras module to rename `groupB` to `groupA` for content type B. However, I cannot do this for my custom resource because then the `include` statement will break (because `nodeTypeA`'s group does not have `groupBField`, and `nodeTypeB`'s group does not have `groupAField`).

So, I need to do the renaming after JSON:API has done its processing:

```
$data = $this->loadResourceObjectDataFromEntityQuery($entity_query, $cacheability);
$response = $this->createJsonapiResponse($data, $request, 200, []);

```

But, this seems to be too late to change the output. Is there some way I can rename `groupB` to `groupA` just before returning the response?

# Answer
From a #decoupled Slack conversation, bbrala (JSON:API maintainer) stated:

> Don't think there is a supported way to do that other than extending and overwriting the controller that handles responses. Other modules do that too, but this will make the maintenance burden of you application higher and probably break some modules you might use.

One way to work around this would be to use Dynamic Entity Reference, but there are several issues that must be solved before DER and JSON:API can be used together.
> 1 votes

---
Tags: entities, 9
---


# Question
Title: Migrate filter_format with embedded_data plugin
I'm trying to migrate filter\_format from d6 to d9, I'm using embedded\_data 'cause migrate\_drupal doesn't work with D6; so I'm trying to do it in another way.

This is my yml file.

```
id: project_filter_format
label: Filter format configuration
migration_group: project_filter_format
migration_tags:
  - Drupal 6
  - Configuration
source:
  plugin: embedded_data
  data_rows:
    -
      format: 1
      name: Filtered HTML
      cache: 1
      roles:
      filters:
        -
          module: filter
          delta: 0
          weight: -10
          settings:
            -
              fid: 55
  ids:
    -
      fid
process:
  format:
    plugin: machine_name
    source: name
  name: name
  cache: cache
  filters:
    plugin: sub_process
    source: filters
    key: '@id'
    process:
      id:
        # If the filter ID cannot be mapped, it will be passed through
        # unchanged because the bypass flag is set. The filter_id plugin
        # will flatten the input value and default it to filter_null (the
        # fallback filter plugin ID) if the flattened input value is not
        # a valid plugin ID.
        plugin: filter_id
        source:
          - module
          - delta
        bypass: true
        map:
          filter:
            - filter_html
            - filter_autop
            - filter_url
            - filter_htmlcorrector
            - filter_html_escape
      settings:
        plugin: filter_settings
        source: settings
      status:
        plugin: default_value
        default_value: true
destination:
  plugin: entity:filter_format
  no_stub: true

```

I have check Drupal\filter\Plugin\migrate\source\d6\FilterFormat.php to try to understand if the row it has the correct structure.

```
    -
      format: 1
      name: Filtered HTML
      cache: 1
      roles:
      filters:
        -
          module: filter
          delta: 0
          weight: -10
          settings:
            -
              fid: 55

```

But I'm not sure if it's the problem or is another.

This is the error I get.

> Migration failed with source plugin exception: '0' is defined as a source ID but has no value. in /var/www/html/web/core/modules/migrate/src/Row.php line 108

I'm not sure if the problem it's de data\_rows, the source IDs definition, or I'm missing something.

# Answer
> 0 votes
This happens because the source ID property (`fid`) does not exist. As the file is structured, only the following could be used as such: `format`, `name`, `cache`, `roles`, `filters`. By the way `roles` is not mapped nor used while you process the row.

You could just do the following:

```
source:
  plugin: embedded_data
  data_rows:
    - id: 1
      format: 1
      name: Filtered HTML
      cache: 1
      roles:
      filters:
        - module: filter
          delta: 0
          weight: -10
          settings:
            -
              fid: 55
  ids:
    id:
      type: string

```

---
Tags: migrations, 9
---


title: Redirect page after all nodes save

text:
# Question
Title: Redirect page after all nodes save
I am trying to write a custom module to save special nodes. With my code after first node save, page redirect and other not affected.

I need after all nodes\_save redirect to list.

```
$nidew = [12,34,55,12,66,63];
foreach ($nidew as $nodeuniqe) {
  if (isset($_POST['submit'])) {
    $node = node_load($nodeuniqe);
    node_save($node);
    drupal_goto('list');
  }
}

```

# Answer
Sounds like a simple PHP issue and you wnt to take the redirect command out of the foreach loop e.g.:

```
$nidew = [12,34,55,12,66,63];
if (isset($_POST['submit'])) {
  foreach ($nidew as $nodeuniqe) {
    $node = node_load($nodeuniqe);
    node_save($node);
  }
  drupal_goto('list');
}

```
> 1 votes

---
Tags: 7
---


# Question
Title: How can I add custom code to Drupals .htaccess and make sure it will stay there
For one of my Drupal 9 website I need to add a custom code to the htaccess file to redirect the visitors from one subdomain to another for this I use the following code:

```
#Custom Rewrite Rule
RewriteBase /
RewriteCond %{HTTP_HOST} ^old-subdomain\.mydomain\.com$ [NC]
RewriteRule ^(.*) http://new-subdomain.mydomain.com/$1 [L,R]

```

I put this code directly under the `RewriteEngine on` on line 68.

But I know that updating my Drupal site might overwrite these lines of code. How do I make sure these changes to the .htaccess file are permanent?

# Answer
Patching scaffolded files is documented precisely.

```

"name": "my/project",
  ...
  "scripts": {
    "post-drupal-scaffold-cmd": [
      "cd docroot && patch -p1 <../patches/htaccess-ssl.patch"
    ]
  }

```
> 2 votes

---
Tags: 9, .htaccess
---


# Question
Title: I can't get rid of duplicates in products view
I tried everything. I reduced the number of fields. I set the Query settings to distinct. Product: Variations (variations:delta) is also set to 0.

When I search by SKU I get duplicates. SKU Search is exposed filter for admins.

This is the generated query:

```
SELECT DISTINCT "commerce_product_field_data"."created" AS "commerce_product_field_data_created", "commerce_product_field_data"."product_id" AS "product_id", "commerce_product_variation_field_data_commerce_product__variations"."variation_id" AS "commerce_product_variation_field_data_commerce_product__vari", "taxonomy_term_field_data_commerce_product__field_catalog"."tid" AS "taxonomy_term_field_data_commerce_product__field_catalog_tid", DATE_FORMAT((DATE_ADD('19700101', INTERVAL commerce_product_field_data.created SECOND) + INTERVAL 7200 SECOND), '%Y%m%d') AS "commerce_product_field_data_created_day"
FROM
{commerce_product_field_data} "commerce_product_field_data"
LEFT JOIN {commerce_product__variations} "commerce_product__variations" ON commerce_product_field_data.product_id = commerce_product__variations.entity_id AND commerce_product__variations.deleted = '0'
LEFT JOIN {commerce_product_variation_field_data} "commerce_product_variation_field_data_commerce_product__variations" ON commerce_product__variations.variations_target_id = commerce_product_variation_field_data_commerce_product__variations.variation_id
LEFT JOIN {commerce_product__field_catalog} "commerce_product__field_catalog" ON commerce_product_field_data.product_id = commerce_product__field_catalog.entity_id AND commerce_product__field_catalog.deleted = '0'
INNER JOIN {taxonomy_term_field_data} "taxonomy_term_field_data_commerce_product__field_catalog" ON commerce_product__field_catalog.field_catalog_target_id = taxonomy_term_field_data_commerce_product__field_catalog.tid
WHERE ("commerce_product_field_data"."status" = '1') AND ("commerce_product__variations"."delta" = '0')
ORDER BY "commerce_product_field_data_created_day" DESC
LIMIT 500 OFFSET 0

```

I don't know how else to ask this question. I did lots of research. Nothing helps. The duplicates are keep on showing up.

# Answer
I can't tell how you've configured the View to add DISTINCT to the query, but just looking at the query, it's clear that this will return *every* distinct combination of far too many variable items. Even the fact that created timestamp is in there is likely enough to always return everything ... unless literally every combination of product + variation + catalog term + etc. was created on the same day.

At the end of the day, this isn't a "remove duplicates from Views results" problem so much as a "how to configure a better View" problem. I'm not sure that's appropriate for Drupal Answers, tbh.
> 1 votes

---
Tags: commerce
---


# Question
Title: Why doesn't form submit callback get called?
I have a custom page (controller) which embeds a node form. I want to submit this form via ajax but also run another submit handler which opens a modal with some of the values from that form.

My controller function is simple:

```
  public function createQuote() {
    $node = \Drupal\node\Entity\Node::create(['type' => 'mpep_quote']);
    $form = \Drupal::service('entity.form_builder')->getForm($node);
    $form['#attached']['library'][] = 'core/drupal.dialog.ajax';

    $form['open_modal'] = [
      '#type' => 'submit',
      '#value' => t('Open modal'),
    ];

    $form['actions']['#access'] = FALSE;

    return $form;
  }

```

This works fine to show the form and clicking my new submit button submits the form (non-ajax).

I have tried numerous (recommended and unsuccessful) methods of trying to get the form to submit using ajax, such as adding this to $form\['open\_modal'\]:

```
  '#ajax' => [
    'callback' =>  '::openQuoteModal',
    'event' => 'click',
  ],

```

where openQuoteModal is my additional submit function. This does not submit the form via ajax nor does it run my added submit handler.

The only way I have been able to get the form to submit via ajax is to add this to the $form\['open-modal'\]:

```
'#attributes' => ['class' => ['use-ajax-submit']],

```

This does work to submit the form via ajax, but nothing I have done will run my added submit handler. I have tried the following:

1. #ajax callback as shown above
2. adding a #submit to the form submit button
3. adding a #submit to the form itself

Is there any way to get both the from to submit via ajax as well as run a secondary form submit handler?

# Answer
> 0 votes
From the link @4uk4 posted above I ended up simply with this:

Controller code basically the same as above except as per the link, i can't do much to the form after it is built. So it is simple this now:

```
  public function createQuote() {
    $node = \Drupal\node\Entity\Node::create(['type' => 'mpep_quote']);
    $form = \Drupal::service('entity.form_builder')->getForm($node);
    $form['#attached']['library'][] = 'core/drupal.dialog.ajax';

    return $form;
  }

```

and main part i was doing wrong was the form changes need to be done in a form alter (before it is built):

```
  $form['actions']['submit'] = array_merge($form['actions']['submit'], [
    '#value' => t('Get quote'),
    '#ajax' => [
      'callback' => 'openQuoteModal',
      'event' => 'click',
    ],
  ]);

```

This was all that was required to do 2 things:

* submits the node form and creates the node
* then runs the openQuoteModal function which opens a modal and that function has access to the $form values.

```
function openQuoteModal($form, $form_state) {
$response = new AjaxResponse();

$values = $form_state->getValues();

// Get the modal form using the form builder.
$modal_form = print_r($values, true);

// Add an AJAX command to open a modal dialog with the form as the content.
$response->addCommand(new OpenModalDialogCommand('Your quote', $modal_form, ['width' => '1000']));

return $response;

```

}

# Answer
> 0 votes
Ajax forms need to have a wrapper with an id.

```
// Add wrapper for AJAX element.
$form['#prefix'] = '<div id="ajaxfeedback">';
$form['#suffix'] = '</div>';

```

And I think the callback needs to return an AJAX response.

```
public function openQuoteModal(array $form, FormStateInterface $form_state) {
    $response = new AjaxResponse();

    // If there are any form errors, re-display the form.
    if ($form_state->hasAnyErrors()) {
      $response->addCommand(new ReplaceCommand('#ajaxfeedback', $form));

      return $response;
    }

    $response->addCommand(new OpenModalDialogCommand("Success!", 'The modal form has been submitted.', ['width' => 500]));

    return $response;
  }

```

(reposted for formatting)

---
Tags: ajax, 9
---


# Question
Title: Cookie authentication when reguistering users through REST API
I am running Drupal 9 commerce 2.0 as headless CMS, and I am trying to integrate the user registration/user login part of my frontend application. I was able to use the user/register REST API to create users. The default (only option without other modules) authentication was cookie authentication. What I am trying to understand is how the cookie authentication works. When running `curl -d @data.json http://example.com/user/register?_format=hal_json --header "Content-Type:application/hal+json"` for example, everything works perfectly fine, and the user is created. But don't I need to add a Set-Cookie header for this to work since the REST API has cookie authentication checked? How does this cookie authentication work?

# Answer
> 2 votes
When you perform a login using the login endpoint you'll get a cookie back (as well as a CSRF token) which you can then use for subsequent requests instead of doing a fresh login every time.

So with curl something like this:

```
curl --header "Content-type: application/json"
  --request POST \
  -s -c cookie.txt \
  --data-binary '{"name": "user1", "pass": "pass1"}' \
  https://.../user/login

```

Would get you back a cookie in cookie.txt and the json response will contain your CSRF token.

---
Tags: commerce, authentication-authorization, cookies
---


title: JSON:API fetch reference data

text:
# Question
Title: JSON:API fetch reference data
I have a content type (MealDiary), which contains a reference to a paragraph multiple times (Meal: date, title). I do get a paragraph uid I can use to retrieve this data, but I would instead like to fetch the field data of the meal withing the MealDiary request. My goals is 1 request instead of 6.

Anybody could help on this?

# Answer
I don't use Paragraphs but I've been doing a lot of work with JSON:API recently.

As noted by @unusedspoon, there are examples in the documentation.

However, using what core provides by default leads to really long queries that aren't much fun to work with.

## Automatically include entity references

Install JSON:API Extras module and go to `/admin/config/services/jsonapi/resource_types/`. Select the resource type (entity bundle) you want to automatically include entity references for. Scroll down to the bottom and edit the **Default include list**.

Note that you can include multiple levels of entity references (for example, to include the file of a media entity: `field_media_audio.file`).

As noted in the UI, if you attach an `include` query string parameter, the default includes will be ignored, so this lets you set useful defaults but then override when necessary.

## Merge entity reference info with the referencing entity

By default, JSON:API returns the entity references separately from the referencing entity. This might be useful for some people but I find it annoying because I want to access my entity reference data like `myEntity.myEntityReferenceField.value`. To get this behavior, you can install the JSON:API Include module.
> 2 votes

---
Tags: 9
---


# Question
Title: Cannot Login, error msg shows "To log in to this site, your browser must accept cookies from the domain"
On my dev environment hosted on the cloud which has SSL, I added this to the settings.php

```
$secure = true; // if you only want to receive the cookie over HTTPS
$httponly = true; // prevent JavaScript access to session cookie
$samesite = 'none';

if(PHP_VERSION_ID < 70300) {
  session_set_cookie_params($maxlifetime, '/; samesite='.$samesite, $_SERVER['HTTP_HOST'], $secure, $httponly);
} else {
  session_set_cookie_params([
    'lifetime' => $maxlifetime,
    'path' => '/',
    'domain' => $_SERVER['HTTP_HOST'],
    'secure' => $secure,
    'httponly' => $httponly,
    'samesite' => $samesite
  ]);
}

```

My goal was to set SESSION cookie to samesite = 'NONE'.

Login was working when I did this on Drupal 8, but now on Drupal Core 9.3.0, when I login I get error message "To log in to this site, your browser must accept cookies from the domain \[domain\_name\]"

# Answer
You get this error message when Drupal *expects* there to be a session, communicated by the `check_logged_in`, but none can be found.

I've found myself in this situation myself when a miss-configured web server stripped the cookies from the request.

The leads to Drupal setting up the session, and adding the query parameters, but the cookie not being present in subsequent requests. Drupal then displays the

> your browser must accept cookies

message.

Likely the cookie settings you are adding cause the cookie to become invalidated somehow, so double check that the browser actually sends the cookies, and that they reach Drupal.
> 1 votes

---
Tags: 9, cookies
---


# Question
Title: How do I recreate Ubercart's product attributes?
While rebuilding an old D7 site with Ubercart into a new D9/Commerce installation, among other problems, I stumbled upon this one.

In Ubercart I can add as many product attributes as I want and make them show up in the product add to cart form as checkboxes with price adjustment, like this:

No matter how much I tried playing around with Commerce product variations, I could not achieve this functionality.

I have added two product attributes in /admin/commerce/product-attributes, and there isn't an option for checkbox for any of them, just radio, select, rendered attribute. I have added a product variation type which has the two product attributes enabled, I added a product of the new variation type, and I added 3 variations with different SKUs for it - one for the plain product, one with the first attribute, one with the second attribute.

Yet it doesn't work.

What am I doing wrong? Is this functionality even possible with Commerce?

Please help. Thanks in advance.

# Answer
If you upgrade with Commerce Migrate Ubercart ( https://www.drupal.org/project/commerce\_migrate\_ubercart ) they automatically come and populate as an unattached product attribute if you use an empty database

They will show up as product attributes and you use them as product variation by creating a product type and using them as a variation

They will not show up attached the original product as it came from Ubercart. You will need to create a product type and add the variation manually to each

See also https://docs.drupalcommerce.org/commerce2/developer-guide/products/product-architecture/simple-product and https://docs.drupalcommerce.org/commerce2/user-guide/products/configure-product-attributes
> 0 votes

---
Tags: commerce, 9
---


# Question
Title: How to reset a field formatter settings or layout builder configuration
I was settings up an images field through layout builder. Change it from `Bootstrap Basic Image Gallery` to `OwlCarousel`.

When I submit the form, the UI does not have any response. and then I refresh the page, the website crash on this configuration page. `/admin/commerce/config/product-types/easel/edit/display/default/layout`

I wonder if there is any method to reset field formatter settings or the layout builder configuration.

PAGE ERROR:

```
Drupal\Component\Plugin\Exception\MissingValueContextException: Required contexts without a value: entity in Drupal\Core\Plugin\Context\ContextHandler->applyContextMapping() (line 155 of core/lib/Drupal/Core/Plugin/Context/ContextHandler.php).
Drupal\layout_builder\SectionComponent->getPlugin(Array) (Line: 70)
Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent->__construct(Object, Array, 1) (Line: 89)
Drupal\layout_builder\SectionComponent->toRenderArray(Array, 1) (Line: 87)
Drupal\layout_builder\Section->toRenderArray(Array, 1) (Line: 240)
Drupal\layout_builder\Element\LayoutBuilder->buildAdministrativeSection(Object, 1) (Line: 124)
Drupal\layout_builder\Element\LayoutBuilder->layout(Object) (Line: 98)
Drupal\layout_builder\Element\LayoutBuilder->preRender(Array)
call_user_func_array(Array, Array) (Line: 101)
Drupal\Core\Render\Renderer->doTrustedCallback(Array, Array, 'Render #pre_render callbacks must be methods of a class that implements \Drupal\Core\Security\TrustedCallbackInterface or be an anonymous function. The callback was %s. See https://www.drupal.org/node/2966725', 'exception', 'Drupal\Core\Render\Element\RenderCallbackInterface') (Line: 772)
Drupal\Core\Render\Renderer->doCallback('#pre_render', Array, Array) (Line: 363)
Drupal\Core\Render\Renderer->doRender(Array) (Line: 435)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 201)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 241)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 564)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 242)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 132)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 142)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.view') (Line: 174)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 709)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

```

# Answer
> 2 votes
REF: https://drupal.stackexchange.com/a/310906/109110

I got the layout-builder back after deleting `name = 'commerce_product.easel.default'` from table `key_value_expire`

---
Tags: layout-builder
---


title: limit order quantity in drupal commerce

text:
# Question
Title: limit order quantity in drupal commerce
In my website I would like to limit product quantity to 1, meaning is that user can order only one of a product in one order. And my question is how to configure to set maximum quantity to 1 . Any suggestion is greatly appreciated.

Thanks.

# Answer
You can achieve this using Rules by following steps given below:

> Event: After udpdating an already existing line item
>
> Conditions: 1/ data comparison: commerce-line-item:type = product 2/ data comparison: commerce-line-item:commerce-product:type = Your given product type 3/ data comparison: commerce-line-item:quantity is greater than 1
>
> Action: \- set data value: commerce-line-item:quantity 1 \- display custom message

Reference: https://drupalcommerce.org/questions/8066/how-limit-maximum-quantity-1-one-given-product-type
> 1 votes

# Answer
I found this link, it is very simple. http://bonify.io/blog/2014/09/limit-quantity-when-adding-product-cart

1. Events
    * Before saving a commerce line item
2. condition

* Entity is of bundle

    data selector: commerce-line-item, value: product
    * Data comparison

    Data to compare : commerce-line-item:commerce-product:product-id, operator: equal, Value:1
3. Action

* set a data value

    data: commerce-line-item:quantity, value: 1
    * Save Entity

    Data selector: commerce-line-item,
    * Show a message on the site

    Message: This product only available for 1., Value: warning
> 1 votes

# Answer
October 2022: Running Commerce Core on Drupal 7

So I struggled with this. On my website we sell digital products so the quantity never needed to be larger than one. I tried using spinners to prevent double clicking on the "Add to Cart" buttons but somehow users still found ways to double click. I still don't know how but they did. I started my solution from trying to follow the drupal commerce user guide.

https://docs.drupalcommerce.org/commerce1/user-guide/shopping-cart/working-with-cart-rules-events

The problem I ran into was that when I tried to set the condition to

commerce-line-item:quantity \> 1 it tried to force me to use data selectors which doesn't give me any value option.

The only thing I could do was set

commerce-line-item:quantity = 2 and then the routine would work. But if someone triple and went really crazy with the clicks this would not work because the QTY would get to three before the rule would finish firing. I then tried adding more conditions in an OR statement but found the performance of the rule was unreliable even in non stress situations. THEN THE EUREKA MOMENT.

I didn't need any condition since everything on my website is to be set to 1. So no product type conditions, no pre-existing quantity conditions, etc... needed to be checked.

So here is what appears to be working for me. I'll come back and edit this if it fails at any point.

1. Create new Rule
2. Set Event to "After adding a product to the cart"
3. Set Actions to
1st Action: Set a Data Value commerce-line-item:quantity = 1 2nd Action: Set Save Entity commerce-line-item:order I left "Force Immediate Save to false (or unchecked).

Comments: On my website you must be logged in to make a purchase. It appears to work for regular registered users and the admin role. I'll come back and update if I have any new problems with this running. What this routine does is make sure that after the user has finally stopped clicking the "Add to Cart" button, line item quantity is set back to 1 and the cart is recalculated. I imagine it increases the "Add to Cart" time a little bit. But it should be worth it not to have calls from people that didn't realize they had overpaid because they added the product to the cart twice. I'm a bit surprised but it happens all the time. Especially on my website cause when I was on drupal 6 I used a different commerce solution and forcing a quantity of 1 was already coded in. So many customers never bothered to check.
> 0 votes

---
Tags: commerce
---


# Question
Title: Can't change quantity of line item with rules
I created a rule that checks for the quantity of a product while adding to cart and while proceeding to the second step of checking out. The action sends a warning message to the site that says you can't have over one qty of the 'gift card' product type and is also supposed to set the quantity back to 1. The problem is that while the message appears when it is supposed to, the quantity is not being set back to 1 at any point. I made sure that I also save the cart after changing quantity as well.

Here is the rule export:

```
{ "rules_1_gift_card_per_cart" : {
    "LABEL" : "1 Gift Card per cart",
    "PLUGIN" : "reaction rule",
    "REQUIRES" : [ "rules", "rules_conditional", "commerce_cart", "commerce_rules_extra" ],
    "ON" : [ "commerce_cart_product_add", "line_item_quantity_changed" ],
    "IF" : [
      { "data_is" : { "data" : [ "commerce-product:type" ], "value" : "gift_certificate" } },
      { "AND" : [
          { "data_is" : {
              "data" : [ "commerce-line-item:quantity" ],
              "op" : "\u003E",
              "value" : "1"
            }
          }
        ]
      }
    ],
    "DO" : [
      { "CONDITIONAL" : [
          {
            "IF" : { "data_is" : {
                "data" : [ "commerce-line-item:quantity" ],
                "op" : "\u003E",
                "value" : "1"
              }
            },
            "DO" : [
              { "data_set" : { "data" : [ "commerce-line-item:quantity" ], "value" : "1" } },
              { "entity_save" : { "data" : [ "commerce-order" ] } },
              { "drupal_message" : { "message" : "Only one gift card per order.", "type" : "warning" } }
            ]
          }
        ]
      }
    ]
  }
}

```

EDIT: I dpm($commerce\_line\_item) in the action as well and it actually says the quantity is 1 while the cart display is still showing 2, though I believe this is only per item qty in the cart.

The total of the order is still being updated when the gift card quantity is being increased.

EDIT 2: I created a custom rules action to manually update the quantity in the commerce\_line\_item table which also does not seem to work:

```
function commerce_giftcards_action_change_qty_one($current_order, $current_line_item) {
  dpm('Current Order ID: ' . $current_order->order_number);
  dpm('Updated Line Item ID: ' . $current_line_item->line_item_id);
  dpm('Updated Line Item Type: ' . $current_line_item->type);

  db_update('commerce_line_item')
    ->fields(array('quantity' => '1.00'))
    ->condition('line_item_id', $current_line_item->line_item_id, '=')
    ->execute();

}

```

The correct fields are printing in the messages but the database is not updating unless I am going back to the product's page and adding another to the cart. It only keeps the quantity at 1 if I hit add to cart more than once. If I change the quantity of the item on the cart page it still increases the quantity in the database while also displaying the message that says only 1 qty of that item is allowed.

# Answer
> 0 votes
I played around with the rules actions and got it to work with these settings & the function I created to manually update the table:

```
    { "rules_1_gift_card_per_cart" : {
    "LABEL" : "1 Gift Card per cart",
    "PLUGIN" : "reaction rule",
    "REQUIRES" : [
      "rules",
      "rules_conditional",
      "commerce_giftcards",
      "commerce_cart",
      "commerce_rules_extra",
      "entity"
    ],
    "ON" : [
      "commerce_cart_product_add",
      "line_item_quantity_changed",
      "commerce_line_item_update"
    ],
    "IF" : [
      { "data_is" : { "data" : [ "commerce-line-item:type" ], "value" : "gift_certificate" } },
      { "AND" : [] },
      { "data_is" : {
          "data" : [ "commerce-line-item:quantity" ],
          "op" : "\u003E",
          "value" : "1"
        }
      }
    ],
    "DO" : [
      { "CONDITIONAL" : [
          {
            "IF" : { "data_is" : {
                "data" : [ "commerce-line-item:quantity" ],
                "op" : "\u003E",
                "value" : "1"
              }
            },
            "DO" : [
              { "data_set" : { "data" : [ "commerce-line-item:quantity" ], "value" : "1" } },
              { "drupal_message" : {
                  "message" : "Only one gift card per order.",
                  "type" : "warning",
                  "repeat" : 0
                }
              },
              { "commerce_giftcards_action_change_qty_one" : {
                  "order" : [ "commerce-line-item:order" ],
                  "line_item" : [ "commerce-line-item" ]
                }
              }
            ]
          }
        ]
      }
    ]
  }
}

```

# Answer
> 0 votes
October 2022: Running Commerce Core on Drupal 7

So I struggled with this. On my website we sell digital products so the quantity never needed to be larger than one. I tried using spinners to prevent double clicking on the "Add to Cart" buttons but somehow users still found ways to double click. I still don't know how but they did. I started my solution from trying to follow the drupal commerce user guide.

https://docs.drupalcommerce.org/commerce1/user-guide/shopping-cart/working-with-cart-rules-events

The problem I ran into was that when I tried to set the condition to

commerce-line-item:quantity \> 1 it tried to force me to use data selectors which doesn't give me any value option.

The only thing I could do was set

commerce-line-item:quantity = 2 and then the routine would work. But if someone triple and went really crazy with the clicks this would not work because the QTY would get to three before the rule would finish firing. I then tried adding more conditions in an OR statement but found the performance of the rule was unreliable even in non stress situations. THEN THE EUREKA MOMENT.

I didn't need any condition since everything on my website is to be set to 1. So no product type conditions, no pre-existing quantity conditions, etc... needed to be checked.

So here is what appears to be working for me. I'll come back and edit this if it fails at any point.

1. Create new Rule
2. Set Event to "After adding a product to the cart"
3. Set Actions to
1st Action: Set a Data Value commerce-line-item:quantity = 1 2nd Action: Set Save Entity commerce-line-item:order I left "Force Immediate Save to false (or unchecked).

Comments: On my website you must be logged in to make a purchase. It appears to work for regular registered users and the admin role. I'll come back and update if I have any new problems with this running. What this routine does is make sure that after the user has finally stopped clicking the "Add to Cart" button, line item quantity is set back to 1 and the cart is recalculated. I imagine it increases the "Add to Cart" time a little bit. But it should be worth it not to have calls from people that didn't realize they had overpaid because they added the product to the cart twice. I'm a bit surprised but it happens all the time. Especially on my website cause when I was on drupal 6 I used a different commerce solution and forcing a quantity of 1 was already coded in. So many customers never bothered to check.

---
Tags: rules, database, commerce
---


# Question
Title: Is it possible to get the last number of a views pager to display after and before the elipses?
I'm trying to create a custom pager similar to the Amazon pager:

> \< 1 2 3 4 ... **82** \>

and after a certain point:

> \< **1** ... 7 8 9 10 ... **82** \>

But, I cant figure out how to display the last pager number after the elipse. Is this possible? What would be the best way to go about this?

# Answer
I'm not sure if this is the best approach, but it's been working for me.

First I set the pager items to display as inline-block. Then I styled the .prev/.next items to float left/right respectively so they're on the outside.

I used `hook_preprocess_pager` and `$pager_total` to set the last pager number `$variables['tags'][4]`.

```
function hook_preprocess_pager(&$variables, $hook) {
  global $pager_total;
  $variables['tags'][4] = $pager_total[0];
}

```

I added a conditional so the last pager item wouldn't appear twice on the last couple pages:

```
function hook_preprocess_pager(&$variables, $hook) {
  global $pager_total;
  $variables['tags'][4] = $pager_total[0];
  if( is_numeric( $_GET['page'] ) &&  $pager_total[0] - 6 < $_GET['page'] ) $variables['tags'][4] = '';
}

```

I set the first page to "1" in the view settings, then use a similar conditional so it doesn't appear twice on the first couple pages.

```
function hook_preprocess_pager(&$variables, $hook) {
  global $pager_total;
  $variables['tags'][4] = $pager_total[0];
  if( is_numeric( $_GET['page'] ) &&  $pager_total[0] - 6 < $_GET['page'] ) $variables['tags'][4] = '';
  if( is_numeric( $_GET['page'] ) && $_GET['page'] < 5 ) $variables['tags'][0] = '';
}

```

This seems to work pretty well.
> 0 votes

# Answer
For the next and previous links, you can use CSS Flexbox order property to move them on start and end position :

```
.pager {
  .pager__items {
    display: flex;
    align-items: center;
    justify-content: center;

    .pager__item {
      &.pager__item--previous {
        order: -1;
      }

      &.pager__item--next {
        order: 10;
      }
    }
  }
}

```

Then you can implement hook\_preprocess\_pager() to set first and last text number :

```
function hook_preprocess_pager(&$variables) {
  $element = $variables['pager']['#element'];

  /* @var $pager_manager \Drupal\Core\Pager\PagerManagerInterface */
  $pager_manager = \Drupal::service('pager.manager');
  $pager = $pager_manager->getPager($element);

  // Nothing to do if there is no pager.
  if (!isset($pager)) {
    return;
  }
  $pager_max = $pager->getTotalPages();

  // Nothing to do if there is only one page.
  if ($pager_max <= 1) {
    return;
  }
  $tags = $variables['pager']['#tags'];

  // Calculate various markers within this pager piece:
  // Middle is used to "center" pages around the current page.
  $current_page = $pager->getCurrentPage();

  // Alter the "first" link.
  if (isset($tags[0]) && $current_page > 1) {
    $variables['items']['first']['text'] = 1;
  }
  else {
    unset($variables['items']['first']);
  }

  // Alter the "last" link.
  if (isset($tags[4]) && $current_page < ($pager_max - 2)) {
    $variables['items']['last']['text'] = $pager_max;
  }
  else {
    unset($variables['items']['last']);
  }
}

```
> 0 votes

---
Tags: 7, views, theming, paging
---


# Question
Title: Prevent trigger of other hook_preprocess_HOOK()
Is there a way to prevent other preprocess hooks from being triggered?

I have a Drupal 8 `hook_preprocess_HOOK()` implementation, and I'm doing some alterations. There will be other modules with same hook, and I need the other preprocess hooks not to alter my changes to `$variables`.

The only options I have are:

* Rely on weights system, which still could cause problems
* Set a value inside `$variables` and prevent other modules from doing their thing if the variable is set

# Answer
You can disable hooks via hook\_module\_implements\_alter().

```
function MYMODULE_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'preprocess_page') {
    unset($implementations['module_foo']);
    unset($implementations['module_bar']);
  }
}

```
> 2 votes

# Answer
Here's an implementation for Drupal 9 that makes `MYMODULE_preprocess_image_style()` run first:

```
/**
 * Implements hook_theme_registry_alter().
 *
 * Makes MYMODULE_preprocess_image_style() run first.
 */
function MYMODULE_theme_registry_alter(&$theme_registry) {
  $themeKey = 'image_style';
  if (isset($theme_registry[$themeKey]['preprocess functions'])) {
    $fname = "MYMODULE_preprocess_$themeKey";
    $pf = &$theme_registry[$themeKey]['preprocess functions'];
    $index = array_search($fname, $pf);
    if ($index) {
      unset($pf[$index]);
      array_unshift($pf, $fname);
    }
  }
}

```
> 1 votes

# Answer
Preprocess hooks (and specifically `hook_preprocess_page`) are not subject to `hook_module_implements_alter`, even if they are implemented by modules. However, they can be adjusted by using `hook_theme_registry_alter` as suggested by @jonhattan above. Look in the `$theme_registrary['page']['preprocess functions']` for the indexed array of implementations.

Note: Tested with Drupal 9.3.8.
> 0 votes

---
Tags: theming, hooks
---


# Question
Title: Is it a best practice to give generally any node an alias?
For each node I can create an alias.

I mean to give an alias such as `/abc` alongside the path `/node/1`.

Is it a best practice to give generally any node an alias?

# Answer
Yes, you should generally give every node an alias. The default path of `/node/1` is not good for SEO; it is better to have a few keywords in the URL that describe the content of the page.

## Using a canonical URL

Although you should use aliases, you do not want to present both `/node/1` and `/my-alias-for-node1` to Google; instead, you should set the aliases (if they exist) as the canonical URL. This can be done automatically by configuring the Redirect module.

If you need to set canonical URLs beyond aliases (for example, if nodes 2 and 3 should actually refer to node 1 as the canonical URL), you can set that up with the Metatag module.

## Automatic alias generation

You can automate creation of aliases with the Pathauto module, which lets you use tokens to easily generate aliases based on patterns/rules that you choose.
> 1 votes

---
Tags: 9
---


# Question
Title: Dynamic webform component select options
In Drupal 7, dynamic options for a select widget could be created with `hook_webform_select_options_info()`:

```
/**
 * Implements hook_webform_select_options_info().
 */
function module_webform_select_options_info() {
  $items = array();
  $items['custom'] = array(
    'title' => t('Custom'),
    'options callback' => 'module_options_function',
  );
  return $items;
}

```

But this hook isn't in Drupal 9. What should be used in Drupal 9? The closest hook I see in webform.api.php is `hook_webform_options_alter()`.

# Answer
There is no replacement hook. In fact, many things that were hooks should now be done with webform handlers.

Below is a simplified version of my solution. Note that in order to set the options dynamically, the field must be added already with dummy option(s), or you need to add the field in the handler prior to setting its options.

```
<?php

namespace Drupal\my_module\Plugin\WebformHandler;

use Drupal\Core\Form\FormStateInterface;
use Drupal\webform\Plugin\WebformHandlerBase;
use Drupal\webform\WebformSubmissionInterface;

/**
 * My Module custom webform handler.
 *
 * @WebformHandler(
 *   id = "my_module_custom_webform_handler",
 *   label = @Translation("My Webform Handler"),
 *   category = @Translation("Custom"),
 *   description = @Translation("Alter form to populate field."),
 *   cardinality = \Drupal\webform\Plugin\WebformHandlerInterface::CARDINALITY_SINGLE,
 *   results = \Drupal\webform\Plugin\WebformHandlerInterface::RESULTS_PROCESSED,
 *   submission = \Drupal\webform\Plugin\WebformHandlerInterface::SUBMISSION_OPTIONAL,
 * )
 */
class MyModuleCustomWebformHandler extends WebformHandlerBase {

  /**
   * {@inheritdoc}
   */
  public function alterForm(array &$form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission): void {
    // Clear dummy options and set program options.
    $form['elements']['my_radios']['#options'] = $this->customService->getOptionList();
  }
}

```

Though the article below is not exactly what I needed, this was the step in the right direction that helped me find this solution:
> 1 votes

---
Tags: hooks, webforms, 9
---


title: Delete user in transaction

text:
# Question
Title: Delete user in transaction
I'm having trouble figuring out why the following code isn't working in Drupal 7. `_queue_processor` is a cron queue processor function:

```
function _queue_processor($uid) {

    $transaction = db_transaction();

    watchdog('debug', 'transaction created'); // This will not be called.

    try {
      user_delete($uid);
    }
    catch (Exception $e) {
      // A problem occurred. Rollback transaction.
      $transaction->rollback();
      throw $e;
    }
    // Rollback intentionally.
    if (variable_get('some_var', FALSE)) {
      $transaction->rollback();
    }
}

```

The code never makes it past the `$transaction = db_transaction();` line. However, if I remove the transaction and try/catch, `user_delete()` is called just fine, and the transaction that `user_delete_multiple()` creates within itself works as well.

Is there something wrong with putting `user_delete()` within a transaction? I know it already uses one, but I need to be able to run the deletion and then conditionally rollback afterwards, and I'd rather not do this by throwing an exception in an implementation of hook\_user\_delete() to force rollback.

I am using MariaDB.

# Answer
As far as I know, this can only be done using exceptions. Here is a minimal example. Note that the module in the code example is called `module`.

```
function module_queue_processor($uid) {
  try {
    // Delete user.
    user_delete($uid);
  }
  catch (DebugException $e) {
    // Catch custom exception. The inner transaction has been rolled back.
    // @todo The exception is still logged to watchdog in user_delete().
  }
}

/**
 * Implements hook_module_implements_alter().
 */
function module_module_implements_alter(&$implementations, $hook) {
  if ($hook == 'user_delete') {
    // Remove node_user_delete() to ensure nodes are not deleted.
    unset($implementations['node']);

    // Move module_user_delete() to the beginning of the list.
    // This ensures that custom processing is done first.
    // This may not be necessary, but it's a good idea.
    $group = $implementations['module'];
    $implementations = ['module' => $group] + $implementations;
  }
}

/**
 * Implements hook_user_delete().
 *
 * This hook is called before all others.
 */
function module_user_delete($account) {
  $uid = $account->uid;
  $name = $account->name;

  // Prevent deletion of anonymous and root users.
  if ($uid == 0 || $uid == 1) {
    watchdog('module', 'Cannot delete user with UID @uid.', array('@uid' => $uid), WATCHDOG_ERROR);
    return;
  }

  // It is not necessary to pass the transaction object to functions. The
  // transaction will automatically be committed when all open transaction
  // objects go out of scope.
  // For more information: https://drupal.stackexchange.com/a/285032
  $transaction = db_transaction();

  try {
    // Temporarily use strict error handler to throw exceptions for warnings and
    // notices. Without this, warnings might cause content to be not deleted
    // without a rollback of user deletion.
    set_error_handler('module_custom_error_handler');

    ...
  }
  catch (Exception $e) {
    // Rollback the transaction.
    $transaction->rollback();

    // Log the exception.
    $message = '%type while deleting user %name with UID %uid. Transaction not committed. !message in %function (line %line of %file).';
    $variables = array(
      '%name' => $name,
      '%uid' => $uid,
    );

    watchdog_exception('module', $e, $message, $variables);

    // Throw the exception again to halt user deletion.
    throw $e;
  }
  finally {
    // Restore the pre-existing error handler.
    restore_error_handler();
  }

  // Rollback intentionally.
  if (variable_get('module_dry_run', FALSE)) {
    $transaction->rollback();

    // Trigger transaction rollback inside user_delete_multiple().
    throw new DebugException($message);
  }
}

/**
 * Custom error handler used to make non-errors into exceptions.
 *
 * @link https://stackoverflow.com/questions/1241728/can-i-try-catch-a-warning
 */
function module_error_handler($errno, $errstr, $errfile, $errline) {
  // Error was suppressed with the @-operator.
  if (error_reporting() === 0) {
    return FALSE;
  }

  throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

/**
 * Custom exception used to trigger transaction rollback for dry run.
 */
class DebugException extends Exception {}

```
> 0 votes

---
Tags: users, database
---


# Question
Title: How to run drush using locally modified repo (from github fork)
I have my own drush repo forked from https://github.com/drush-ops/drush and have a local clone of this, as I want to start modifying and potentially push back to add a new function. How do I configure a local drupal site to use my local repo? I have tried replacing vendor/drush with a symlink to my repo but that produced the following

```
PHP Fatal error:
Declaration of DrupalCodeGenerator\Command\DrupalGenerator::getDestination(array $vars): ?string
must be compatible with DrupalCodeGenerator\Command\GeneratorInterface::getDestination()
in /path-to-my-drush-repo/vendor/chi-teck/drupal-code-generator/src/Command/DrupalGenerator.php
 on line 141

```

I have tried tracking down the cause of that problem, but I dont think this is right way to solve it. I must be doing something else wrong. I want to contribute to drush development but getting stuck here.

# Answer
> 0 votes
Add the path to the local Git working copy as a VCS repository in the Drupal project with a file:// URI. Specify `dev-your-branch-name` for the package version.

---
Tags: drush
---


title: SQL error in Module

text:
# Question
Title: SQL error in Module
I'm trying to query the database inside my module, but I get this error.

> Drupal\Core\Database\DatabaseExceptionWrapper: SQLSTATE\[42000\]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FROM "commerce\_product\_variation" "cpv" WHERE ("variation\_id" NOT IN (NULL)) AND' at line 1: SELECT FROM "commerce\_product\_variation" "cpv" WHERE ("variation\_id" NOT IN (:db\_condition\_placeholder\_0)) AND ("status" = :db\_condition\_placeholder\_1); Array ( \[:db\_condition\_placeholder\_0\] =\> \[:db\_condition\_placeholder\_1\] =\> 1 ) in deactivateProductVariantsNotInList() (regel 816 van /data/sites/web/pcreathingbe/subsites/staging.protectasolutions.be/web/modules/custom/importproducts/importproducts.module).

The code I am using is the following.

```
function deactivateProductVariantsNotInList($variant_type) {
  global $milieu_data;

  if ($variant_type == 'milieutechniek') {
    $database = \Drupal::service('database');
    $query = $database->select('commerce_product_variation', 'cpv');
    $query->condition('variation_id', $milieu_data, 'NOT IN')
      ->condition('status', 1)
      ->execute();
  }
}

```

# Answer
If you take a closer look at your error message, your query probably fails because your `$milieu_data` variable is null.

`FROM "commerce_product_variation" "cpv" WHERE ("variation_id" NOT IN (NULL)) AND`  where (NULL) is your `$milieu_data` variable value.

In a NOT IN condition, it should be formatted like `NOT IN (value1, value2, ...)`. If `$milieu_data` is allowed to be null, then you should add a condition to have your query condition modified to `$query->isNotNull("variation_id");`
> 2 votes

# Answer
I cannot speak to misterdidi's answer it may apply also . . . but

Your error message points specifically to a syntax error. As I said in the comments it appears to be a " ; " - the semicolon at

$query = $database-\>select('commerce\_product\_variation', 'cpv');

which should be

$query = $database-\>select('commerce\_product\_variation', 'cpv')

A PHP code checker will report no issue with either but Drupal is sensitive to it

For instance in Drupal 7 this code below

```
   $weight = db_select('system', 's')
     ->fields('s', array('weight'))
     ->condition('name', 'uc_quote', '=')
     ->execute()
     ->fetchField();
   db_update('system')
     ->fields(array('weight' => $weight + 1))
     ->condition('name', 'uc_addresses', '=')
     ->execute();

```

ONLY has the semicolon at the end or execute and in Drupal 8/9 Drupalmoduleupgrader changed it to

```
   $weight = \Drupal::database()->select('system', 's')
     ->fields('s', array('weight'))
     ->condition('name', 'uc_quote', '=')
     ->execute()
     ->fetchField();
   // TODO: Drupal Rector Notice: Please delete the following comment after you've made any necessary changes.
   // You will need to use
  \Drupal\core\Database\Database::getConnection()` if you
 do not yet have access to the container here.
   \Drupal::database()->update('system')
     ->fields(array('weight' => $weight + 1))
     ->condition('name', 'uc_addresses', '=')
     ->execute();

```

While there is no "system" table any longer in Drupal 8 / 9 the purpose of DrupalModuleUpgader and Drupal Rector is to correct syntax and apply coding standards

You will notice whether it is $weight or your $query variable there is no semicolon behind the statement.

The semicolon needs to be removed
> -2 votes

---
Tags: database, 9
---


# Question
Title: Create a Context/Condition and get a view display used on the page
I want to create a context/condition plugin that checks the total results returned from a view display on the page (its a block), and if its less/greater than a certain figure, hide certain peripheral display elements.

I cannot seem to find a ContextDefinition for the view being executed, does this exist? Do I need to grab the context from the Block itself? How?

# Answer
I wound up writing a specific module for this.

https://www.drupal.org/project/views\_minimum
> 0 votes

---
Tags: views, 9, plugins
---


# Question
Title: How do I load the Bootstrap CSS into a CKEditor template?
Just how we add custom theme style, I want to add Bootstrap CSS. Is there a way to do it?

```
/**
 * Implements hook_ckeditor_css_alter().
 */
function mymodule_ckeditor_css_alter(array &$css, Editor $editor) {
  $css[] = \Drupal::service('extension.list.theme')->getPath('my_theme') . '/css/styles.css';
}

```

# Answer
> 0 votes
The body classes in ckeditor start with cke\_. So I created a \_ckeditor.scss file with most of the classes I used on my site, wrapped in body.cke\_editable and then included that file in my style.scss.

Should work with straight up css included via THEME.info.yml or THEME.libraries.yml

---
Tags: wysiwyg, bootstrap-theme
---


# Question
Title: simple view of a custom entity is extremely slow
I have created a custom entity to store payment information:

```
 * @ContentEntityType(
 *   id = "bank_operation",
 *   label = @Translation("Bank operation"),
 *   handlers = {
 ...
 *   },
 *   base_table = "bank_operation",
 *   fieldable = TRUE,
 *   revisionable = FALSE,
 *   translatable = FALSE,
 *   internal = TRUE,
 *   entity_keys = {
 *     "id" = "id",
 *     "uuid" = "uuid"
 *   },
 *   common_reference_target = TRUE,
 *...
 *   },
 * )
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {

    // Standard field, used as unique if primary index.
    $fields['id'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('ID'))
      ->setDescription(t('The ID of the BankOperation entity.'))
      ->setReadOnly(TRUE);

    // Standard field, unique outside of the scope of the current project.
    $fields['uuid'] = BaseFieldDefinition::create('uuid')
      ->setLabel(t('UUID'))
      ->setDescription(t('The UUID of the BankOperation entity.'))
      ->setReadOnly(TRUE);

    return $fields;
  }

```

Through the GUI, I have added 17 other fields: Operation date, Statement date , amount, account number, Statement number, ...

And I have created a simple view (without any relation) to display my Bank operation entities (the count is approx 10 000 items displayed 40 by 40). It display the 7 main fields in a table.

Unfortunately this view is taking +/- 1-2 minutes to be displayed

What should I do to speed up this view? Should I add few indexes? if yes how?

Here are the request made by the view:

```
SELECT "bank_operation"."id" AS "id", DATE_FORMAT(bank_operation__field_operation_date.field_operation_date_value, '%Y%m%d') AS "bank_operation__field_operation_date_field_operation_date_va"
FROM
{bank_operation} "bank_operation"
LEFT JOIN {bank_operation__field_fake_bo} "bank_operation__field_fake_bo" ON bank_operation.id = bank_operation__field_fake_bo.entity_id AND bank_operation__field_fake_bo.deleted = '0'
LEFT JOIN {bank_operation__field_company} "bank_operation__field_company" ON bank_operation.id = bank_operation__field_company.entity_id AND bank_operation__field_company.deleted = '0'
LEFT JOIN {bank_operation__field_operation_date} "bank_operation__field_operation_date" ON bank_operation.id = bank_operation__field_operation_date.entity_id AND bank_operation__field_operation_date.deleted = '0'
WHERE ("bank_operation__field_company"."field_company_target_id" = '00597853560') AND ("bank_operation__field_fake_bo"."field_fake_bo_value" = '1')
ORDER BY "bank_operation__field_operation_date_field_operation_date_va" DESC

```

And this ones:

```
[0.000234 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( views:exposed_form ) ORDER BY "cid"

```

This ones is repeated 11 times (really strange)

```
[0.000299 ms] SELECT "s".*, "t"."language" AS "language", "t"."translation" AS "translation", "t"."customized" AS "customized"
FROM
"locales_source" "s"
LEFT OUTER JOIN "locales_target" "t" ON t.lid = s.lid AND t.language = fr
WHERE ("s"."source" IN (Is less than)) AND ("s"."context" IN ())

```

Then those ones (the last is long as 15 pages):

```
[9.7E-5 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( views:pager ) ORDER BY "cid"
[0.000149 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( views:access ) ORDER BY "cid"
[0.000137 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( views:join ) ORDER BY "cid"
[0.000213 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( views:argument_validator ) ORDER BY "cid"
[0.000533 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( entity_type_definitions.installed ) ORDER BY "cid"
[0.000288 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( bank_operation.field_storage_definitions.installed ) ORDER BY "cid"
[0.000277 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( views:cache ) ORDER BY "cid"
[0.037341 ms] SELECT COUNT(*) AS "expression"
FROM
(SELECT 1 AS "expression"
FROM
"bank_operation" "bank_operation"
LEFT JOIN "bank_operation__field_fake_bo" "bank_operation__field_fake_bo" ON bank_operation.id = bank_operation__field_fake_bo.entity_id AND bank_operation__field_fake_bo.deleted = 0
LEFT JOIN "bank_operation__field_company" "bank_operation__field_company" ON bank_operation.id = bank_operation__field_company.entity_id AND bank_operation__field_company.deleted = 0
LEFT JOIN "bank_operation__field_operation_date" "bank_operation__field_operation_date" ON bank_operation.id = bank_operation__field_operation_date.entity_id AND bank_operation__field_operation_date.deleted = 0
WHERE ("bank_operation__field_company"."field_company_target_id" = 00597853560) AND ("bank_operation__field_fake_bo"."field_fake_bo_value" = 1)) "subquery"
[0.050103 ms] SELECT "bank_operation"."id" AS "id", DATE_FORMAT(bank_operation__field_operation_date.field_operation_date_value, '%Y%m%d') AS "bank_operation__field_operation_date_field_operation_date_va"
FROM
"bank_operation" "bank_operation"
LEFT JOIN "bank_operation__field_fake_bo" "bank_operation__field_fake_bo" ON bank_operation.id = bank_operation__field_fake_bo.entity_id AND bank_operation__field_fake_bo.deleted = 0
LEFT JOIN "bank_operation__field_company" "bank_operation__field_company" ON bank_operation.id = bank_operation__field_company.entity_id AND bank_operation__field_company.deleted = 0
LEFT JOIN "bank_operation__field_operation_date" "bank_operation__field_operation_date" ON bank_operation.id = bank_operation__field_operation_date.entity_id AND bank_operation__field_operation_date.deleted = 0
WHERE ("bank_operation__field_company"."field_company_target_id" = 00597853560) AND ("bank_operation__field_fake_bo"."field_fake_bo_value" = 1)
ORDER BY "bank_operation__field_operation_date_field_operation_date_va" DESC
[0.043597 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_entity" WHERE "cid" IN ( values:bank_operation:10403, values:bank_operation:10381, values:bank_operation:3408, values:bank_operation:2790, values:bank_operation:3639, values:bank_operation:3640, values:bank_operation:3634, values:bank_operation:3647, values:bank_operation:2799, values:bank_operation:9,
 values:bank_operation:3405, values:bank_operation:10379, values:bank_operation:3668, values:bank_operation:10322, values:bank_operation:3643, values:bank_operation:3664, values:bank_operation:3416,
 values:bank_operation:3381, values:bank_operation:3606, values:bank_operation:10286, values:bank_operation:10288, values:bank_operation:3604, values:bank_operation:10290, values:bank_operation:3667,
 values:bank_operation:10321, values:bank_operation:62, values:bank_operation:3160, values:bank_operation:3420, values:bank_operation:3446, values:bank_operation:3575, values:bank_operation:3428,
 values:bank_operation:10402,.....
 ... 15 full pages of values ...

```

And another 30 pages of the following

```
[0.019228 ms] SELECT "base"."id" AS "id", "base"."uuid" AS "uuid"
FROM
"bank_operation" "base"
WHERE "base"."id" IN (10403, 10381, 3408, 2790, 3639, 3640, 3634, 3647, 2799, 9, 3405, 10379, 3668, 10322, 3643, 3664, 3416, 3381, 3606, 10286, 10288, 3604, 10290, 3667, 10321, 62, 3160, 3420, 3446, 3575,
 3428, 10402, 3512, 3145, 3520, 3437, 3508, 8807, 8852, 8916, 10394, 8840, 8949, 8898, 8828, 8822, 8816, 8880, 10396, 8925, 8810, 8631, 8919, 8849, 8907, 8952, 8837, 8786, 10398, 8825, 8262, 8819, 8928, 10387,
 10400, ... 3 pages of id ...

[0.00032 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( entity_bundle_field_definitions:bank_operation:bank_operation:fr ) ORDER BY "cid"
[0.869771 ms] SELECT "t".*
FROM
"bank_operation__field_amount" "t"
WHERE ("entity_id" IN (2913, 7134, 2591, 2586, 7060, 2616, 9744, 3115, 1576, 6496, 821, 5057, 8491, 5844, 579, 6638, 7852, 3807, 3167, 5793, 9467, 6534, 10295, 3363, 7654, 2256, 5125, 2043, 10074, 8873, 7061, 1284,
 10260, 9587, 10206, 1677, 1621, 2826, 463, 4036, 3129, 4887, 3445, 7235, 6240, 2083, 2923, 7564, 5812, 859, 7570, 7807, 10207, 1640, 736, 5417, 1577, 7427, 7792, 8261, 53, 2597, 8747, 2810, 7261, 3985, 1606, 6998,
 266, 8598, ... 3 pages of id ...

 The same happens for each field on approx 30 pages

```

The following become very huge:

```
[0.000243 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( entity_bundle_info:fr ) ORDER BY "cid"
[6.4E-5 ms] SELECT "tag", "invalidations" FROM "cachetags" WHERE "tag" IN ( entity_bundles )
[0.000244 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_config" WHERE "cid" IN ( user.settings ) ORDER BY "cid"
[0.000145 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_config" WHERE "cid" IN ( language.fr:user.settings ) ORDER BY "cid"
[0.000416 ms] SELECT "cid", "data", "created", "expire", "serialized", "tags", "checksum" FROM "cache_discovery" WHERE "cid" IN ( entity_field_map ) ORDER BY "cid"
[0.000133 ms] SELECT "tag", "invalidations" FROM "cachetags" WHERE "tag" IN ( bank_operation_values )
[0.002551 ms] INSERT INTO "cache_entity" ("cid", "expire", "created", "tags", "checksum", "data", "serialized") VALUES (values:bank_operation:2913, -1, 1667477872.318, bank_operation_values entity_field_info, 8818, O
:42:"Drupal\bank_operation\Entity\BankOperation":29:{s:9:"*values";a:18:{s:2:"id";a:1:{s:9:"x-default";s:4:"2913";}s:4:"uuid";a:1:{s:9:"x-default";s:36:"0000de0a-d738-481b-8d45-60f4f5f57539";}s:12:"field_amount";
a:1:{s:9:"x-default";a:1:{i:0;a:1:{s:5:"value";s:9:"-16661.70";}}}s:13:"field_company";a:1:{s:9:"x-default";a:1:{i:0;a:1:{s:9:"target_id";s:11:"00597853560";}}}s:21:"field_company_account";a:1:{s:9:"x-default";
a:1:{i:0;a:1:{s:5:"value";s:16:"BE07363143795466";}}}s:17:"field_company_bic";a:1:{s:9:"x-default";a:1:{i:0;a:1:{s:5:"value";s:8:"BBRUBEBB";}}}s:26:"field_counterparty_account";a:1:{s:9:"x-default";a:1:{i:0;a:1:
... the serialized value are listed on 1000 or 2000 pages ....

```

I stop here as I have thousand of pages with SQL queries...

# Answer
> 0 votes
I found the solution. Many thanks for those who tried to help me. The problem was not the SQL but the rendering time and this was due to the module Views Aggregator Plus which was displaying the results of my view.

Sorry for the time spent on such stupid problem

---
Tags: views
---


# Question
Title: How to show fields in the Inline Entity Form display widget?
I've just started with Inline Entity Form and seem to have it working with a custom entity type that has fields. My problem is, none of these fields show in the Inline Entity Form widget, it just shows an empty ID column and Edit / Delete buttons:

I've looked through what little documentation there is, and browsed related issues and questions, but they all seem to be doing things more complex than what I'm trying to do.

Is there any simple way to just choose a field or two to display in the Inline Entity Form widget?

It seems to "just work" for nodes - how can I have it pick up the entity fields in a similar way?

# Answer
> 8 votes
Use hook\_inline\_entity\_form\_table\_fields\_alter() this is what I am using on a current site:

```
function MY_MODULE_inline_entity_form_table_fields_alter(&$fields, $context) {
  //Determine the bundle and entity type from $context

  unset($fields['id']); //<get rid of the id field

  //add any fields you need to the $fields array
  $fields['FIELD_NAME'] = array(
    'type' => 'field',
    'label' => t('FIELD'),
    'weight' => 2
  );

}

```

# Answer
> 5 votes
To add to Mojeferous' answer, you do this indeed by implementing `hook_inline_entity_form_table_fields_alter()` in your module which is documented in the modules' inline\_entity\_form.api.php.

You can add properties, custom fields or call backs as columns. See the below example.

Note: to prevent error messages, check for the entity types.

```
function custommodule_inline_entity_form_table_fields_alter(&$fields, $context) {
  if ($context['parent_entity_type'] == 'customentity' && $context['entity_type'] == 'anothercustomentity') {
    $fields['field_custom'] = array(
      'type' => 'field',
      'label' => t('Custom'),
      'weight' => 101,
    );
    $fields['title'] = array(
      'type' => 'property',
      'label' => t('Title'),
      'weight' => 1,
    );
  }
}

```

See: https://www.drupal.org/node/2091585 and https://www.drupal.org/node/2497289

# Answer
> 5 votes
I made a module - IEF Table View Mode that can help you with that using the view mode

> This module defines a view mode to set up the columns of the table for the Inline Entity Form widget.
>
> With this you could define which fields (with their settings) and in what order will be displayed in the table. Also includes the properties defined by the entity and IEF.

# Answer
> 0 votes
In case anyone is looking to output a taxonomy term ID...

```
/**
 * Implements hook_inline_entity_form_table_fields_alter().
 */
function HOOK_inline_entity_form_table_fields_alter(array &$fields, array $context) {
  if ($context['parent_entity_type'] === 'taxonomy_term') {
    $fields['tid'] = [
      'type' => 'field',
      'label' => t('Term ID'),
      'weight' => 2,
    ];
  }
}

```

Use of the type `property` threw me off as the latest version of the code does not actually have a condition that looks for `property` in type. See: https://git.drupalcode.org/project/inline\_entity\_form/-/blob/8.x-1.x/inline\_entity\_form.module#L393

---
Tags: entities
---


# Question
Title: How to load a dependency in the <head> in drupal 9?
I have followed the official documentation, but it doesn't work

```
global-styling:
  version: VERSION
  js:
    js/bootstrap.min.js: {}
    js/custom.js: {}

  css:
    component:
      css/style.css: {weight: 50}
  dependencies:
    - core/drupalSettings
    - core/jquery
    - core/jquery.once
    - core/drupal
    - core/popperjs
    - my_theme/fontawesome

fontawesome:
  js-header:
    header: true
    js:
      //kit.fontawesome.com/12345678.js: {}

```

This gives me error:

> Drupal\Core\Asset\Exception\IncompleteLibraryDefinitionException: Incomplete library definition for definition 'fontawesome' in extension 'my\_theme' in Drupal\Core\Asset\LibraryDiscoveryParser-\>buildByExtension() (line 131 of core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php).

Please note that I wanna keep my js file in the `dependencies`, I don't want to do the following:

```
global-styling:
  version: VERSION
  js-header:
    header: true
      js:
        //kit.fontawesome.com/1234556.js: {}

```

# Answer
`js-header` is not a valid libraries configuration key. If you read the documentation page closely, you will find, that it has been used as library name (first level of the yml file) for the example given.

Instead, you'll have to define your fontawesome library this way:

```
fontawesome:
  header: true
  js:
    //kit.fontawesome.com/12345678.js: { external: true }

```

YAML (in Drupal just \*.yml) files are used to describe data structures (configuration). They use indentations for nested scopes. So it is very important that you don't add indentations where they aren't needed and provide configuration keys at the level where they are expected by Drupal. That is, at the second level of a library definition (first indentation), `version`, `js`, `css`, `dependencies` and `header` are allowed only, each of which has its own expected sub structure.

Either `js` or `css` MUST exist with at least one entry for a library. The error you have seen occurs, if you define a library without any `js` or `css` configuration keys.
> 2 votes

---
Tags: javascript
---


# Question
Title: Exposed date filter adds a timezone offset in query
In Drupal 8, when creating a view with an exposed filter on a Date field (which is in `date only` mode), the resulting query removes some hours based on my timezone.

I'm in the UTC+2 timezone, so a date filter of `2016-04-20` creates a query of `DATE_FORMAT('2016-04-19T22:00:00', '%Y-%m-%d')`. And so, none of the nodes I want are displayed...

How to avoid that?

# Answer
The following helps when rendering views programmatically:

```
$event_date_time = new \DateTime($query->get('date'), new \DateTimeZone('America/New_York'));
$event_date_time->modify('+1 day');
$event_date = $event_date_time->setTimezone(new \DateTimeZone('America/New_York'))->format('Ymd');

$view = \Drupal\views\Views::getView('events');
$view->setArguments([$event_date]);
$output['events'] = $view->preview();

```
> 0 votes

# Answer
Wow. It seems the core issue has not yet resolved.

That happens because: `\Drupal\datetime\Plugin\views\filter\Date`

```
  protected function opSimple($field) {
    $timezone = $this->getTimezone();
    $origin_offset = $this->getOffset($this->value['value'], $timezone);
    //...
  }

  protected function getTimezone() {
    return $this->dateFormat === DateTimeItemInterface::DATE_STORAGE_FORMAT
      ? DateTimeItemInterface::STORAGE_TIMEZONE
      : date_default_timezone_get();
  }

```

calls `$this->getTimezone()` and `$this->dateFormat` in my case is `Y` (I selected "Year" granularity within filter configuration).

Then `getTimezone` returns default server timezone. That's because `DateTimeItemInterface::DATE_STORAGE_FORMAT` is `Y-m-d` to get UTC timezone.

Meantime, I use the next trick (In my case I need a filter by year) with adding custom exposed form element validate callback.

```
function kb9_issue_form_views_exposed_form_alter(array &$form, FormStateInterface $form_state): void {
  if ($form['#id'] === 'views-exposed-someview-page-1') {
    $currentYear = (int) date('Y');
    $years = array_reverse(range(
      MIN_YEAR,
      $currentYear - 1
    ));

    $options = ['now' => $currentYear] + array_combine($years, $years);

    if (isset($form['year'])) {
      $form['year'] = [
        '#type' => 'select2',
        '#options' => $options,
        '#select2' => [
          'placeholder' => t('Select year'),
        ],
        '#prefix' => '<div class="year-container">',
      ];

      unset($form['year']['#process']);
      array_unshift($form['#validate'], 'mymodule_validate_year_filter');
    }
}

function mymodule_validate_year_filter(&$form, FormStateInterface $form_state) {
  $year = $form_state->getValue('year') ?? FALSE;

  // If user deleted value from GET parameter (e.g year=''),
  // then fill it with current year.
  if (empty($year)) {
    $form_state->setValue('year', 'now');
  }
  else {
    // Make year a bit bigger than default timezone offset.
    // Alternativelly, you can calculate needed ofset.
    // And ofcause you need validate year format before :)
    $form_state->setValue('year', $year . '-1-2');
  }
}

```
> 0 votes

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