title: Youtube media thumbnail size

text:
# Question
Title: Youtube media thumbnail size
I want to control the thumbnail image size for my media entities of type video.

The thumbnail image size being fetched by the media module from Youtube has 480 x 360px.

I want to use the 1280x720 images. Is there a way for me to control this?

# Answer
> 2 votes
Drupal core issue regarding this problem: https://www.drupal.org/project/drupal/issues/3042423

After patching, I would implement the new hook\_oembed\_resource\_data\_alter:

```
function MY_MODULE_oembed_resource_data_alter(array &$data, $url) {
  if (strpos($url, 'youtube.com/oembed') !== FALSE) {
    $thumbnailUrl = str_replace('hqdefault', 'maxresdefault', $data['thumbnail_url']);
    $data['thumbnail_url'] = $thumbnailUrl;
  }
}

```

Then I would also run an update hook to update the existing thumbnails:

```
function MY_MODULE_update_N(&$sandbox) {
  /** @var \Drupal\media\MediaStorage $mediaStorage */
  $mediaStorage = \Drupal::entityTypeManager()->getStorage('media');
  if (!isset($sandbox['progress'])) {
    $result = $mediaStorage->getQuery()->condition('bundle', 'video');
    $mediaItems = $result->execute();
    $max = count($mediaItems) - 1;
    $sandbox['progress'] = 0;
    $sandbox['mediaItems'] = array_values($mediaItems);
    $sandbox['max'] = $max;
  }
  $progress = $sandbox['progress'];
  /** @var \Drupal\media\MediaInterface $media */
  $media = $mediaStorage->load($sandbox['mediaItems'][$progress]);
  if (!$media->get('thumbnail')->isEmpty()) {
    $media->get('thumbnail')->delete();
  }
  $media->updateQueuedThumbnail();
  $media->save();
  $sandbox['progress']++;
  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : $sandbox['progress'] / $sandbox['max'];
}

```

# Answer
> 2 votes
Building on José Trindade's answer, here's my solution that uses Guzzle to find the highest resolution that YouTube actually provides for a given video:

```
use GuzzleHttp\Client as GuzzleClient;

/**
 * Implements hook_oembed_resource_data_alter().
 *
 * This tries to fetch the highest available YouTube video thumbnail by sending
 * requests via Guzzle for the various formats from highest to lowest, using the
 * first one that doesn't return a 404.
 *
 * @param array &$data
 *   The oEmbed data, parsed into an array.
 *
 * @param string $url
 *   The oEmbed URL that $data was retrieved from.
 *
 * @see https://www.drupal.org/project/drupal/issues/3042423
 *   This hook won't be invoked unless this Drupal core patch is applied.
 */
function YOUR_MODULE_oembed_resource_data_alter(array &$data, $url) {
  if (
    $data['provider_name'] === 'YouTube' &&
    strpos($data['thumbnail_url'], 'hqdefault.jpg') !== false
  ) {
    // Array of thumbnail sizes above 'hqdefault' to try, started with the
    // largest size.
    //
    // @see https://stackoverflow.com/a/20542029
    $thumbnailTypes = [
      'maxresdefault' => [
        'width'   => 1920,
        'height'  => 1080,
      ],
      'sddefault' => [
        'width'   => 640,
        'height'  => 480,
      ],
    ];

    $client = new GuzzleClient();

    foreach ($thumbnailTypes as $thumbnailName => $thumbnailDimensions) {
      // Replace 'hqdefault' in the thumbnail URL with the current type we're
      // testing for.
      $testThumbnailURL = str_replace(
        'hqdefault',
        $thumbnailName,
        $data['thumbnail_url']
      );

      // We need to wrap the request in a try {} catch {} because Guzzle will
      // throw an exception on a 404.
      try {
        $response = $client->request('GET', $testThumbnailURL);

      // Got an exception? Skip to the next thumbnail size, assuming this
      // returned a 404 or ran into some other error.
      } catch (Exception $exception) {
        continue;
      }

      // If this was a 200 response, update the thumbnail URL and dimensions
      // with the higher resolution and break out of the loop.
      if ($response->getStatusCode() === 200) {
        $data['thumbnail_url']    = $testThumbnailURL;
        $data['thumbnail_width']  = $thumbnailDimensions['width'];
        $data['thumbnail_height'] = $thumbnailDimensions['height'];

        break;
      }
    }
  }
}

```

Don't forget to replace `YOUR_MODULE` with the name of your custom module.

# Answer
> 1 votes
Thanks to Jose Trinidad and Ambient.Impact for their answers, they helped me a lot. To get the Jose's update-function to work in my project though I had to set the bundle to 'remote\_video' instead of only video:

`$result = $mediaStorage->getQuery()->condition('bundle', 'remote_video');`

I think the video bundle refers to normally uploaded videos

---
Tags: 8, media
---


# Question
Title: Show a summary calculated from webform submitted values on the submission preview page only (not on form) and re-use in e-mail handler
We need to display a computed summary of submitted information on both the submission preview page and in e-mails that are sent out.

I'd expect this is a common usecase and wanted to check if i'm missing something obvious before cobbling something together (and documenting that and leading others astray!)— like figuring out if computed twig elements can be excluded from the original form, and if the same computed twig elements can be pulled into the email handler easily.

# Answer
> 0 votes
It's not the way i'd prefer to do it, but as far as putting customization on the preview page, there is at least an alternate template available for that:

```
 FILE NAME SUGGESTIONS:
   * webform-submission-data--preview.html.twig
   * webform-submission-data--webform-10152--preview.html.twig
   * webform-submission-data--webform-10152.html.twig
   x webform-submission-data.html.twig

```

Rather than use the overall template above, we decided to do most of the work in a preprocess function for a key element on the webform. This only affects the preview page, as it's about the HTML display not the form element.

```
function example_preprocess_webform_element_base_html__example_element__specific_instance(&$vars) {
  $rows = example_summary($vars['webform_submission']);
  $vars['table_summary'] = [
   '#type' => 'table',
   '#rows' => $rows,
  ];
}

```

We can take the `{{ table_summary }}` variable we added there and include it in the custom template for that element, `webform-element-base-html--example-element--specific-instance.html.twig`.

---
Tags: theming, webforms, 9, configuration
---


# Question
Title: How to display specific button for certain user?
I have a simple Drupal 7 page with 3 buttons. Page is only accessible by logged-in users.

I have 3 roles - role 1, role 2 & role 3

What I would like to do is to show only **button 1** when a user with **role 1** logged in, hide the other 2. How can I achieve this, please?

# Answer
To hide and show buttons by role you can use the ***$GLOBALS*** to get the user and check on user role, something like.

```
 <?php if (in_array('role 1', $GLOBALS["user"]->roles)): ?>
    <button value="button 1">button 1</button>
  <?php else: ?>
    <button value="button 2">button 2</button>
    <button value="button 3">button 3</button>
  <?php endif; ?>

```
> 0 votes

---
Tags: 7, theming
---


# Question
Title: Why is the CSS in my sub-theme not working?
I'm a Drupal newbie, but hoping someone can assist. The site was working okay, but I've tried to implement a sub-theme and things seem to have gotten messed up.

What I was trying to achieve is to include my own CSS/JS files, and figured that a sub-theme seems like the proper way to do it. Well, I did install the sub-theme, but no CSS or JS from the sub-theme was loading (or referenced in the page anywhere). So, I played around some more and eventually stopped the entire site from loading.

So, now I'm getting "The website encountered an unexpected error. Please try again later.", and the Apache error log says:

```
"Uncaught PHP Exception Drupal\\Core\\Asset\\Exception\\IncompleteLibraryDefinitionException: "
 Incomplete library definition for definition 'global-styling' in extension 'my_theme'" at ..."

```

My theme is called "my\_theme", and is meant to be a sub-theme of `awesome_zymphonies_theme`. Went to loads of places trying to figure out the sub-theme stuff, given the abysmal Drupal documentation, but ended up with a directory called "`my_theme`", under `/drupal/themes/`, and directories of `/css/` and `/js/`, with CSS and JavaScript files in each, respectively, and two files: `my_theme.info.yml` and `my_theme.libraries.yml`. Permissions are all okay, and owned by apache:apache.

```
drwxr-xr-x. 2 apache apache   26 Mar 24 20:30 css
drwxr-xr-x. 2 apache apache   25 Mar 24 20:30 js
-rw-r--r--. 1 apache apache 1300 Mar 24 20:57 my_theme.info.yml
-rw-r--r--. 1 apache apache   86 Mar 24 20:30 my_theme.libraries.yml

```

The file `my_theme.libraries.yml` looks like this:

```
global-styling:
css:
  theme:
    css/my_theme.css: {}

js:
    js/my_theme.js: {}

```

The top portion of the `my_theme.info.yml` file looks like this:

```
name: My Theme
type: theme
description: Sub-theme of 'Awesome Zymphonies Theme.'
package: core
base theme: awesome_zymphonies_theme
core: 8.x
core_version_requirement: ^8 || ^9

#Libraries
libraries:
  - awesome_zymphonies_theme/bootstrap
  - awesome_zymphonies_theme/global-components
  - my_theme/global-styling

#Regions
regions:
  header: 'Header'
  primary_menu: 'Primary Menu'
  slideshow: 'Slideshow'
  homepagemessage: 'Home page message'
  topwidget_first: 'Top First Widget'
  topwidget_second: 'Top Second Widget'
  topwidget_third: 'Top Third Widget'
  ....
  ....

```

Additionally, not sure if I need to include the two lines:

```
  - awesome_zymphonies_theme/bootstrap
  - awesome_zymphonies_theme/global-components

```

... or do they get inherited from the parent theme?

So, I guess three questions there really. Any assistance would be most appreciated. Thanks!

# Answer
> 1 votes
The `my_theme.libraries.yml` isn't indented correctly.

```
global-styling:
  css:
    theme:
      css/my_theme.css: {}
  js:
    js/my_theme.js: {}

```

---
Tags: theming, 9
---


title: Shipping weight not calculated?

text:
# Question
Title: Shipping weight not calculated?
we are currently trying to get our drupal commerce 2 attaching a certain shipping method based on the weight of the order. It is pretty simple (at least I thought so): if the order is below 20kg, it is one rate, above a second rate.

Here is what I did:

* enabled commerce shipping module and physical fields
* added a custom physical weight field **field\_prod\_gewicht** to the default product type (the only one we have)
* marked the default product variation as shippable
* filled the individual products with their weights accordingly
* created two shipping methods with different prices, only restricted by **Shippment Weight**

So far so good - on the shipping page I see indeed only the lower rate shipping method, but if I add more weight to the order, the higher rate shipping method never appears.

My suspicion is, that the weight is not calculated at all, or that there is some kind of implicit convention I did not follow.

Anybody has an idea, how to solve or debug this?

Thx a lot!

# Answer
In the end it was ideed as expected a convention: If you enable the commerce shipping module a system level weight field will be added automatically to the **Product Variation** Entity, not the product.

This weight field is the only field, used for order weight calculations and other custom fields are ignored. All in all very logical ;)

If you want to use the weight in templates, it can be done via `{{ product.variation_weight }}`
> 0 votes

---
Tags: 8, commerce
---


# Question
Title: Count how many times a node is referenced
I have a content type: **classroom**

I have another content type: **lesson**

Lesson nodes have an entity reference field (field\_classroom) that reference classrooms.

I want to create a view that outputs a table like this:

| Classroom | Number of lessons |
| --- | --- |
| Leicester Square | 5 |
| Piccadilly Circus | 8 |
| London Bridge | 0 |

So, there are five lesson nodes that reference the "Leicester Square" classroom (all the classrooms are named after places in London), 8 that reference the classroom named Piccadilly Circus, and 0 lesson nodes referencing London Bridge.

Is there a way to achieve this in views?

I'm playing around with relationships and aggregation but I can't get it to work.

# Answer
> 2 votes
Silly mistake. I had the relationship the wrong way round. Now it's working perfectly. These are the steps:

1.) Create a relationship: *Content **using** field\_classroom* (not *content referenced from field\_classroom*)

2.) Enable aggregation

3.) Add a field: field\_classroom

4.) Use the relationship

5.) Set aggregation on the field to COUNT

And it works!

---
Tags: views
---


title: How to use $token_service->replace?

text:
# Question
Title: How to use $token_service->replace?
I am using following code to replace current-user:email token.

```
 $pattern = '[current-user:mail]';
 $output = $token_service->replace($pattern, array('current-user' => $account), array(
            'clear' => TRUE,
            'callback' => xyz_function($pattern_array),
          ));

```

In the callback function i am doing

```
foreach ($replacements as $token => $value) {
  $replacements[$token] = _cleanstring($value);
}

```

I guess i am passing wrong array('current-user' =\> $account) argument. Where am i doing wrong?

# Answer
Tokens for the current user `[current-user:*]` don't need any data. Leave the array empty.

What you might referring to are tokens for any user `[user:*]`. They need an account as parameter 'user'.
> 1 votes

# Answer
Instead of token replace use -\> normal placeholder in t function D8

```
eg: $body = t("@username is my Name.", ['@username' => "Jyoti"]);

```

Output will be "Jyoti is my Name."
> 0 votes

---
Tags: 8, tokens
---


# Question
Title: Uploading an image with JSON:API; getting "Access denied"
I'm attempting to upload an image with JSON:API.

I have added an **Image** field (not a media field) to the user entity.

In Postman, I get a session cookie for testing.

Then, in accordance with Flow 2 in the JSON:API upload file documentation, I configure my request:

I added image data as a binary to the request body.

However, when I send the request, I get the following error:

```
    "title": "Forbidden",
    "status": "403",
    "detail": "The current user is not permitted to upload a file for this field. The 'administer users' permission is required.",

```

I don't know why it is saying I need `administer users` permission.

When I log in as the same (authenticated, non-admin) user and then go to the user edit page, I can edit the image field (save a new image, remove the existing image) without any problem. So why am I getting a permissions error in JSON:API? I thought JSON:API permissions were supposed to be exactly the same as in the Drupal UI.

# Answer
I wasn't able to get it working with Flow 2 in the docs; I kept getting a `Needs "administer users" permission` error (which is incorrect; users have permission to edit the field).

So instead, I used Flow 1:

```
POST /jsonapi/node/article/{uuid}/field_image HTTP/1.1
Content-Type: application/octet-stream
Accept: application/vnd.api+json
Content-Disposition: file; filename="filename.jpg"

[… binary file data …]

```

This requires the user to already be created, which is OK for my user case, but may not be the case for everyone.

Additional notes

* I had to turn off the popular Filefield Paths module for my image field because it breaks JSON:API.
* I had to uncheck **Alt field required** in the image field settings; if you leave the alt field required, you get this nasty error:

```
  "detail": "The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: Drupal\\Core\\Cache\\CacheableResponse.",

```
> 0 votes

---
Tags: services
---


# Question
Title: How do I create nodes with comments enabled using drush?
I have a drupal 9.1.5 site with a custom node type. I can create test content for it using drush by running;

`drush genc 1 --bundles=mynode --authors=test`

However, half of the content has comments disabled. I think what is happening is that drush is randomly settings the *COMMENT SETTINGS* field:

Drush has a `--skip-fields` parameter, but I don't know what to put in there. I've tried a bunch of different things like `field_mynode_comment` (the machine name of the field) but none seemed to work. I'm basically guessing.

How can I use drush to create nodes that always allow comments?

# Answer
This is more of a workaround;

I can coerce all nodes to enable comments by running a query like this:

```
drush sql-query "UPDATE node__field_mynode_comment SET field_mynode_comment_status = 2"

```

I had a look at the database and found the `node__field_mynode_comment` table, which has a `field_mynode_comment_status` column. I found that the nodes with that column set to `2` had comments enabled, so I ran the above query to set it for all nodes, and now all nodes have comments enabled.

Incidentally I also tried creating the nodes with that field name ignored (`--skip-fields=field_mynode_comment_status`) but that didn't seem to have any effect.
> 1 votes

---
Tags: drush
---


# Question
Title: hook_views_pre_render -> how to access variables
I have a view of teasers, and would like to check the status of each node. Using hook\_views\_pre\_render (in the template.php file of the theme), I can access:

```
$view->style_plugin->row_plugin

```

Which gives me the output below (only first few lines printed, using debug):

```
entity_views_plugin_row_entity_view::__set_state(array(
 'entity_type' => 'node',
 'entities' =>
 array (
  0 =>
  stdClass::__set_state(array(
     'vid' => '19',
     'uid' => '1',
     'title' => 'My Node Title',
     'log' => '',
     'status' => '0',
     'comment' => '1',
     'promote' => '0',

```

However, I can't figure out how to access the status variable.

```
debug($view->style_plugin->row_plugin->entities());

```

produces a white screen, any variation that I tried either returned NULL or a white screen.

Any help greatly appreciated.

# Answer
Install the Devel module if you haven't already and use `dpm($view);` to see the structure of the view, then you can drill down to the part of the variable that you wish to inspect.

The devel module will print the result of your `dpm()` in the message area as long as there are no syntax errors in your module crashing the site.

I have found `drush cc all` (Linux command line tool) to be useful in finding syntax errors though I suspect there is a better way.
> 0 votes

# Answer
`entities` isn't a method, so you cannot use `$view->style_plugin->row_plugin->entities()`.

What shown in the question is the output of `var_dump()` for the instance of a class, in this case `entity_views_plugin_row_entity_view`. The `$entities` property is protected, so it cannot be directly accessed from outside the class.

```
class entity_views_plugin_row_entity_view extends views_plugin_row {

  protected $entity_type, $entities;

  // …

}

```

`entity_views_plugin_row_entity_view::get_value()` returns values from that property. More exactly, it returns the entity for the view row associated with that class instance.

In your case, you should use `$view->style_plugin->row_plugin->get_value(NULL)`.
> 0 votes

---
Tags: views
---


# Question
Title: Why is theme not used in my remote site when it is in my local site?
I just installed Drupal 8.9.13 locally with Composer: `composer create-project drupal/recommended-project:8.9.13 mySite`.
Then I copied all files to remote site.
Then I launched Drupal installer: `http://path/to/site/core/install.php` on both local and remote sites in parallel.
The process went to its end with no problem but (there is a but) the remote site doesn't look very nice...

Local site:

Remote site:

Any idea of what went wrong?

# Answer
2 options:

1. Your production server might not handle a `.htaccess` file well that lives in `sites/default/files`.

Or

2. can't write to the `tmp` folder.

To check this out: first visit `admin/reports/dblog` and read the errors.

Second: ***note*** clear browser history first!

1. you can comment out all lines of code in the `.htaccess` file.
2. Upload file to your production server.
3. visit `admin/config/development/performance`
4. click `clear all caches`
> 0 votes

# Answer
Drupal must have access to modify files directory (it needs write permission) `/sites/default/files` so you'd better to change owner and group of this directory.

if you have ssh access use these commands:

`cd WEBROOT/sites/default`

`sudo chown www-data:www-data files`

and then

`sudo chmod 755 files`

else you can use cpannel or directadmin or etc to change this directory owner and permissions.
> 0 votes

---
Tags: 8
---


title: How do you upload an image via jsonapi?

text:
# Question
Title: How do you upload an image via jsonapi?
The documentation is vague: https://www.drupal.org/docs/8/modules/json-api/working-with-files-post

I am trying to upload an image following the sample code given for uploading a "document" on above page.

Simplified example:
Given an admin user "bot" and a base-64 encoded qr code.

I create the json payload following the example in the documentation

```
{
  "data": {
      "type": "file--image",
      "attributes:": {
          "title": "QR Code",
          "uri": "public://folder/qr-code.png",
          "data": "iVBORw0KGgoAAAANSUhEUgAAAG8AAABvAQMAAADYCwwjAAAABlBMVEUAAAD///+l2Z/dAAAAAnRSTlP//8i138cAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAEsSURBVDiN1dS7jcMwDABQGirU5RYQoDXUaSV7AX8WsFdSxzUCeAGrUyGYRzuJ79KIKoIDTnCRVyj8gBTQ24H/wQ1gQNNCBrAiI+UOafRmoAqG48eSTKur2Gq4+VzJ3q/x190SKbfOLpivJAvkejs0/F3lF8hnh9yFn8YWuIEBR7tXs6ugJkIVEzSPrIqMBF94By72DFTmpteJVAxXoBI5RK9Nz4lpmbtTCx2FdGdWZRLmHuzo1/m8K5DWKeWB6001NEOg0dHrbombt9wfHu8GrcgYeEjuN00Lkky0m1eEdkoVTIa3rHfQBCuST6TzH0DmMbGBo/AukEjehSHkLtmYrExeyWNioXmWL1EDd34GW0XPneQ3h2Tym0OKh/Y5sUU+9hfcOmqZf/YCf4zfOAszBtzxUOsAAAAASUVORK5CYII="
      }
  }
}

```

Which translates into this curl command

```
curl \
--user bot:bot \
--header 'Accept: application/vnd.api+json' \
--header 'Content-type: application/vnd.api+json' \
--request POST http://drupalvm.test/jsonapi/file/image \
--data-binary '{"data": {"type": "file--image", "attributes:": {"title": "QR Code", "uri": "public://folder/qr-code.png", "data": "iVBORw0KGgoAAAANSUhEUgAAAG8AAABvAQMAAADYCwwjAAAABlBMVEUAAAD///+l2Z/dAAAAAnRSTlP//8i138cAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAEsSURBVDiN1dS7jcMwDABQGirU5RYQoDXUaSV7AX8WsFdSxzUCeAGrUyGYRzuJ79KIKoIDTnCRVyj8gBTQ24H/wQ1gQNNCBrAiI+UOafRmoAqG48eSTKur2Gq4+VzJ3q/x190SKbfOLpivJAvkejs0/F3lF8hnh9yFn8YWuIEBR7tXs6ugJkIVEzSPrIqMBF94By72DFTmpteJVAxXoBI5RK9Nz4lpmbtTCx2FdGdWZRLmHuzo1/m8K5DWKeWB6001NEOg0dHrbombt9wfHu8GrcgYeEjuN00Lkky0m1eEdkoVTIa3rHfQBCuST6TzH0DmMbGBo/AukEjehSHkLtmYrExeyWNioXmWL1EDd34GW0XPneQ3h2Tym0OKh/Y5sUU+9hfcOmqZf/YCf4zfOAszBtzxUOsAAAAASUVORK5CYII="}}}'

```

This results in an error:

```
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'uri' cannot be null

```

**What am I doing wrong?**

I am using a local Drupal instance generated by https://github.com/geerlingguy/drupal-vm#quick-start-guide on Mac Sierra 10.12.6

It is

`Drupal core 8.5.3`

Includes: Automated Cron, BigPipe, Block, Breakpoint, CKEditor, Color, Comment, Configuration Manager, Contact, Contextual Links, Custom Block, Custom Menu Links, Database Logging, Datetime, Field, Field UI, File, Filter, HTTP Basic Authentication, Help, History, Image, Internal Dynamic Page Cache, Internal Page Cache, Link, Menu UI, Node, Options, Path, Quick Edit, RDF, Search, Serialization, Shortcut, System, Taxonomy, Text, Text Editor, Toolbar, Tour, Update Manager, User, Views, Views UI

With the following Modules

* `File Entity (fieldable files) 8.x-2.0-beta6`
* `JSON API 8.x-1.18`
* `JSON API File 8.x-1.1`
* `Token 8.x-1.3`

(And with the core `HTTP Basic Authentication` module enabled)

# Answer
> 2 votes
Here is a javaScript version that may help after alot of trial and error I could only get "entity/file?\_format=hal\_json" to work aka "file\_entity" module.

the following "bace64" = iVBORw0KGgoAAAANSUhEUgAAAG8AAABvA.....

```
uploadDrupalImage(bace64) {
  // Could only get hal_json to work.
  var dataToPost = '{"_links": {"type": {"href": ' + JSON.stringify(this.baceUrl + 'rest/type/file/image') + '}},"filename": [{"value": "' + this.state.file.name + '"}],"data":[{"value": "' + bace64 + '"}]}';
  var url = this.baceUrl + 'entity/file?_format=hal_json';
  fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/hal+json',
      'X-CSRF-Token': this.state.csrf_token,
      'Authorization': this.state.basicAuth,
    },
    body: dataToPost
  }).then(response => response.json()).then(data => {
    if (data) {
      this.setState({uploadedFile: data});
      if (data.fid) {
        //console.log(data.fid[0].value);
        this.setState({fid: data.fid[0].value});
      }
    }
  }).catch(err => console.error(err.toString()));
  return false;
}

```

taken from (when i was just learning react so be kind lol) https://github.com/taggartj/Drupa\_react\_REST\_examples/blob/master/src/components/drupal/DrupalCreateArticleWithImageBasicAuth.js

# Answer
> 1 votes
I found another example with axios buried in the issue queue:

Credit to Hygglo on drupal.org, but I'm reposting here because having this example saved me from some frustrating debugging, and hopefully it can help more people:

```
onDrop = (acceptedFiles, rejectedFiles) => {
        let file = acceptedFiles[0];

        let filename = file.name;

        var reader = new FileReader();
        reader.readAsArrayBuffer(file);

        reader.onabort = () => console.log('file reading was aborted')
        reader.onerror = () => console.log('file reading has failed')
        reader.onload = () => {

            const arrayStr = reader.result;

            axios.post('/jsonapi/node/application/field_resume',
                arrayStr
                , {
                    headers: {
                        "Content-Type": "application/octet-stream",
                        "Accept": "application/vnd.api+json",
                        "Content-Disposition": 'file; filename="' + filename + '"',
                        'X-CSRF-Token': "HDel-LIL4o709vjgAW6N82Me5wiJ1ZHu_7KHaXN19Vo",
                    }
                }
            )
                .then((response) => {
                    console.log(response);

                })
                .catch(function (error) {
                    console.log(error);

                }.bind(this));
        }

    };

```

---
Tags: files, 8
---


# Question
Title: Any idea why view->field is empty when executing a view returning user emails?
We are using Business Rules to execute a view (users) that returns a list of email addresses. It works fine when rule is triggered by admin, but does not work when triggered by other users. In debugging it I found the following:

1. as both users the view returns the correct result rows, ie. $view-\>result is identical for both users.
2. as admin the view object contains a list of the fields which business\_rules uses, ie. $fields = $view-\>field is an array keyed on 'mail';
3. as any other user $view-\>field is empty UNLESS I turn on administer users permissions for that user's role!

I am thinking that in views a permission to view the mail field is being checked when the 'fields' are populated into the view object. But, oddly enough that permission does not effect the view result as mentioned in #1.

Any thoughts on how to debug this further?

# Answer
If anyone else sees this it is because view does a checkAccess before adding the field during preExecute. Since it is the mail field there is no other way to allow access to that field unless you give administer users. But, there is a patch coming out that introduces a mail field access permission.

https://drupal.org/project/drupal/issues/2799049

With patch and permission set everything works.
> 2 votes

---
Tags: 8, views
---


# Question
Title: How do I configure Content Security Policy for base64 images?
I'm using the Content Security Policy module and I placed restrictions on **img-src**.

Set to `Self`.

**Additional sources**:

```
https://www.google-analytics.com https://ssl.gstatic.com https://www.gstatic.com https://www.googletagmanager.com

```

However, my logs are filled with messages like this:

> \[Report Only\] Refused to load the image 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAD1JREFUeNpiYGBgOADE%2F3Hgw0DM4IRHgSsDFOzFInmMAQnY49ONzZRjDFiADT7dMLALiE8y4AGW6LoBAgwAuIkf%2F%2FB7O9sAAAAASUVORK5CYII%3D' because it violates the following Content Security Policy directive: "img-src 'self' https://www.google-analytics.com https://ssl.gstatic.com https://www.gstatic.com https://www.googletagmanager.com".

How do I allow the base64 images provided by Drupal (jsonapi in this case)?

# Answer
Based on this Stack Overflow answer, you need to add `data:` to **Additional Sources**:

```
data: https://www.google-analytics.com https://ssl.gstatic.com https://www.gstatic.com https://www.googletagmanager.com

```
> 0 votes

---
Tags: media
---


# Question
Title: Generate classname from variable in template
In the template file for a view with grouped rows, I would like to add the group title as class name, but the rendered class name from the title variable is just *_* on every group. This is the generated HTML markup for the group whose title is *1*.

```
<h3 class="views-group group-_">1</h3>

```

What's wrong here?

This is the template file content.

```
{#
/**
* @file
* Default theme implementation to display a view of unformatted rows.
*
* Available variables:
* - title: The title of this group of rows. May be empty.
* - rows: A list of the view's row items.
*   - attributes: The row's HTML attributes.
*   - content: The row's content.
* - view: The view object.
* - default_row_class: A flag indicating whether default classes should be
*   used on rows.
*
* @see template_preprocess_views_view_unformatted()
*
* @ingroup themeable
*/
#}
{% if title %}
  {%
    set classes = [
      'views-group',
      'group-' ~ title|clean_class,
    ]
  %}
  <h3{{ content_attributes.addClass(classes) }}>{{ title }}</h3>
{% endif %}
{% for row in rows %}
  {%
    set row_classes = [
      default_row_class ? 'views-row',
    ]
  %}
  <div{{ row.attributes.addClass(row_classes) }}>
    {{- row.content -}}
  </div>
{% endfor %}

```

# Answer
Valid CSS identifiers (for example, element names, classes, and IDs in selectors) cannot start with a digit, or a hyphen followed by a digit. `Html::cleanCssIdentifier()`, which is called when a CSS identifier is created from a string, contains the following code.

```
  // Valid characters in a CSS identifier are:
  // - the hyphen (U+002D)
  // - a-z (U+0030 - U+0039)
  // - A-Z (U+0041 - U+005A)
  // - the underscore (U+005F)
  // - 0-9 (U+0061 - U+007A)
  // - ISO 10646 characters U+00A1 and higher
  // We strip out any character not in the above list.
  $identifier = preg_replace('/[^\\x{002D}\\x{0030}-\\x{0039}\\x{0041}-\\x{005A}\\x{005F}\\x{0061}-\\x{007A}\\x{00A1}-\\x{FFFF}]/u', '', $identifier);

  // Identifiers cannot start with a digit, two hyphens, or a hyphen followed by a digit.
  $identifier = preg_replace([
    '/^[0-9]/',
    '/^(-[0-9])|^(--)/',
  ], [
    '_',
    '__',
  ], $identifier);

```

As a digit is only replaced when it's the first character, or the second character when the first character is a hyphen, it's enough to first concatenate a string that is an acceptable CSS identifier, as in the following code.

```
{% if title %}
  {%
    set classes = [
      'views-group',
      ('group-' ~ title)|clean_class,
    ]
  %}
  <h3{{ content_attributes.addClass(classes) }}>{{ title }}</h3>
{% endif %}
{% for row in rows %}
  {%
    set row_classes = [
      default_row_class ? 'views-row',
    ]
  %}
  <div{{ row.attributes.addClass(row_classes) }}>
    {{- row.content -}}
  </div>
{% endfor %}

```

The only difference with the code shown in the question is using `('group-' ~ title)|clean_class`, instead of `'group-' ~ title|clean_class`. The parentheses are necessary because `|` takes precedence over `~`.
That is the only change needed to avoid that the first digit in the node title is replaced with an underscore. There is no need to change the code to add a single CSS class instead of two CSS classes.
> 1 votes

# Answer
Now I found it out myself: clean\_class replaced all my numbers by an underscore! So in case the title consists of a number only, it is stripped to a single underscore. So an updated template file takes care of this and could look similar to this one:

```
      {#
  /**
   * @file
   * Default theme implementation to display a view of unformatted rows.
   *
   * Available variables:
   * - title: The title of this group of rows. May be empty.
   * - rows: A list of the view's row items.
   *   - attributes: The row's HTML attributes.
   *   - content: The row's content.
   * - view: The view object.
   * - default_row_class: A flag indicating whether default classes should be
   *   used on rows.
   *
   * @see template_preprocess_views_view_unformatted()
   *
   * @ingroup themeable
   */
  #}
  {% if title %}
    {%
        set class = 'column-' ~ title
    %}
    <div{{ content_attributes.addClass(class|clean_class) }}>
  {% endif %}

  {% for row in rows %}
    {%
      set row_classes = [
        default_row_class ? 'views-row',
      ]
    %}
    <div{{ row.attributes.addClass(row_classes) }}>
      {{- row.content -}}
    </div>
  {% endfor %}

  {% if title %}
    </div>
  {% endif %}

```
> 0 votes

---
Tags: 8, theming
---


# Question
Title: Command "generate:module" is not a valid command name
I have this problem when I run command `drupal generate:module`. I don't know why, despite everything I did was suggested on the documentation for Drupal Console.

I don't see all the possible commands, when I run `drupal list`.

```
Available commands:
  about                      Displays basic information about Drupal Console project
  chain                      Chain command execution
  check                      System requirement checker
  exec                       Execute an external command.
  help                       Displays help for a command
  init                       Copy configuration files.
  list                       Lists all available commands
 debug
  debug:chain (dch)          List available chain files.
  debug:settings (dse)       List user Drupal Console settings.
  debug:site (dsi)           List all known local and remote sites.
 develop
  develop:contribute         Download Drupal + Drupal Console to contribute.
 generate
  generate:site:alias (gsa)  Generates a site alias.
 quick
  quick:start                Download, install and serve a new Drupal project
 settings
  settings:set               Change a specific setting value in DrupalConsole config file
 site
  site:new                   Download a new Drupal project

```

# Answer
> 1 votes
I have faced the same problem this works 100 % :

1. open the shell and `cd to projectFolder`
2. run this command :

```
   composer require drupal/console:~1.0 --prefer-dist --optimize-autoloader

```
3. then run this command :

```
   composer update drupal/console --with-dependencies

```
4. run `drupal list` command again, and you'll find the list of all commands.

**! this steps must be repeated with each project.**

# Answer
> 0 votes
I had the same problem, it was resolved when I deleted extra blank composer.json file present inside "web" directory. Not sure how it got created but the issue got resolved when I deleted non-required composer.json

**Folder Structure with Issue** /path/to/site/dev

config/ vendor/ web/ composer.json composer.lock web/composer.json

**Proposed fix** /path/to/site/dev

config/ web/ vendor/ composer.json composer.lock

I got answer from below link, reposting if it helps someone

https://github.com/hechoendrupal/drupal-console/issues/3925

---
Tags: console
---


title: How do I migrate a view?

text:
# Question
Title: How do I migrate a view?
After releasing Drupal8-beta-15 we decide to migrate some of sites to Drupal8. I read this article about how to migrate to Drupal 8, But I have some problem with it, I know when I want use a `views` in another website ( in Drupal 7) I can export/import it or also use Features but now I don't know how I can migrate my views from Drupal 7 to Drupal 8.

How can I migrate a view from Drupal 7 to Drupal 8?

# Answer
You can do it using this module :

Views D8 Upgrade

> Tentative upgrade instructions (these may change):
>
> Before upgrading your site to Drupal 8, update to the latest 7.x-3.x release of Views on your Drupal 7 site.
>
> **Back up your data and place your site in maintenance mode.** Install the 7.x-1.x release of this module.
>
> Navigate to admin/build/views\_d8\_upgrade and click "Perform upgrade."
> warning: This will copy your Views data and uninstall the Drupal 7 Views module.
>
> Follow the Drupal core instructions for upgrading to Drupal 8, including updating this module to its D8 version. This will convert your old Views data (still saved in the database) to Drupal 8 Views.
> 2 votes

# Answer
There is not currently (June 2016) an upgrade path for Views to Drupal 8. If one is created, it will not be available until D8.2 is released.
> 1 votes

# Answer
You can migrate a views from drupal 7 to drupal 8 or Drupal 9, using this module :

https://www.drupal.org/project/views\_migration
> 1 votes

# Answer
You can get latest release by cloning, using git feature: git instructions for this particular module here!
> 0 votes

---
Tags: views, 8, migrations
---


# Question
Title: Cant show Commerce Products in View on Taxonomy Term page
My Commerce Products (not Product Displays) have a term reference field. On a taxonomy term page I want to show all the products tagged with that term.

If I create a view to show prodcuts (which I would attach as a block), I cant seem to use the term ID from the contextual filters to limit the results.

If I create a view of terms, then I cant find the relationship and fields to show the products.

Am I missing something or is this how Commerce Products work? Are they not available in Views the same way that nodes with the same term field would be?

# Answer
This isn't an official source, but it might help you.

1. Don't attach a block on your taxonomy page. Instead, create the View as a page and set the URL (under path) to override the the taxonomy term page (e.g. taxonomy/term/%).
2. Under contextual filter use : Content: Has taxonomy term ID
3. For the filters, use the settings in the screen shot (in the screenshot, my taxonomy terms belong to a vocabulary called Shop Categories).

Hope that helps!
> 2 votes

# Answer
I think you need to add relationship first then you can apply contextual filters based on term id.

there is no such issue having commerce product instead of nodes as d7 is entity based and both are entity to it.
> 0 votes

# Answer
> Drupal core taxonomy module index only for node entity. it doesn't maintain other entities.

https://www.drupal.org/project/commerce\_product\_taxonomy\_filter module supports more than one taxonomy\_term reference field in commerce product entity
> 0 votes

# Answer
The taxonomy of the products are usually product attributes that need to be used in the reference of the product display. Otherwise you might need to add the same attribute to the product display
> -1 votes

---
Tags: 7, views, commerce
---


# Question
Title: Is there any way to clear the cache with specific cid?
I set some data in cache using `cache_set($cache_id, $temp_data, 'cache', CACHE_TEMPORARY);` from a custom module. It's cleared when I clear all the cache.

Is there any way I can clear that specific cached data using its ID?

# Answer
> 1 votes
Despite the name, `cache_clear_all()` doesn't necessarily clear all the cache; it does so only when no parameter is passed to the function.

Usually Drupal core uses `cache_clear_all()` to clear all the cache. In some cases, it uses that function to clear a specific cache item, which is what Drupal core does in `variable_set()`, for example.

```
function variable_set($name, $value) {
  global $conf;
  db_merge('variable')->key(array('name' => $name))
    ->fields(array('value' => serialize($value)))
    ->execute();
  cache_clear_all('variables', 'cache_bootstrap');
  $conf[$name] = $value;
}

```

In that code, the cache ID of the deleted item is *variables*, which is contained in the *cache\_bootstrap* cache bin.

As side note, `cache_clear_all()` could be also used to delete all the cache items whose IDs start with the string passed as first argument. For example, `cache_clear_all('mymodule_', 'cache', TRUE)` would delete the cache items whose cache IDs are *mymodule\_cached\_data* or *mymodule\_long\_calculus\_result*, for example. It won't delete a cache item whose ID is *user\_cached\_data*, for example.

# Answer
> 0 votes
You can pass a `cid` to cache\_clear\_all() to clear a specific bin.

---
Tags: 7, caching
---


# Question
Title: How to use the Vanilla JS version of Drupal Once
Once again i am having a problem with the JS called more than once. the code here transform the select/options of the exposed filters to ul/li. The problem is that the

> console.log("enter init")

is called many times , when i would need it to be called only once on load :

```
(function($, Drupal) {
  /**
   *
   * Retourne la valeur correspondante du localstorage
   *
   * @param {string} key
   * @return {string}
   */
  function getFromLocalStorage(key) {
    if (localStorage.getItem(key) === null) {
      localStorage.setItem(key, "All");
    }
    return localStorage.getItem(key);
  }

  const variables = {
    selectElement /** @type={HTMLElement} */: document.querySelector(
      ".views-exposed-form .form-select"
    ),
    optionElements /** @type={HTMLCollection} */: document.querySelector(
      ".views-exposed-form .form-select"
    ).children,
    inputElement /** @type={HTMLElement} */: document.querySelector(
      ".views-exposed-form .form-submit"
    ),
    selectedFilter: getFromLocalStorage("data-value"),
    ul: document.createElement("ul")
  };

  /**
   * Stocke le li clické
   *
   * @param {Event } e
   * @return {void}
   */
  function setToLocalStorageOnClick(e) {
    variables.selectedFilter = e.target.dataset.value;
    localStorage.setItem("data-value", variables.selectedFilter);
  }

  /**
   * Convertit select/option to ul/li
   * Affranchit de l'usage du submit bouton
   * Mémoire des clicks
   *
   * @return {void}
   */
  function selectToUlFilter() {
    variables.inputElement.classList.add("visually-hidden");
    variables.selectElement.hidden = true;
    variables.ul.setAttribute("class", "selectlist");
    Array.from(variables.optionElements).forEach(item => {
      const li = document.createElement("li");
      li.setAttribute("class", "selectlist-option");
      li.dataset.value = item.value;
      li.innerHTML = item.innerHTML;
      variables.ul.append(li);
    });
    variables.selectElement.after(variables.ul);
  }

  /**
   * Transpose le li sélectionné au select/option avant le submit
   *
   * @return {void}
   */
  function transposeModifToSelect() {
    Array.from(variables.optionElements).forEach(item => {
      if (item.value === variables.selectedFilter) {
        item.setAttribute("selected", "selected");
      } else {
        item.removeAttribute("selected");
      }
    });
  }

  /**
   * Ajout d'un attribut à l'element sélectionné pour le css
   *
   * @return {void}
   */
  function addSelectedAttribute() {
    document.querySelector(
      `li[data-value="${variables.selectedFilter}"]`
    ).dataset.selected = "true";
  }

  /**
   * Default controller appelé au chargement de la page
   *
   * @return {void}
   */
  function init() {
    console.log(drupalSettings.amu_bef_selectors);
    console.log("enter init");

    selectToUlFilter();
    addSelectedAttribute();
    transposeModifToSelect();

    variables.inputElement.click();

    const newUl = document.querySelector(".selectlist");
    const liDefaultEN = document.querySelector(
      '.lang--en li[data-value="All"]'
    );
    if (liDefaultEN) {
      liDefaultEN.innerHTML("All");
    }
  }

  Drupal.behaviors.bef = {
    attach(newUl) {
      document.addEventListener("DOMContentLoaded", init(), { once: true });

      newUl.addEventListener(
        "click",
        e => {
          setToLocalStorageOnClick(e);
          transposeModifToSelect();
          variables.inputElement.click();
        },
        { once: true }
      );
    }
  };
})(jQuery, Drupal);

```

EDIT:

* if (!initialised) added
* what happen then is eventlistener is not working on : variables.inputElement.click() : error Form submission canceled because the form is not connected.

```
(function($, Drupal) {
/**
 *
 * Retourne la valeur correspondante du localstorage
 *
 * @param {string} key
 * @return {string}
 */
function getFromLocalStorage(key) {
  if (localStorage.getItem(key) === null) {
    localStorage.setItem(key, "All");
  }
  return localStorage.getItem(key);
}

const variables = {
  selectElement /** @type={HTMLElement} */: document.querySelector(
    ".views-exposed-form .form-select"
  ),
  optionElements /** @type={HTMLCollection} */: document.querySelector(
    ".views-exposed-form .form-select"
  ).children,
  inputElement /** @type={HTMLElement} */: document.querySelector(
    ".views-exposed-form .form-submit"
  ),
  selectedFilter: getFromLocalStorage("data-value"),
  ul: document.createElement("ul")
};

/**
 * Stocke le li clické
 *
 * @param {Event } e
 * @return {void}
 */
function setToLocalStorageOnClick(e) {
  variables.selectedFilter = e.target.dataset.value;
  localStorage.setItem("data-value", variables.selectedFilter);
}

/**
 * Convertit select/option to ul/li
 * Affranchit de l'usage du submit bouton
 * Mémoire des clicks
 *
 * @return {void}
 */
function selectToUlFilter() {
  console.log("enter selectToul");
  // variables.inputElement.classList.add("visually-hidden");
  // variables.selectElement.hidden = true;
  variables.ul.setAttribute("class", "selectlist");
  Array.from(variables.optionElements).forEach(item => {
    const li = document.createElement("li");
    li.setAttribute("class", "selectlist-option");
    li.dataset.value = item.value;
    li.innerHTML = item.innerHTML;
    variables.ul.append(li);
  });
  variables.selectElement.after(variables.ul);
}

/**
 * Transpose le li sélectionné au select/option avant le submit
 *
 * @return {void}
 */
function transposeModifToSelect() {
  Array.from(variables.optionElements).forEach(item => {
    if (item.value === variables.selectedFilter) {
      item.setAttribute("selected", "selected");
    } else {
      item.removeAttribute("selected");
    }
  });
}

/**
 * Ajout d'un attribut à l'element sélectionné pour le css
 *
 * @return {void}
 */
function addSelectedAttribute() {
  const selectedLi = document.querySelector(
    `li[data-value="${variables.selectedFilter}"]`
  );
  if (selectedLi !== null) {
    selectedLi.dataset.selected = "true";
  }
}

/**
 * Default controller appelé au chargement de la page
 *
 * @return {void}
 */
function init() {
  console.log(drupalSettings.amu_bef_selectors);
  console.log("enter init");

  selectToUlFilter();
  addSelectedAttribute();
  transposeModifToSelect();
  // variables.inputElement.click();

  const liDefaultEN = document.querySelector(
    '.lang--en li[data-value="All"]'
  );
  if (liDefaultEN) {
    liDefaultEN.innerHTML("All");
  }
}

const form = document.querySelector(".views-exposed-form");
form.addEventListener("click", e => {
  setToLocalStorageOnClick(e);
  transposeModifToSelect();
  // works but no ajax
  form.submit();
  // when this does not work : Form submission canceled because the form is not connected
  // variables.inputElement.click();
});

let initialised = false;
Drupal.behaviors.bef = {
  attach() {
    if (!initialised) {
      initialised = true;
      init();
    }
  }
};

```

})(jQuery, Drupal);

# Answer
There is now a vanilla version of Drupal once (https://www.drupal.org/project/once) and I've been using it successfully on a Drupal 9 project with vanilla JS in my theme. You can look at the change log here and the original issue that was the impetus for converting to vanilla. The source file in the project from which you can build sheds some insight on its use.

In your code above, I see you are using `document.querySelector` and you'll want to pay attention to that as I found a bug as noted here. "Error when context.querySelector() doesn't find an element on the page".

The documentation says:

```
 // once methods always return an array, to simplify the use with a single
 *   // element use destructuring or the shift method.
 *   const [myElement] = once('my-once-id', document.body);
 *   const myElement = once('my-once-id', document.body).shift();

```

So in the end, it's probably best for a single element to use an id with the patch linked to herein rather than `document.querySelector`. For example, I have a single element I want to target so I do it like this:

```
const glossary_view_conditions = once('glossary-view-once', '#views-exposed-form-scs-conditions-block');

```

For multiple elements being targeted, `querySelectorAll` works great. You'll also need your main function to target once, beginning and end. So an example would be:

```
(function (Drupal, once) {
  Drupal.behaviors.customCheckboxes = {
    attach(context) {
      // Find checkboxes, add markup.
      let outer_checkboxes = once('yay-only-once', context.querySelectorAll('.js-form-type-checkbox'));
      // Loop through each matched element.
      for (let i = 0; i < outer_checkboxes.length; i++) {
        // This is similar to jquery $(this).find('input.form-checkbox).
        let inner_inputs = outer_checkboxes[i].querySelectorAll("input.form-checkbox");
        // This is similar to jquery .after().
        // Since querySelectorAll returns a collection, we target with [0].
        inner_inputs[0].insertAdjacentHTML('afterend', '<span class="checkbox-toggle"><span class="checkbox-toggle__inner"></span></span>');
      }
    }
  };
}(Drupal, once));

```
> 5 votes

---
Tags: javascript, 9
---


# Question
Title: How do I delete all book page nodes, book outline, and uninstall book module
I would like to remove a book, its contents, its outline, and uninstall the book module itself.

I deleted all the "Book page" content type nodes. I then deleted the one book listed under: admin/structure/book

However, when I try and uninstall the module using Drush I get the message:

"To uninstall Book, delete all content that is part of a book"

I'm assuming this is the outline data on non "Book page" nodes that I missed, but there's nothing there in the Admin UI to tell me which ones they are. The UI says "No books available."

There is a module that addresses the issue of deleting book pages and their outlines in this answer here in Drupal 7.

Is there a way to easily find and delete that book content and uninstall the module in Drupal 8?

# Answer
> 1 votes
The problem was that there were some non "Book page" nodes that still had Book outlines (after I had deleted the Book and all Book page nodes through the Admin).

I could get a list of the NIDs of these problematic, "trace" outlines through a database query:

```
drush sqlq "select nid from book"

```

However, I couldn't access the nodes. I got a message:

"The website encountered an unexpected error. Please try again later."

So I rolled back/reinstalled the Book content and then deleted the outlines of the problematic nodes through the UI at:

/node/1234/outline/remove

Fortunately, there weren't too many of them.

If I was doing this again I would first query the database just to see if there many non-Book Page nodes with Book outlines:

```
drush sqlq "select * from node, book where book.nid = node.nid and not node.type='book'"

```

After deleting these outlines through the UI, I was able to uninstall the Book module through Drush.

# Answer
> 1 votes
It sounds like you have orphaned book content. You can go look for any nodes of type book page at `/admin/content`, and delete them all. Also, check your configuration of the book module to see if any other content types are enabled as book content. You may have to determine which nodes of those content types have been created as book pages but not assigned to an outline.

---
Tags: 8, nodes
---


# Question
Title: Is 'order completed' a safe way to assume that order is paid in full?
I am working on a client's site. I have a requirement that when a user buys a product, a specific role should be assigned to the user. For this, I have used 'business rules' module.
**Business Rules**
Reacts on event: After updating Entity
Target Entity Type: Order
Target Bundle: Default
**Condition**
Type: Data Comparison
Target Entity Type: Order
Target Bundle: Default
Field: state: State\[state\]
Data to compare: Current value
Operator: =
Value to compare: completed
**Items to execute if condition succeed**
Action: Add 'One year subscriber' role to user

My question is, Is this the correct way to identify that the product is purchased and order is paid in full?
That is, if order status is completed then is it safe to assume that the product is purchased and order is paid in full?

# Answer
No. As with Commerce 1.x, we have a specific event in Commerce 2.x that is only triggered the first time an order is observed to be paid in full. It's defined in OrderEvents.php:

```
  /**
   * Name of the event fired after the order has been fully paid.
   *
   * Guaranteed to only fire once, when the order balance reaches zero.
   * Subsequent changes to the balance won't redispatch the event (e.g. in case
   * of a refund followed by an additional payment).
   *
   * Fired before the order is saved.
   *
   * @Event
   *
   * @see \Drupal\commerce_order\OrderInterface::getBalance()
   * @see \Drupal\commerce_order\Event\OrderEvent
   */
  const ORDER_PAID = 'commerce_order.order.paid';

```
> 2 votes

---
Tags: 8, commerce
---


title: Non-empty string as route parameter

text:
# Question
Title: Non-empty string as route parameter
I'm creating a search results page using the Search API. I want to set an url like this:

```
    /search/{text}

```

How should i set up my route? It must accept any combination of characters, including non-ascii, spaces, numbers, etc, but it must not be empty.

This is my current routing rule. As you can see, there is no restriction for the text parameter:

```
    my.search.results:
      path: '/search/{text}'
      defaults:
        text: NULL
        _controller: '\Drupal\my\Controller\SearchController::results'
        _title: 'Search Results'
      requirements:
        _permission: 'access content'

```

# Answer
As long as a default value isn't provided in the route definition, every route placeholder is required. Defining the route as follow is sufficient.

```
my.search.results:
  path: '/search/{text}'
  defaults:
    _controller: '\Drupal\my\Controller\SearchController::results'
    _title: 'Search Results'
  requirements:
    _permission: 'access content

```

See, for example, the definition of the *dblog.event* route in the dblog.routing.yml file.

```
dblog.event:
  path: '/admin/reports/dblog/event/{event_id}'
  defaults:
    _controller: '\Drupal\dblog\Controller\DbLogController::eventDetails'
    _title: 'Details'
  requirements:
    _permission: 'access site reports'

```

The controller associated to that route, `DbLogController::eventDetails()`, doesn't check the value of `$event_id` is an empty string, simply because it won't get an empty string for that parameter.

```
public function eventDetails($event_id) {
  $dblog = $this->database->query('SELECT w.*, u.uid FROM {watchdog} w LEFT JOIN {users} u ON u.uid = w.uid WHERE w.wid = :id', [
    ':id' => $event_id,
  ])
    ->fetchObject();
  if (empty($dblog)) {
    throw new NotFoundHttpException();
  }
  // …
}

```
> 0 votes

---
Tags: 8, routes, search
---


# Question
Title: Node is not created, but nid is returned
I have this code in my module.

```
  $node = new stdClass();
  $node->title = "YOUR TITLE";
  $node->type = "page";
  node_object_prepare($node);

  $node->language = 'it';
  $node->uid = 1;
  $node->status = 1;
  $node->promote = 0;
  $node->comment = 1;

  $node = node_submit($node);
  node_save($node);

  return "Nodo 222: " . $node->nid;

```

When I execute this code, it returns "Nodo 222: XXX," where XXX is an integer. If I execute it another time, I get XXX+1. When I try to load node/XXX or node/XXX+1, Drupal give me a Page not found error.

I have seen the "node" table in MySQL (via PHPMyAdmin), and nids XXX and XXX+1 are not present. When I create a page via node/add/page, the new nid is XXX+2 and it is saved in the "node" table too.

I have some modules installed (commerce, rules, logintoboggan and others), but this is the first time that I see this strange behavior.

So, where is my error?

# Answer
> 0 votes
Hope this will help you,

In Drupal 7, The $node object you pass to **node\_save()** wouldn't get it's nid member populated unless the node has been successfully saved to the node table in the database.

The auto-increment ID actually comes from the database table so if the $node object has a nid, you can pretty much guarantee the record has been successfully inserted into the table.

Im just guessing check for "node" table paging.

Clear drupal cache and check again.

I have used the below code and it is working fine for me, you can refer this.

```
  $node = new stdClass();
  $node->type = "page";
  node_object_prepare($node);
  $node->title = 'test node';
  $node->language = 'it';
  // Set node body details
  $node->body[LANGUAGE_NONE]['0']['value'] = 'test body';
  $node->body[LANGUAGE_NONE][0]['summary'] = text_summary('test body');
  $node->body[LANGUAGE_NONE][0]['format'] = 'filtered_html';
  //.. other fields goes here
  $node->uid = 1;
  $node->status = 1;
  $node->promote = 0;
  $node->comment = 1;
  if ($node = node_submit($node)) {
    node_save($node);
    drupal_set_message('NODE : ' .$node->nid);
  }

```

# Answer
> 0 votes
The error in the code shown in the question is that it's setting `$node->nid`, but not `$node->is_new`. For `node_save()`, the node is an existing node that needs to be updated. In fact, the function contains the following code.

```
// Load the stored entity, if any.
if (!empty($node->nid) && !isset($node->original)) {
  $node->original = entity_load_unchanged('node', $node->nid);
}
field_attach_presave('node', $node);
global $user;

// Determine if we will be inserting a new node.
if (!isset($node->is_new)) {
  $node->is_new = empty($node->nid);
}

```

```
// Save the node and node revision.
if ($node->is_new) {

  // For new nodes, save new records for both the node itself and the node
  // revision.
  drupal_write_record('node', $node);
  _node_save_revision($node, $user->uid);
  $op = 'insert';
}
else {
  // For existing nodes, update the node record which matches the value of
  // $node->nid.
  drupal_write_record('node', $node, 'nid');

  // …
}

```

It tries to update a database record that doesn't find, if there aren't nodes with that node ID, and it doesn't save anything. That's why you don't find a node with that node ID, in the table used for the nodes.

---
Tags: 7, nodes
---


# Question
Title: Twig: How to show static text in the template to the Anonymous User?
On a Drupal 8.9.13 website, I've removed the permission "View published content" from the Anonymous user. By default, when someone visits the front page, Drupal will then display:

> ## Access denied
>
> You are not authorized to access this page.

I want to replace this with some other text, e.g.

> Please create an account to see our content.

To do this I try to create something like this in `page--front.html.twig`.

```
{% if not logged_in %}
<p>Please create an account to see our content.</p>
{% endif %}

```

However, I am stuck .

1. I am not able to get rid of the "Access denied" text for the anonymous user.
2. I can't get the the text "Please create an account to see our content." to show for the *Anonymous user*. (If I remove "not" from the if-test it shows up as expected on the front page for the *Authenticated user*).

The site's theme is an otherwise unmodified subtheme of **Bootstrap Barrio** 5.1.4, but I don't think the problem is theme-dependent. Rather, the problem is that I don't understand the interplay between *Twig* and permissions (IMHO, there should be none).

# Answer
> 3 votes
Add a `page--403.html.twig` template to your theme.

See this change record: https://www.drupal.org/node/2960810

If you only want to change the default message you don't need a template. You can configure a node as access denied message in /admin/config/system/site-information.

Caveat for the non-template solution (as commented by @FreeRadical): If you restrict access to all nodes you have to find a different type of content. Could be a small module providing a custom controller which returns the static text.

BTW the themed page--403.html.twig is built in a subrequest which only job is to return a themed page with blocks. It's too late to make decisions on what to do with a 403 exception at this point. If you want to replace the core handling of a 403 exception (returning a themed subrequest) use an exception subscriber with default priority. See https://drupal.stackexchange.com/a/245211/47547

---
Tags: 8, theming
---


# Question
Title: Need to hide a views attachment when exposed filters are used
I have a view that displays employees and I've added an attachment that places the manager at the top of the page. I also have two exposed filters (department and name) that allow users to search the view. I'd like for the attachment to be hidden when the exposed filters are used. Any ideas? I've played with contextual filters but nothing has worked.

# Answer
> 0 votes
I would try with `hook_views_pre_render()`

```
function CUSTOM_MODULE_NAME_views_pre_render(&$view) {
  if ($view->name == 'YOUR_VIEW_NAME') {
    //inspect the url arguments
    //hide the view header if your exposed fields are used
  }
}

```

Another maybe more straightforward solution would be to use `template_preprocess_views_view`

```
function YOUR_THEME_NAME_preprocess_views_view(&$variables) {
  if ($variables['view']->name == 'YOUR_VIEW_NAME') {
    if ($variables['view']->current_display == 'YOUR_DISPLAY_NAME'
         && !empty($variables['exposed'])) {
      $variables['header'] = '';
    }
  }
}

```

For the 2nd one, this is a step by step how-to :

1. locate the folder of your current theme
2. open the file `template.php` in that folder with an editor
3. search in the code if there's already a function which name contains `preprocess_views_view`
4. if it does you'll place your code into that function, before the ending bracket `{`
5. if not, you'll create your own `template_preprocess_views_view` function, replacing `template` by the machine name of your theme, and write it at the bottom of the file :

```
function your_theme_name_preprocess_views_view {
  //we'll place the code there
}

```
6. open the related view and find its machine name in the url : ie for `admin/structure/views/view/frontpage/edit/page` view, the view name is *frontpage* and the display name is *page*
7. in the following code, replace view\_name and display name by yours :

```
  if ($variables['view']->name == 'YOUR_VIEW_NAME') {
    if ($variables['view']->current_display == 'YOUR_DISPLAY_NAME'
         && !empty($variables['exposed'])) {
      $variables['header'] = '';
    }
  }

```
8. finally, put it all together, placing that code either inside the existing or in the new function, as seen above
9. Clear caches, or at least theme-registry cache

Hope you'll manage it, not that difficult

# Answer
> 0 votes
The preprocess method shown previously doesn't work as intended in Drupal 7. It's a great start, but the function hides the header/attachment if an exposed filter itself is present, not if one is actively being used. The code below will hide the attachment (in this case attachment\_before) when the exposed filter is used.

```
function MYTHEME_core_preprocess_views_view(&$variables) {
  if ($variables['view']->name == 'YOUR_VIEW_NAME') {
    if ($variables['view']->current_display == 'YOUR_DISPLAY_NAME'
         && !empty($variables['view']->exposed_input['YOUR_FILTER']['value'])) {
      $variables['attachment_before'] = '';
    }
  }
}

```

---
Tags: views
---


# Question
Title: Is it possible to load a webform that is using a specific custom handler?
I have a custom handler for one of our webforms, it may be re-used for other webforms. It integrates with a 3rd party API and sends the response back to Drupal. I have to save the submissions to handle the response. I\`m wondering if its possible to load all webforms which are using this custom handler?

My goal is delete submissions of those webforms when they are older than a certain time.

# Answer
> 2 votes
You can use the next code:

```
$webforms = \Drupal::entityTypeManager()->getStorage('webform')->loadMultiple();
  foreach ($webforms as $webform) {
    foreach ($webform->getHandlers() as $handler) {
      if ($handler->getPluginId() == 'your_custom_handler') {
        // do your logic.
        break;
      }
    }
  }

```

---
Tags: webforms
---


# Question
Title: How do I get the taxonomy term ID from its name?
The only function on the list of taxonomy.module functions that looks like it does what I want appears to be a private function (\_taxonomy\_get\_tid\_from\_term).

What function am I supposed to use if all I know is the taxonomy term name and I need to find out its ID?

# Answer
It's taxonomy\_get\_term\_by\_name() which you use as in the following code.

```
$term_array = taxonomy_get_term_by_name('Foo');
$term = reset($term_array); # get the first element of the array which is our term object
print $term->name;

```
> 14 votes

# Answer
`taxonomy_get_term_by_name()` will do the trick:

```
$terms = taxonomy_get_term_by_name($row->field_term_name);
if (!empty($terms)) {
  $first_term = array_shift($terms);
  print $first_term->tid;
}

```
> 22 votes

# Answer
Here's a Drupal 8/9/+ answer, designed as a static PHP class method:

```
  /**
   * Utility: find term by name and vid.
   *
   * @param string $name
   *   Term name.
   * @param string $vid
   *   Term vid.
   *
   * @return int
   *   Term id, or 0 if none.
   */
  public static function getTidByName($name = NULL, $vid = NULL) {
    if (empty($name) || empty($vid)) {
      return 0;
    }
    $properties = [
      'name' => $name,
      'vid' => $vid,
    ];
    $terms = \Drupal::service('entity_type.manager')->getStorage('taxonomy_term')->loadByProperties($properties);
    $term = reset($terms);
    return !empty($term) ? $term->id() : 0;
  }

```
> 7 votes

# Answer
This function worked for me:

```
/**
 * Return the term id for a given term name.
 */
function _get_tid_from_term_name($term_name) {
  $vocabulary = 'tags';
  $arr_terms = taxonomy_get_term_by_name($term_name, $vocabulary);
  if (!empty($arr_terms)) {
    $arr_terms = array_values($arr_terms);
    $tid = $arr_terms[0]->tid;
  }
  else {
    $vobj = taxonomy_vocabulary_machine_name_load($vocabulary);
    $term = new stdClass();
    $term->name = $term_name;
    $term->vid = $vobj->vid;
    taxonomy_term_save($term);
    $tid = $term->tid;
  }
  return $tid;
}

```

If you are using another vocabulary (different from Tags), then modify in the code above the line:

```
$vocabulary = 'tags';

```
> 1 votes

---
Tags: taxonomy-terms
---


# Question
Title: New module service is dependency on old module service - The service has a dependency on a non-existent service
I have a new module moduleB. It defines a service that is used in the dependency injection of moduleA.

moduleA is already enabled, its changes are just to the services definition. The info.yml has moduleB as a dependency.

Both moduleA and moduleB are in the core.extension config to be enabled.

moduleB cannot be enabled using config (cim or csim) because the missing dependency from moduleA throws an exception.

How can I get config to enable the missing module before checking the service dependency? Or, how can I restructure to allow the existing module to use the new module service to allow enabling the module through drush ?

Thanks!

# Answer
> 0 votes
You can add moduleA to `core.extension.yml` on a new line (with the other modules) as `module_a: 0`.

---
Tags: 8, dependency-injection, symfony-services
---


# Question
Title: How to create an RSS or Atom Feed in Drupal (source)?
I have a website with Drupal 8 CMS and I have a second website without CMS.

I want to create an RSS or Atom Feed on my Drupal site (this will be the source).

I want to display the RSS or Atom Feed on the second site.

How to create an Atom or RSS Feed in Drupal 8 nodes to display it on the second site ?

# Answer
Just use Views to create feed with content and fields you desire. A bit more up to date tutorial: https://yalesites.yale.edu/book/creating-rss-feed-views
> 1 votes

---
Tags: 8, views, feeds
---


# Question
Title: How to programmatically require a field using Inline Entity Form
I have a node form using an inline entity form widget for either selecting or creating taxonomy terms to be referenced from the node. The field should be required at a certain moderation state, but in the early stages of moderation the field does not need to be required. I'm trying to make this change in `hook_form_alter`

I tried comparing the values of `$form` in the alter function when the field had been set to required, and when it hadn't. The only differences were within `$form['field_name']['widget']`:

`$form['field_name']['widget']['#required'] => 0`

vs.

`$form['field_name']['widget']['#required'] => 1`

and

```
$form['field_name']['widget'][#element_validate] => Array
                (
                    [0] => Array
                        (
                            [0] => Drupal\inline_entity_form\Plugin\Field\FieldWidget\InlineEntityFormComplex
                            [1] => updateRowWeights
                        )

                )

```

vs.

```
$form['field_name']['widget'][#element_validate] => Array
                (
                    [0] => Array
                        (
                            [0] => Drupal\inline_entity_form\Plugin\Field\FieldWidget\InlineEntityFormComplex
                            [1] => updateRowWeights
                        )

                    [1] => Array
                        (
                            [0] => Drupal\inline_entity_form\Plugin\Field\FieldWidget\InlineEntityFormComplex
                            [1] => requiredField
                        )

                )

```

Just adding `$form["field_name"]["widget"]["#required"] = TRUE;` to the alter didn't change anything, and trying to add the `#element_validate` bit lead to an error:

> User error: "0" is an invalid render array key in Drupal\Core\Render\Element::children() (line 97 of core/lib/Drupal/Core/Render/Element.php).

How can I programmatically require an inline entity form field in a hook form alter?

# Answer
I'm using the complex widget for Inline Entity Form. It may be that the normal form alter approach works for the simple form, I haven't tested, that but could not find the method I'm using to accomplish my solution in the simpleWidget code.

To get an admittedly ugly by default required indicator, and to actually have the validation happen, I needed to call the same validation method the complex widget uses when the field is marked as required within the structure -\> content type -\> manage fields interface.

Here is the code I used:

```
array_push($form['field_name']['#attributes']['class'],
          'form-required',
          'js-form-required');
$form['field_name']['widget']['#element_validate'][] = [
          '\Drupal\inline_entity_form\Plugin\Field\FieldWidget\InlineEntityFormComplex',
          'requiredField'
        ];;

```
> 0 votes

# Answer
I'm not sure if this will work out of the box for you, but I wrote this module https://www.drupal.org/project/require\_on\_publish to solve a similar problem. You might be able to borrow some of the ideas in there around adding constraints to custom fields to achieve your desired functionality.
> 1 votes

---
Tags: 8, workflows
---


# Question
Title: Is it helpful to improve performance by mysql table indexing?
Yes I am talking about manually indexing drupal cache table.

Is it helpful to improve site performance by indexing cache table?

For ex::

```
SELECT cid, data, created, expire, serialized, tags, checksum FROM cache_default WHERE cid IN ( 'locale:en::anonymous' ) ORDER BY cid;

```

# Answer
> 6 votes
The cache\_default table already has an index by CID (as well as indexes by creation and expiry date that allow old entries to be discarded).

Since almost all queries to the table are by CID there's not really any need for other indexes and it's not clear what benefit you would hope to see.

Adding extra indexes to tables does not result in cost-free performance enhancement. Every additional index makes write operations to the table more expensive, so you should not add any new index to a table until you have clear evidence of slow queries resulting from its absence.

# Answer
> 0 votes
Obviously id you add an index of a correct way to some specific fields/tables you can improve your performance. Sometimes is mandatory if you have thousands (or maybe millions) of rows.

Depends of the table you can add it using Drupal tools (and you should). I do not recommend add it manually in the database because if you manage more than one environment (that it's usual) you have to do it everywhere. To make a quick test you can add it directly in MySQL (for example using Workbenck) and test the queries using the EXPLAIN MySQL query tool (and obviously compare the performance results). After that, you can create the code to create the index programmatically using the Drupal Apis.

---
Tags: performance
---


# Question
Title: How to send dynamic content as an attachment file in email?
Normally we send files as attachments in the email if they are stored in the file system.

```
$file->uri = 'sites/default/files/file_name.pdf'; // File path
$file->filename = 'file_name.pdf'; //File name
$file->filemime = 'application/pdf'; //File mime type
$params['attachments'][] = $file;
$mailManager->mail($module, $key, $to, $langcode, $params, NULL, $send);

```

But I have dynamically generated content.

```
$content = <?xml version="1.0"?>
<root><element>element value</element></root>

```

I want to send it as an XML file attachment in the email. How can I do this?

# Answer
> 1 votes
I have found the answer.

Here is my code.

```
$content = '<?xml version="1.0"?><root><element>element value</element</root>';
$params['attachments'][] = [
  'filecontent' => $content,
  'filename' => 'data.xml',
  'filemime' => 'application/xml',
];

```

and then in hook\_mail

```
function mymodule_mail($key, &$message, $params) {
  switch ($key) {
    case 'my_email_key':
      $message['body'][] = $params['body'];
      $message['subject'] = $params['subject'];
      $message['params']['attachments'] = $params['attachments'];
      break;
  }
}

```

BTW I am using the swift mailer module.

Hope this helps someone.

---
Tags: 8, files, emails
---


# Question
Title: How to print the paragraph field translation value in twig template
I am trying to access the nested paragraph field inside my twig template.

```
{% for items in item['#paragraph'].get_aw_title_details%}
  {{ item.entity.field_award.value }}
{% endfor %}

```

When I am using this syntax it is always returning the English content. Translation content is not visible for me. For chinese also it is giving the english content

# Answer
Normally it's a better idea to process (or even better let Drupal process) the field values in PHP.

If there is no other way you can use Twig Tweak and its newly added entity translation filter:

```
{% set entity = item.entity|translation %}
{{ entity.field_award.value }}

```

See https://git.drupalcode.org/project/twig\_tweak/-/blob/3.x/docs/cheat-sheet.md#entity-translation
> 3 votes

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


# Question
Title: States don't work for a block rendering a form
I created a block in which I called a form inside the build() function. The form class has elements like radio button, input field type number, and submit button. I added a state condition to make the number field and submit button only visible on a certain condition of radio button.

The submission button is working correctly based on state condition, but not the number input field.

Does anyone has any idea?

```
$form['age'] = [
  '#type' => 'number',
  '#min' => 0,
  '#title' => $this->t('age'),
  '#default_value' =>'',
  '#states' => [
    'visible' => [
      [':input[name="marital_status"]' => [['value' => 'single'],['value'=>'couple']]],
    ]
  ],
];

$form['mybutton'] = [
  '#type' => 'submit',
  '#value' => $this->t('button'),
  '#states' => [
    'visible' => [
      [':input[name="marital_status"]' => [['value' => 'single'],['value'=>'couple']]],
    ]
  ],
];

$form['marital_status'] = [
  '#type' => 'radios',
  '#title' => $this->t('Marital status'),
  '#options' => [
    'single' => $this->t('single'),
    'couple' => $this->t('couple')
  ]
];

```

# Answer
I had to override the twig files for the form-element so some classes were missing like js-form-item' and 'form-item'. After adding thoses classes in the twig file, the states worked.
> 0 votes

---
Tags: 8, forms
---


# Question
Title: How to change a Textfield into a Select list in a Views Exposed Filter
Figured this question would be asked before, but don't see it.

I have a views exposed filter with a Text Field as one of the filters. I'd like to display this filter as a Select List instead of the standard text input or autocomplete.

Any advice on how to?

# Answer
> 5 votes
Okay, figured out a solid solution using hook\_form\_alter.

```
function MODULENAME_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {

    if ($form['#id'] == 'EXPOSED-FORM-ID') {

        $nids = \Drupal::entityQuery('node')->condition('type','CONTENTTYPE')->execute();
        $nodes = \Drupal\node\Entity\Node::loadMultiple($nids);
        $options = ['' => 'All'];

        foreach($nodes as $nid => $node) {
          $value = $node->get('FIELD_NAME')->getString();

          if (isset($value)) {
            $options[$value] = $value;
          }
        }

        if (isset($form['FIELD_NAME_value'])) {
          $form['FIELD_NAME_value']['#type'] = 'select';
          $form['FIELD_NAME_value']['#options'] = $options;
          $form['FIELD_NAME_value']['#size'] = 1;
        }
      }
    }

}

```

# Answer
> 1 votes
You can Implement using `hook_form_alter`

```
//Note: This will apply to all Views (thoes having same textfield in exposed filter).

function moduleName_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, &$form_id) {
  if ($form_id == 'views_exposed_form') {

    // Replace your TextField Name with 'field1'
    $form['field1'] = array(
      '#type' => 'select',  // Converting to select list
      '#options' => array(0 => t('<any>'), 20 => '*', 40 => '**', 60 => '***', 80 => '****', 100 => '*****'),  // your options/array
      '#default_value' => 0,
      '#title' => t('The average vote is more than'),
    );
  }
}

```

if you want to implement for specific view only then try following code.

```

function moduleName_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, &$form_id) {
  if ($form_id == 'views_exposed_form') {

    $view = $form_state->get('view');
//    \Drupal::logger('$view')->notice('<pre><code>' . print_r($view, TRUE) . '</code></pre>' );

    if ($view->id() == 'your_view_name') {

      // Replace your TextField Name with 'field1'
      $form['field1'] = array(
        '#type' => 'select', // Converting to select list
        '#options' => array(0 => t('<any>'), 20 => '*', 40 => '**', 60 => '***', 80 => '****', 100 => '*****'), // your options/array
        '#default_value' => 0,
        '#title' => t('The average vote is more than'),
      );
    }
  }
}

```

---
Tags: 8
---


title: Why does this code use so much memory?

text:
# Question
Title: Why does this code use so much memory?
I've got code that loops through nodes in order to generate processed output.

I've previously done an entity query that provided an array of node IDs. My main loop code looks like this.

```
foreach ($this->nids as $nid) {
  $node = Node::load($nid);
  $nodeData = $node->toArray();
  $nodeURL = $node->toUrl()->toString();
  print "Mem usage: " . memory_get_usage(TRUE) . "\n<br>";
}

```

Obviously, the loop shown here is a minimal example to demonstrate the problem; as it stands, it's pretty useless as it doesn't do anything with the data it loads.

However, the loop is eating memory. The debug call to `memory_get_usage(true)` in the loop gives a bigger number every time, until the script eventually runs out of memory if I feed it enough nodes (about 300 seems to be enough to kill it).

Obviously, I can increase the memory available, but I'm reluctant to do that because I can't see why the loop would be use so much memory in the first place.

Can anyone please explain why this fairly basic loop is using much memory, and what I can do to prevent it?

A few additional notes:

* I've tried adding `unset()` at the end of the loop to clear the node and data variables; this doesn't have any effect (I wasn't expecting it to, but I tried it anyway).
* The nodes in question have about fifty custom fields, including a couple that are paragraphs, which in turn have fields of their own.
* My real code passes the node data to a processor class that re-formats it for use elsewhere. It builds an array of these objects, but they aren't causing the issue.

I'm currently running on Drupal 8.6.

# Answer
> 10 votes
With thanks to the comments made by various people above, I have now optimised this code so that it doesn't run out of memory.

```
$chunks = array_chunk($this->nids, 100);

foreach ($chunks as $chunk) {
    $nodes = Node::loadMultiple($chunk);

    foreach ($nodes as $node) {
        //do stuff with the node here...
    }
    Drupal::entityTypeManager()->getStorage('node')->resetCache([$chunk]);
    print "Mem usage: ".memory_get_usage(true)."\n<br>";
}

```

I couldn't simply do `loadMultiple` for all the nodes at once as it was still using unholy amounts of memory, but chunking it and resetting the cache after each chunk seems to work nicely.

I experimented with different sized chunks, and I found I got the best mix of performance vs memory usage with the chunk size at 100. YMMV.

# Answer
> 4 votes
Fool proof method: `$memory_cache->deleteAll()`.

```
$memory_cache = \Drupal::service('entity.memory_cache');
$entity_storage = \Drupal::entityTypeManager()->getStorage('node');
$nids = \Drupal::entityQuery('node')
  ->condition('type', 'issues')
  ->execute();

$chunks = array_chunk($nids, 100);

foreach ($chunks as $chunk) {
  $entities = $entity_storage->loadMultiple($chunk);

  foreach ($entities as $entity) {
    // Do your stuff with the node/other entities.
  }

  $memory_cache->deleteAll();
}

```

`$memory_cache->deleteAll()` will delete the cached items from memory. I had a script that would load entity reference entities and that would not free the used memory, even after doing all the possible cache resets like suggested in the other answer. The only thing that worked for me is deleting everything.

---
Tags: 8, nodes
---


# Question
Title: External content migration translation problem
I am trying to import content into Drupal 8 from an external source (not previous Drupal version). I have crawled the original site and placed the content in a database. I am then writing a custom module to bring it into Druapl. I have the default language as English so when I run the migration for the English content there has no issue. It all imports perfectly. When I then run the translation migration, with French content, I get this error:

```
 [error]  SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null: INSERT INTO {key_value} (name, collection, value) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2); Array
(
    [:db_insert_placeholder_0] =>
    [:db_insert_placeholder_1] => node_translation_redirect
    [:db_insert_placeholder_2] => a:2:{i:0;N;i:1;N;}
)

```

Despite the error the content is imported, but as separate nodes instead of as translations to the original migration. I am using `drush` to run the migrations. Even though the French is imported, incorrectly, `drush` reports that the migration failed. I try to rollback both and the French does not get removed. I have to remove it manually.

I searched around but have not been able to find anyone having issues with SQL migrations.

Any help is appreciated. Thanks.

Here are my files:

# mymigrate\_content.yml

```
id: mymigrate_content
label: my content migration
langcode: en
source:
  plugin: mymigrate_content
  default_lang: true
  key: canada
  ids:
    pageid:
      type: integer
process:
  id: pageid
  title: title
  'body/value': body
  'body/format':
    plugin: default_value
    default_value: full_html
  'moderation_state/target_id':
    plugin: default_value
    default_value: published
destination:
  plugin: 'entity:node'
  default_bundle: page
  langcode: en
  no_stub: true

```

# mymigrate\_content\_translation.yml

```
id: mymigrate_content_translation
label: my content migration
langcode: fr
source:
  plugin: mymigrate_content_translation
  translations: true
  default_lang: false
  key: canada
  ids:
    pageid:
      type: integer
process:
  id:
    plugin: migration_lookup
    migration: mymigrate_content
    source: pageid
  title: title
  'body/value': body
  'body/format':
    plugin: default_value
    default_value: full_html
  'moderation_state/target_id':
    plugin: default_value
    default_value: published
  content_translation_source:
    plugin: default_value
    default_value: "en"
destination:
  plugin: 'entity:node'
  default_bundle: page
  langcode: fr
  no_stub: true
  translations: true

```

# MyMigrate.php

```
<?php
namespace Drupal\ca_migrate\Plugin\migrate\source;

use Drupal\migrate\Plugin\migrate\source\SqlBase;
use Drupal\migrate\Row;

/**
 * Migration
 *
 * @MigrateSource(
 *  id = "mymigrate_content",
 * source_module = "mymigrate",
 * )
 */
class MyMigrate extends SqlBase {
  /**
   * @var integer $rowCount
   */
  public $rowCount = -1;

  /**
   * {@inheritdoc}
   */
  public function query() {
    $query = $this->select('pagecontent', 'pc')
      ->condition('pc.language', 'en', '=')
      ->fields('pc', [
        'pageid',
        'language',
        'body',
        'originalurlpath',
        'title',
      ]);

    return $query;
  }

  /**
   * {@inheritdoc}
   */
  public function fields() {
    $fields = [
      'pageid' => $this->t('pageid'),
      'language' => $this->t('language'),
      'body' => $this->t('body'),
      'originalurlpath' => $this->t('originalurlpath'),
      'title' => $this->t('title'),
    ];

    return $fields;
  }

  /**
   * {@inheritdoc}
   */
  public function getIds() {
    return [
      'pageid' => [
        'type' => 'integer',
        'alias' => 'pc',
      ],
    ];
  }
}

```

# MyMigrateFr.php

```
<?php
namespace Drupal\ca_migrate\Plugin\migrate\source;

use Drupal\migrate\Plugin\migrate\source\SqlBase;
use Drupal\migrate\Row;

/**
 * Migration
 *
 * @MigrateSource(
 *  id = "mymigrate_content_translation",
 * source_module = "mymigrate",
 * )
 */
class MyMigrateFr extends SqlBase {
  /**
   * @var integer $rowCount
   */
  public $rowCount = -1;

  /**
   * {@inheritdoc}
   */
  public function query() {
    $query = $this->select('pagecontent', 'pc')
      ->condition('pc.language', 'fr', '=')
      ->fields('pc', [
        'pageid',
        'language',
        'body',
        'originalurlpath',
        'title',
      ]);

    return $query;
  }

  /**
   * {@inheritdoc}
   */
  public function fields() {
    $fields = [
      'pageid' => $this->t('pageid'),
      'language' => $this->t('language'),
      'body' => $this->t('body'),
      'originalurlpath' => $this->t('originalurlpath'),
      'title' => $this->t('title'),
    ];

    return $fields;
  }

  /**
   * {@inheritdoc}
   */
  public function getIds() {
    return [
      'pageid' => [
        'type' => 'integer',
        'alias' => 'pc',
      ],
    ];
  }
}

```

# Answer
> 1 votes
I was finally able to trace the problem. The migration code was expecting a value for the key `nid`. I was able to provide the appropriate value by overriding the function `prepareRow`.

Here is the code I used in both **MyMigrate.php** and **MyMigrateFr.php**:

```
  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    $nid = $row->getSourceProperty('pageid');
    $row->setSourceProperty('nid', $nid);
    $row->setDestinationProperty('nid', $nid);

    return parent::prepareRow($row);
  }

```

# Answer
> 0 votes
I encountered the same problem migrating from a JSON source:

Integrity constraint violation: 1048 Column 'name' cannot be null: INSERT INTO {key\_value} (name, collection, value) ...

with empty value for 'name'.

I solved the problem by removing the line

```
  translations: true

```

from the source: block. I think this is only needed in the destination: block.

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


# Question
Title: Retrieve Webform submission data from database
Here's a little background on my project: I have 10 or so webforms let's call them Forms A thru J which are for different departments of a college. I also, have 1 credit card processing form let's call Form Z. I will be collecting information from a form like Form A specific to that departments needs and upon submission will redirect the user to Form Z to process a credit card transaction. I have created a webform handler to redirect the user from Forms A-J to Form Z and a handler to process the credit card transaction. In the redirect handler I am able to pass all of the information from Forms A-J to Form Z using the query string in the URL. I want to avoid this since there would be Personal Identifiable Information (PII) being passed through the URL.

I want to be able to retrieve the data submitted on say Form A from the database when Form Z is loading. I should be able to pass the webform node ID and submission ID to Form Z through the URL query string and use them to get the data from the database. I found these posts which give me an idea of how to retrieve the data from the database:

Programmatically update Webform Submission by sid

Load webform submission

https://www.drupal.org/project/webform/issues/2911356

What I can't find is how do I get this to run when Form Z is loading. I've seen a couple of posts on hook\_form\_alter but those posts are using it in a different way from what I am trying to do so I don't know it that's the way I need to go.

Once I retrieve the data from the database I need to populate that data into I'm thinking some hidden webform fields on Form Z. I'd like to be able to fill billing address with the address submitted with the previous form upon request (checkbox or button). Also, I need to be able to have the data from the previous form available once Form Z submits so that I can send a custom email Confirmation depending on which form the information came from (i.e. Form A or B or J).

Being new to drupal development I've gotten some great assistance with this project from this site and I am very grateful to those who have been assisting me. :)

EDIT:

So based on Remy's recommendations I have created a custom module with these two files in \modules\custom\cc\_processing\_getsubmissiondata:

cc\_processing\_getsubmissiondata.info.yml

```
name: 'CC Processing Get SubmissionData'
description: 'Provides a custom webform handler for retrieving the previous forms submission data'
core_version_requirement: ^8.8
Core: 8.x
package: Custom
type: module

```

CCProcessingGetSubmissionData.module

```
<?php

/**
 * Implementation of hook_form_alter
 */

 use Drupal\Core\Form\FormStateInterface;

 function CCProcessingGetSubmissionData_form_alter(&$form, FormStateInterface $form_state, $form_id) {
    echo "form alter hook triggered";
        $form['street_1'] = '92-2000 Some Rd.';

    if($form['#webform_id'] == 'credit_card_billing_information') {
        echo "form alter form id found";
        $form['credit_card_name'] = 'Jared';
    }
 }

```

At this stage I am just trying to get the hook\_form\_alter to just do something so that I know it is being triggered. However, I am getting nothing. I even tried the function name CCProcessingGetSubmissionData\_webform\_credit\_card\_billing\_information\_form\_alter but that didn't work either. Any suggestions?

# Answer
Easiest is probably to preprocess the webform's new submission, load the desired submission, and then pre-populate your fields. I doubt that this is built-in.

fe

```
<?php
function HOOK_webform_submission_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  if ($form['#webform_id'] == 'your_webfom') {
    $form['elements']['your_element']['#default_value'] = $your_value;
  }
}

```

There may be several ways by not-coding, but using modules.

LMGTFY - https://www.drupal.org/forum/support/post-installation/2021-02-01/how-to-use-webforms-submissions-in-other-forms

1. Install the 'Webform Views Integration' module.
2. Create the view for display submissions of the 'Client' webform.
3. Add to the view the 'Entity Reference' display and add the 'Name' field (or any field you want to see on the 'Project' webform).
4. Click on the 'Settings' and check the field that will use for serach.
5. In the 'Client' webform select the following reference method: 'View: Filter by an entity reference view'.
6. Select the view created by you from the 'View used to select the entities' list.

The screenshots of the example:

1. https://ibb.co/ZJxgK9w
2. https://ibb.co/C6sxCFv
3. https://ibb.co/mFWDCTX
4. https://ibb.co/QcwYYm6
> 2 votes

---
Tags: webforms
---


# Question
Title: Creating date field with only month and year
We are using the Form API in a custom module (and not an entity field), how can we easily set the date widget for just year and month data entry?

I've tried adding a `#date_format` attribute but no change:

```
$form['date_needed'] = array(
  '#type' => 'date',
  '#title' => $this->t('Date Needed'),
  '#date_date_format' => 'Y/m',
);

```

I have also tried `'#date_date_format' => 'd/m/Y'` but the date widget still appears asking for `YYYY-mm-dd`.

Looking at the source code for `core/Render/Element/Date.php` and stepping though the code, I can see it's picking up this setting.

The drupal.org doc page has a comment that indicate this should work: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21Element%21Date.php/class/Date/8.2.x

Any ideas?

# Answer
> 3 votes
We can make this in a hook\_form\_alter.

```
$form['DATE_FIELD_MACHINE_NAME']['widget'][0]['value']['#date_date_element'] = 'month';
$form['DATE_FIELD_MACHINE_NAME']['widget'][0]['value']['#date_date_format'] = 'Y-m';

```

However, there is still a problem of this way: instead of first day of the month, current day will be saved. I cannot figure out how to solve.

# Answer
> 0 votes
Your code should work, just tested it in my own form class:

```
public function buildForm(array $form, FormStateInterface $form_state) {
    return [
      'date_needed' => [
        '#type' => 'date',
        '#title' => $this->t('Date Needed'),
        '#date_date_format' => 'm/Y',
      ],
}

```

My browser changes the displayed date value as provided in the value of `#date_date_format`. In the rendered HTML I also see the `data-drupal-attribute`:

```
<input data-drupal-selector="edit-date-needed" data-drupal-date-format="m-Y" id="edit-date-needed" name="date_needed" value="" class="form-date hasDatepicker" type="date">

```

I am testing with Drupal 8.3.4. Perhaps your core version is lower?

# Answer
> 0 votes
Add attribute type "month", this will render as

```
<input type="month">

```

Of course the modern day Internet Explorer (Safari) doesn't support this. Well it doesn't support date pickers out of the box anyway so... Actually not supported by Firefox either yet :(

```
  $form['date_to'] = [
    '#title' => 'To',
    '#type' => 'date',
    '#date_date_format' => 'm/Y',
    '#attributes' => ['type'=> 'month']
  ];

```

Funny how mozilla documentation explains it but doesn't support it its browser: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/month

---
Tags: 8, forms
---