# Question
Title: How to see all keys for a PrivateTempStore?
The Drupal class `PrivateTempStore` allows for setting and getting key-value pairs within a temporary data store. The class includes the `$storage` property which then has a `getAll()` method for retrieving all items in the store. However, this is protected, and so cannot be used by an instantiated `PrivateTempStore` object.

Is it possible, given a `PrivateTempStore` object, to retrieve a list of all keys currently used in the store?

# Answer
No, with the current `PrivateTempStore` you don't have access to the list of keys. You're welcome to create your own `TempStore` class if you want different functionality, but I don't see why that is needed here.

The whole point of `PrivateTempStore` is to stash temporary data for a user, under a given key. If you don't know the key, then you have no knowledge of the type or structure of the data stored there, so in general you won't know how to use it. If your intention is to store a collection of data of a known type (stored in an associative array, for example) so that you can iterate over it later, then store the array itself under a known key, don't store each array element separately. Then you can retrieve the array later from the known key and do a foreach over each element of the array.
> 0 votes

---
Tags: 8
---


# Question
Title: What is the best way to add "last_imported" field into a view for a node entity-reference field joined to migrate_map table?
I have a node which has an entity-reference field. The enitity in that field is being imported via Migration framework.

So if I call that entity fruit. MyNode has a field call fruit. Which is being migrated from an up-stream. Thus, it has a "migrate\_map" table call "migrate\_map\_fruit".

In which it has a column call "sourceid" which can be joined to "fruit.id" and then I want to extract a field call "last\_imported" and display in the view.

What would be the best way to bring it to views ?

It's quite complex so feel free to reach me if you need more clarification.

# Answer
> 0 votes
So I found the solution to that.

You have to add relationship to referenced "fruit" entity to the view. And immediately following field will be available.

In my **fruits\_import.module.php** I added hook\_view\_data() as follows.

```
/**
 * Implements hook_views_data().
 */
function fruits_import_views_data() {
  $views_data = [];
  // Exposing Migrate Map table.
  $views_data['migrate_map_fruit']['table'] = [
    'title' => t('Related migration'),
    'group' => t('Fruit Entity Migration Tables.'),
    // Watch out! This is not a base table, so we use a different key and
    // explain to Views how this table can be JOINed to our base table of
    // 'fruit'.
    'join'  => [
      // We are explaining Views how 'migrate_map_fruit' can be JOINed to 'fruit'.
      // By the way, you do not necessarily have to JOIN onto a base table. You
      // may as well JOIN in chain a few non-base tables. Although for a table
      // to become visible in Views UI, it must be connected one way or another
      // to a base table on which the view is being built.
      'fruit' => [
        // Column from 'fruit' table which will participate in the JOIN clause.
        'left_field' => 'id',
        // Column from 'migrate_map_fruit' table that will participate in the JOIN
        // clause.
        'field'      => 'destid1',
      ],
    ],
  ];
  // Exposing last imported col only for now. (We could expose other ones here)
  $views_data['migrate_map_fruit']['last_imported'] = [
    // Human friendly name for Views UI.
    'title' => t('Last Imported'),
    'help' => t('Timestamp for an fruit last imported.'),
    'field' => [
      // In the 'id' key we place the name of Views field plugin that is
      // responsible for operating the column. The id "date"
      // corresponds to \Drupal\views\Plugin\views\field\Date class. It is
      // an extremely simplistic straightforward field plugin that appends the
      // column into SELECT query (see ::query() method) and then displays the
      // fetched column as field output (see ::render() method).
      'id' => 'date',
    ],
  ];
  return $views_data;
}

```

Credits to awesome Views tutorial by Oleksandr

---
Tags: views, migrations
---


# Question
Title: How do I invoke a service after submitting a form?
I am very new to Drupal and I am asked to create form with a submit button and a service that makes a get request to an API with the values from the form. The API is a simple API that the user can enter a country and it will return a response with the correct greeting from that country.

This is my routing file.

```
hello_world.salutation:
  path: '/hello'
  defaults:
    _controller: Drupal\hello_world\Controller\HelloWorldSalutation::salutation
    _form: Drupal\hello_world\Form\GreetingForm
    _title: 'Get a greeting from a different language'
  requirements:
    _permission: 'administer site configuration'

```

First problem is that I do not know how to make the form and the controller in the same routing, and second is that I do not know how to invoke that service when the user has entered submit.

This is the services file.

```
services:
  hello_world.salutation:
    class: Drupal\hello_world\HelloWorldSalutation
    arguments: [ '@config.factory' ,'@tempstore.private']
  cache.nameofbin:
    class: Drupal\Core\Cache\CacheBackendInterface
    tags:
      - { name: cache.bin }
    factory: [ '@cache_factory', 'get' ]
    arguments: [ nameofbin ]

```

I will skip some lines from the GreetingFrom class to keep it simple, but I can add them if it is required.

Here is the submitForm function from the GreetingForm class. The idea is to put the input in a global tempstore so I cal access the values from the controller I guess.

```
  public function submitForm(array &$form, FormStateInterface $form_state)
  {
    $search_str = $form_state->getValue('greeting');
    // check the input
    $params['items'] = $form_state->getValue('greeting');
    // 2. Create a PrivateTempStore object with the collection 'greetingForm_values'.
    $tempstore = $this->tempStoreFactory->get('greetingForm_values');
    // 3. Store the $params array with the key 'params'.
    try {
      $tempstore->set('params', $params);
    } catch (\Exception $error) {
      // dump the error for now, read error, --fix this!
      dpm($error);
    }
  }

```

And the salutation function from the controller looks like this.

```
  public function salutation()
  {
    $tempstore = $this->tempStoreFactory->get('greetingForm_values');
    $params = $tempstore->get('params'); // this value should come from the search form
    return [
      '#markup' => $this->salutation->getGreeting($params),
    ];
  }

```

# Answer
You're trying to do four things at once (form, service, integration with API, caching), so you can't see where the problem is. Instead, break this down into distinct steps.

First, code and debug your form. In the submit function, just use the messenger service in your form (`$this->messenger()->addMessage('this is a test message');`) to display a static value for your greeting. You should reach a point where visiting `/hello` and submitting the form will display the message. You can customize that message later. Get this working first.

Second, code and debug your service class. I find it useful to use `drush php-script` here to execute a standalone PHP script that accesses your service. That way you can ensure your service is doing exactly what you want, and figure out how to communicate with the external API, before you try to use your service in a form. You don't need the "\_controller" in your routing file. The way to access your service is using `\Drupal::service('hello_world.salutation')->salutation()`. Instead of passing variables through a tempstore, pass them as parameters to your `salutation()` method. So your standalone PHP script for drush would look something like this:

```
<?php

  $greetings = \Drupal::service('hello_world.salutation')->salutation('some string entered on your form');
  echo $greetings;

```

Save this as test.php then execute this with `drush php-script test.php`.

Third, once your service is working as you want, integrate your service with your form. You should be able to take the PHP script you wrote in step two and insert it almost unchanged into your form submit function. (As a future enhancement, learn how to inject your service into the Form rather than use the static `\Drupal::service()` call, but that can wait until after you have this working).

Fourth (do this only after you have the above working), examine your need to cache data, and then implement some sort of caching in your service *if needed*. You haven't shown all your code or completely explained what you're doing, but I don't see anything that justifies using `cache.nameofbin` or a tempstore.
> 0 votes

# Answer
I would suggest taking a look at hook\_form\_alter

Forms can have multiple submit functions and its best not to wipe out the original functionality (unless that's what you really want to do)

Your code might look something like this

```
function yourmodule_YourFormID_form_alter(&$form, &$form_state) {
     // conditions you execute custom code

      $form['#submit'][] = 'yourmodule_submit_function';
}

```
> -1 votes

---
Tags: forms
---


# Question
Title: How do I display a Media entity reference field in a nested paragraph on a template?
I have been working on this for 2 days and I can't figure it out. I hope someone can help me. I have a paragraph `(dinamic_columns_grid)` that has an entity reference field to another paragraph `(field_dinamic_column)` This nested paragraph has an entity reference field to a Media image field `(field_image)`. All the paragraphs have more fields but this is the one that is giving me problems.

I created a twig template for the first paragraph `(paragraph--dinamic-columns-grid.html.twig)` where I want to display the nested paragraph's fields individually. I know I could use `{{ content.field_dinamic_column }}` to display all of the results, and it does work, including the image field, but that's now what I want. All the fields in the code below are displaying correctly except the image field `(field_image)`. I have tried everything but I can't seem to make it work. Any help will be appreciate.

```

        {% for key, item in content.field_dinamic_column %}
            {{ item['#paragraph'].field_html_content.value|raw }} / text field.It works
            {{ item['#paragraph'].field_hide.value|raw }} / select field. It Works
            {{ item['#paragraph'].field_image }} / Media image field. It doesn't work
         {% endfor %}

```

I like to be able to see the image or at the very least the url. Thanks.

# Answer
After many attempts I finally figure it out, thanks to the comments above and a little investigation. I think my problem was that I assume that the machine name I need it to use for my nested image field was the one I give when I created the content type but that's not the case, I had to use the field of the media type in my case `field_media_image` instead of `field_image`.Below is the working code.

`{{ file_url( item['#paragraph'].field_image.entity.field_media_image.entity.uri.value ) }}`
> 1 votes

---
Tags: 8, theming, paragraphs
---


# Question
Title: Enable rest resource resource when module installs
I have a custom rest resource I have created within my module:

```
/**
 * Provides a Demo Resource
 *
 * @RestResource(
 *   id = "custom",
 *   label = @Translation("custom"),
 *   uri_paths = {
 *     "canonical" = "/rest/custom"
 *   }
 * )
 */
class custom extends ResourceBase {
public function get() {
    return new ResourceResponse("Response");
}

```

I have a `rest.resource.custom.yml` file in my module/custom/install folder to activate the end point when the module gets installed but it doesnt work:

```
id: module.custom
plugin_id: 'custom'
granularity: method
status: true
configuration:
  GET:
    supported_formats:
      - json
    supported_auth:
      - cookie

```

How do you enable rest endpoints when module is installed?

# Answer
> 0 votes
The error was in the .yml file with the id: attribute. Dont need to include the module name with it:

```
id: custom
plugin_id: 'custom'
granularity: method
status: true
configuration:
  GET:
    supported_formats:
      - json
    supported_auth:
      - cookie

```

# Answer
> 0 votes
If you enable the core Configuration Manager module you can export any or all configurations on your site. After you configure your module's REST resource, go to `/admin/config/development/configuration/single/export` and choose "REST resource configuration" for the configuration type, then choose "custom" (your RestResource plugin ID) for the configuration name - the export will show you the proper contents and tell you what to name your .yml file.

This is the best way to ensure that the .yml contains the exact configuration you want and that all the necessary information is present. This process would have prevented you from having the original problem.

---
Tags: 8, configuration, installation
---


title: SMS password recovery

text:
# Question
Title: SMS password recovery
I'm currently using D7. When my users attempt to request a password reset, 95% of the time, these reset emails land in their spam, or are blocked by whomever their email provider is. That being said, I'm looking to implement a way for my user to regain access to their account by receiving this password reset link via SMS instead.

Currently, my site collects the user's phone number on registration, and I have the Twilio module installed. All of that said, there doesn't seem to be a Drupal Rule that I can execute for "When anonymous user requests password reset".

Ideally, I'd like to have a Drupal rule search my user list for the user that contains the input email, and then simply send the generated password reset link to the phone number on file (also attached to the found User's account).

Is this possible?

# Answer
You might want to investigate using the SMS Framework module along with Twilio SMS Integration instead - they have more users and there is more active and more recent development with these modules. They also have D8 ports, so you are covered for when you decide to upgrade to D8. But the answer below will work whether you use the above two modules or whether you just use the Twilio module.

When you say "Drupal Rule" I'm going to assume you mean a Rule made with the Rules module.

A Rules module Rule requires an Event, one or more optional Conditions, and one or more Actions. In this case, the Action would be to send an SMS message. The SMS Framework module does provide an Action for Rules, which is named "Send sms". You can use this action to send the SMS message. All you need now is an Event.

You want an Event that is fired when the anonymous user submits the password reset form. Drupal core does not have any hooks or events for password reset. This Event does not come with Rules. I know of no contributed modules that provide this Event. So you will have to write a few dozen lines of code. You can also do this without Rules, but you will also have to write code and it will be more code than with Rules.

Writing an Event is not hard, but it does require coding. A tutorial on how to do that is outside the scope of this issue. Below I will outline the basic steps and point you to some documentation. What you need to do is:

* Implement `hook_rules_event_info()` to declare your event to Rules and define the variables that will be stored in the event. These variables will probably the telephone number and the user email address plus whatever other information you may need to complete the task.
* Implement `hook_form_alter()` to alter the `user_pass` form so that it executes a custom submit handler.
    + Your custom submit handler should use the submitted email address to look up the user's telephone number.
    + Your custom submit handler will then call `rules_invoke_event()` to invoke your own custom event. You will pass this event the telephone number and the email address.

There are many examples of this that can be found. Some randomly selected pages which discuss this are:
> 3 votes

---
Tags: 7, users, rules
---


# Question
Title: How to load Node and Paragraphs using target_revision_id?
In Drupal 8, How to load Node and Paragraphs using `target_revision_id`?

For node I used `\Drupal::entityTypeManager()->getStorage('node')->load($nodeId);` . I tried this for revision id: `\Drupal::entityTypeManager()->getStorage('node')->loadRevision($vid);`

# Answer
The second line probably should be:

```
\Drupal::entityTypeManager()->getStorage('paragraph')->loadRevision($target_revision_id)

```

It is recommended, though, to load the referenced entities through the field:

The first paragraph:

```
$paragraph = $node->{$field_name}->entity;

```

The second paragraph:

```
$paragraph = $node->{$field_name}->get(1)->entity;

```

All paragraphs:

```
$paragraphs = $node->{$field_name}->referencedEntities();

```
> 1 votes

---
Tags: paragraphs
---


title: Custom Theme Repository update

text:
# Question
Title: Custom Theme Repository update
I have a custom theme that I use in several websites.

My theme is on gitlab.

I can download my theme by composer in different websites.

My problem is when I update repository theme with a fix or new feature and then this do not mirror on websites, even if I delete theme folder and composer.json info, it's always stuck on the same version.

My composer.json of theme repository

```
{
"name": "test/test-theme",
"description": "Drupal Custom Theme",
"type": "drupal-custom-theme",
"minimum-stability": "dev",
"require": {}

```

}

My composer.json from the website:

```
"repositories": [
    {
        "type": "composer",
        "url": "https://packages.drupal.org/8"
    },
    {
        "type": "package",
        "package": {
          "name": "test/test-theme",
          "version": "dev",
          "type": "drupal-custom-theme",
          "source": {
            "type": "git",
            "url": "{URL}",
            "reference": "master"
          }
        }
      }
],
"require": {
    "test/test-theme": "dev",
 }

```

How can I update my theme last features with composer?

# Answer
We had a similar setup. But the only difference is we create a new tag for every update in the theme repository. So we just reference the new tag in website composer.I would suggest you to try that instead of referencing branch so you get updated code on every compiser update.

If you are not interested in doing in that manner I would suggest you to clear composer cache and execute `composer update` you will probably get the updated code.
> 2 votes

---
Tags: 8, theming, composer
---


# Question
Title: Inconsistent behavior with user_logout function
For a drupal 8 site, I have a custom function that does the following:

It logs out the user and sends them to an external url

Inside the controller CustomController, I have:

```
function custom_logout(){
 if (\Drupal::currentUser()->isAuthenticated()) {
    user_logout();
    return new TrustedRedirectResponse('https://example.com');
 }
}

```

In the routing.yml

```
customl.clogout:
  path: '/customlogout'
  defaults:
    _controller: '\Drupal\user\Controller\CustomController::custom_logout'
  requirements:
    _user_is_logged_in: 'TRUE'

```

When I visit the **/customlogout** for the **first time** it logs me out of Drupal and redirects me to example.com. If I revisit my site and login in again, and repeat the process it still redirects me to example.com but when I check my site I am still logged in. I am wondering why this happens? I can still logout using /user/logout though

Thank you

# Answer
> 5 votes
As it turns out,

`return new TrustedRedirectResponse('https://example.com');`

was the culprit here. TrustedRedirectResponse extends CacheableSecuredRedirectResponse, as a result the function was cached, and user\_logout was not called even when I visited the **/customlogout**

The workaround for this is adding the following lines in your routing.yml

```
options:

  no_cache: TRUE

```

---
Tags: 8, users, redirection
---


# Question
Title: How can we make edit Body input area larger?
The Body field of the content on our website is generally quite large -- multiple pages. When Editing in Drupal 8, the Input Area is quite small -- 98 characters wide by 9 lines. The first thing we do is drag the bottom right of the Input Area and increase the size to 30-40 lines. This makes editing much easier.

Is there a way to make the Body Input Area size 30 lines long for our website? This would eliminate one step on every Edit!

# Answer
> 6 votes
You can go to the content types (or paragraph type) Form display settings and set the number of rows. No dev needed:

e.g. /admin/structure/types/manage/content\_type/form-display

1. Click on the gear in the right column
2. Click update
3. Click save at the bottom

# Answer
> 0 votes
This can be done by setting `#rows` for the textfield widget in `hook_form_alter()`.

This should work regardless of whether you are using CKEditor or a regular textarea form element.

For example (using hook\_form\_FORM\_ID\_alter() which requires you to target the node edit form with FORM\_ID),

```
/**
 * Implements hook_form_FORM_ID_alter().
 */
function mymodule_hook_form_FORM_ID_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['body']['widget'][0]['value']['#rows'] = 30;
}

```

---
Tags: 8
---


title: Rebuild images from image style

text:
# Question
Title: Rebuild images from image style
I have an image style in Drupal 7. I attached several images to a nodes and display the images based on this style. I then changed the effects on this image style but the existing images are not being recreated with the new image style effects. They show with the old image style effects.

If I attach new images, they use the new effects. Deleting an existing image and re-uploading causes the image to use the old effects.

The manual (incorrectly I assume) states that just saving an image style causes a rebuild: http://drupal.org/documentation/modules/image

I have cleared the cached.

How do I force a rebuild?

# Answer
Clearing cache, won't flush image styles: http://drupal.org/node/997332

You could:

* delete them manually
* use image\_style\_flush
* use the command line: `rm -rf sites/default/files/styles`
* use drush: `drush image-flush`
> 123 votes

# Answer
To flush Image Style Names in Drupal 7 through the UI, try this contrib module:

http://drupal.org/project/imagestyleflush

It gives you a flush option for each Image Style Name. It also has an option to flush all the Image Style Names at once.

Once the module is enabled, in the admin UI go here to flush a particular image style:

```
admin/config/media/image-styles

```
> 15 votes

# Answer
This is a bug with image styles. If you are editing an image style and edit an effect that is already present, the images will not be flushed on update. However, if you delete that effect (I'm not talking about deleting the image style - delete the effect within the particular image style) and create a new one, the images will be flushed on update.
> 9 votes

# Answer
There is another, easier way. It's more a replacement than update, but it works fine. You can create a new image style based on the old one, but with new features (image actions) you wish. Then delete the old style; on the deletion confirmation page, you will find a drop list with available image styles, which you can use to replace the old one. This is a standard image style replacement function, I assume.
> 3 votes

# Answer
Just for information in Drupal 8 you have an "flush" option in the "Edit" dropdown in /admin/config/media/image-styles you can flush one by one.
> 3 votes

# Answer
Edit the style you want from admin/config/media/image-styles.

Click on 'update style' button on bottom, that will flush all the existing generated images in style folder and create new ones.
> 2 votes

# Answer
if u have a custom template and wanna force style for an image field :

```
 $style='full_content_width';
 $path=$node->my_img_field['und']['0']['uri'];
 $style_url = image_style_url($style, $path);
  print "<img src=".file_create_url($style_url)." >";

```
> 1 votes

# Answer
If you are using Drupal Console (and let's face it, why not?) then you can use:

```
drupal image:styles:flush image_style

```

Or

```
drupal isf image_style

```

Documentation: https://drupalconsole.com/docs/ca/commands/image-styles-flush
> 1 votes

---
Tags: 7, media
---


# Question
Title: How to load certain old submission value into webform?
I collect data in a web form. As one of the first fields, it has a dropdown with which it selects a certain ID. Later on, there shall be grouped elements like this:

```
value_old | value_new | diff

```

`value_new` is just the new value, that the user shall provide.

`diff` is the computed difference `value_new - value_old` and I think that I can implement that as a "Computed Twig" element.

`value_old` is a bit more complex. This should be the `value_new` from the newest submission already in the database for the same form, where the ID from the dropdown in the beginning was the same.

I think, the solution should go in a direction of a token definition for the `value_old` or so, but I'm not sure on whether this is a) the right direction and b) how this could be done.

# Answer
> 0 votes
Long story short:

I wrote a custom webform element that takes an argument that gets updated via AJAX and queries the database.

Long story:

As in my comment, adding the "Webform View" module worked besides the wrong version number in the project description for the dependencies.

But it didn't help.

So, here are a few learnings along the way that might be interesting for people with similar challenges, followed by the final solution.

I was able to create a view that outputs the `value_old` that I need, when I provided the previously selected ID as an argument.

*But:*

While there is a webform element that shows views and takes arguments, it doesn't work with a token as an argument to reload it's content, when there is a (new) value for the token. It is even not possible to split it up into several pages, such that there is already a value for the token, when the user proceeds to the next page.

I needed a webform element that gets recalculated, when the form changes, but gets its information from the database. So, I created a new webform element in a custom module. I took the „Computed Twig Element“ as a starting point. But instead of doing a computation, I took the input value as an argument for querying the database for my `value_old`.

In theory, it would have been possible, to use the view from above, as long as computed values in this view are stored in the database. If they aren't, querying the view will run out of memory.

In my case, there are some additional requirements to the rights management. Therefore, I tried different querying mechanisms. In this custom field, it was possible to query the database directly and to query the view. I also tried the Webform Query module. But something in there seems broken, because this module produced a query with a wrong name in it, as soon as I started querying for ordered results.

---
Tags: webforms, tokens
---


# Question
Title: Product reference add to cart form shows only add to cart button
I've created a content type with a product reference field, but when I create a content with the reference to the product, it shows add to cart form with only add to cart button. I wanted to display Price, quantity, and product attributes on the add to cart form. I've searched a lot to find out any configuration for this, but no luck. Can anyone please help me regarding this?. It works fine in Drupal 7, but in Drupal 8 there is no way I can set up the form.

# Answer
> 2 votes
First be aware that Commerce is still in Alpha, so behavior might change between versions!

I suppose you are looking for something like this from the Drupal Commerce Blog.

I have no idea how to get there as I am awaiting a more stable version of Drupal Commerce, but I suppose the breadcrumb in the image should give you some directions on where to find these settings.

# Answer
> 1 votes
I wanted to address your question Sky Buzz, regarding exposing the 'quantity' field and an 'editable price field' with the 'add to cart form' on product pages.

I posted the below here: https://www.drupal.org/node/2702989#comment-12134795

For posterity, I wanted to post the solution I found here, as I ran in to similar symptoms with Commerce 2.x with D8, only to learn I wasn't looking the right places.

Regarding exposing the quantity field, that is done at Commerce \> Configuration \> Order Item Types \> Default \> Manage Form Display \> the Add to Cart display.

There you can move the quantity field out of the "disabled section"

or here on my site: /admin/commerce/config/order-item-types/default/edit/form-display/add\_to\_cart

as mentioned here: https://drupalcommerce.org/blog/44226/commerce-20-alpha3-released

Regarding price showing up as an editable field, this happens if you move the "Unit Price" field up out of the "disabled" section" on the SAME PAGE mentioned above. So i recommend NOT doing that (not sure in what context that'd be used for, but it's a gotcha for some).

The price output happens on the Product Variation Type manage display or here on my site: /admin/commerce/config/product-variation-types/default/edit/display

There, you can move the Price out of the "disabled section" as it should be by default (or SKU, etc).

# Answer
> 1 votes
Another reason for price not showing may be a disabled `Inject product variation fields into the rendered product.` option for your product type at `/admin/commerce/config/product-types/default/edit`

---
Tags: commerce, 8, entities
---


# Question
Title: How can I rebuild an image field with values in an Ajax callback?
in Drupal 8 I have media form with select box having ajax property and an image field. on select box value change I want to assign specific file to the image field. On form\_alter this code work, the image field received the file and correctly rendered.

```
$form['field_media_image']['widget'][0]['#default_value'] = array('target_id' => "165", 'alt' => 'ttt', 'fids' => ["165"]);

```

but on ajax callback it's not working even if I set value.

```
function myAjaxCallback(array &$form, \Drupal\Core\Form\FormStateInterface $form_state) {
  $form['field_media_image']['widget'][0]['target_id']['value'] = array('target_id' => 165, 'alt' => 'ttt', 'fids' => [165]);
  return $form['field_media_image'];
}

```

Thanks for helping

# Answer
> 0 votes
You cannot alter the form in the Ajax callback. Instead, you must put a check in your form if an Ajax action is triggered and if so, set the default value.

I did this once in D7 and managed to get it to work by doing the following:

1. Give the Ajax button a name attribute.
2. Somewhere in the form, check if `$form_state['input']['_triggering_element_name']` is set and when it matches the name of the Ajax button, alter the $form.

In D8, I think you can get the clicked button with `$form_state->getTriggeringElement()`.

---
Tags: 8, ajax, files
---


# Question
Title: Add "Add new content" custom block to a specific page
I would like to add a block which contain a button for when the user click would redirect to the Add new content page with a specific content type.

I'm building some sort of a book store a would like to let users (Anonymous, Logged-in users) to be able to upload content of a specific type to be featured in that page (once approved of course).

For now, I can only list contents added by admin or anyone with the permission but using the default Add new content menu.

How can I achieve this?

# Answer
If you have already given anonymous and authenticated users permission to create new content of the content type, you can simply add the link in the block.

If you're creating a custom block through the admin interface, you can make the link as you normally would.

For example, if you want to add a link to the **page** content type,

`<a href="/node/add/page">Add a page</a>`

For node content types, the link pattern is `/node/add/CONTENT_TYPE_ID`.

For taxonomy, it's `/admin/structure/taxonomy/manage/TAXONOMY_VOCAB_ID/add`.

The easy way to find these links is to navigate to the add content page and then copy the link.
> 1 votes

---
Tags: 8, blocks
---


# Question
Title: What can I use as replacement for $pager_total_items?
I updated a website to Drupal 8.9.6. I saw that the global `$pager_total_items` was used, but it is deprecated since Drupal 8.8.0.

Ia m looking for an alternative to retrieve the total items of the pager. This was used on a **Search API page**.

The old code is the following one.

```
$variables['count_results'] = empty($GLOBALS['pager_total_items']) ? 0 : $GLOBALS['pager_total_items'][0];

```

After reading The pager has now a backend changeable service, I tried to use the following code.

```
/** @var \Drupal\Core\Pager\PagerManager $pagerManager */
$pagerManager = \Drupal::service('pager.manager');
$pager = $pagerManager->getPager());

```

It seems the Search API module, and `$pager` does not contain the expected pager object.

# Answer
> 3 votes
This works for me:

```
$pager = \Drupal::service('pager.manager')->getPager();
$count_results = $pager->getTotalItems();

```

---
Tags: 8, search
---


# Question
Title: Post update hook fails to run via Drush, but works via update.php
I've implemented hook\_post\_update\_NAME to bulk import some files into Drupal (creating file and media entities for them). This hook runs correctly when I use update.php. But it seems to silently fail via `drush updb`.

My update hooks looks like this

```
/**
 * Creates SVG icons as media entities.
 */
function my_module_default_content_post_update_create_icons() {

  $module_handler = \Drupal::service('module_handler');
  $module_path = $module_handler->getModule('my_module_default_content')->getPath();

  \Drupal::logger('my_module_default_content')->notice('Importing icons from @path', ['@path' => $module_path]);

  $dir = new DirectoryIterator("$module_path/icons");

  \Drupal::logger('my_module_default_content')->notice('Directory contains @count items', ['@count', count($dir)]);

  foreach ($dir as $fileinfo) {
    if (!$fileinfo->isDot()) {

      \Drupal::logger('my_module_default_content')->notice('Importing file @file', ['@file' => $fileinfo->getFilename()]);

      my_module_default_content_create_icon($fileinfo->getPathname());
    }
  }
}

```

This works fine via update.php. All the files are copied, relevant entities created, and messages logged to watchdog. When running `drush updb` I only get

> \[ok\] Update completed: my\_module\_default\_content\_post\_update\_create\_icons
>
> \[success\] Finished performing updates.

None of my log messages are output (while using `--debug` option) to the screen or to watchdog.

My initial thought was a permissions issue, but if it's not outputting any of my log messages. I'm not positive the function is even being run. Adding in a `die()` on the first line of the function gave the exact same output/outcome.

Any ideas on what could cause this to silently fail when running via Drush?

# Answer
For anyone else who runs into this, make sure that the post-update hooks are defined in a `MODULE_NAME.post_update.php` file. It seems as though `update.php` will happily invoke post-update hooks defined in the `MODULE_NAME.install` file, while Drush will not.
> 1 votes

---
Tags: 8, drush
---


title: Export Node as Static HTML in a Zip

text:
# Question
Title: Export Node as Static HTML in a Zip
I have a content type called "Lesson". Lessons have fields like Title, Body, Image, Video, and Topic (term ref).

I would like authors to be able to export any lesson they have created into a Zip that would contain:

* a static html version of their node
* all of the media they have uploaded for the node

I have looked at several export modules, but they seem to mostly export as csv or be designed for re-importing into a drupal site.

They also do not handle media attached to the entity very well.

Any suggestions on where to begin?

# Answer
> 1 votes
You can try this with Tome Drupal Module. Which provides the functionality of exporting site content as Static HTML. By default it doesnt provide option to download as zip. You might need to tinker around to find a way to create zip.

For single page export you can check the discussion in this link.

https://www.drupal.org/project/tome/issues/3184258

---
Tags: 8, nodes, importing-exporting
---


# Question
Title: How to redirect in WebformHandler after submitting Ajax form
I'm trying to redirect to a results page after a form that uses Ajax is submitted. The form is a semi long multi step form, so Ajax is enabled for the user experience.

I have created a new WebformHandler and I'm using the `confirmForm()` method, but I'm having difficulties to make the redirect work. The 'Confirmation' setting in my Webform is set to 'None'. I also don't see errors in the logs.

```
namespace Drupal\burnout_module\Plugin\WebformHandler;

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

/**
 * Send values to the matching API and get results back, redirects to results page
 *
 * @WebformHandler(
 *   id = "matching_api_handler",
 *   label = @Translation("Matching API"),
 *   category = @Translation("Webform Handler"),
 *   description = @Translation("Send values to the matching API and get results back, redirects to results page."),
 *   cardinality = \Drupal\webform\Plugin\WebformHandlerInterface::CARDINALITY_UNLIMITED,
 *   results = \Drupal\webform\Plugin\WebformHandlerInterface::RESULTS_PROCESSED,
 *   submission = \Drupal\webform\Plugin\WebformHandlerInterface::SUBMISSION_REQUIRED,
 * )
 */

class MatchingApiWebformHandler extends WebformHandlerBase {

  /**
   * {@inheritdoc}
   */

  public function confirmForm(array &$form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission) {

    // Get an array of the values from the submission.
    $values = $webform_submission->getData();

    // $result = ... code for calculating results with form values

    $url = \Drupal\Core\Url::fromRoute('burnout.match')->setRouteParameters(array('result' => json_encode($result)));
    $form_state->setRedirectUrl($url);

  }

}

```

I have also tried other possibilities:

* Using a RedirectResponse which gave me a 'Headers already sent' error
* AjaxResponse with a RedirectCommand, nothing happens, no errors

Hopefully someone can point me in the right direction.

Kind regards

# Answer
> 0 votes
I got it working with another approach, instead I used the form\_alter hook and added an ajax submit callback.

See Webform alter with ajax submit callback - field values are empty in callback

---
Tags: ajax, webforms
---


# Question
Title: How can I use Composer with no Internet access?
I need to build and deploy a Drupal 8 site within an on-premise server with no internet access (developer machines have internet access, and access to a private repo).

I would like to avoid committing the whole vendor directory to the codebase, and use composer to build the site.

As far as I am aware, my options are:

1. Commit everything, including third-party modules and the vendor directory
2. Use something like Satis as a local repository and mirror all the necessary dependencies in there, and reference the private Composer repository

Any recommendations on this scenario?

# Answer
I personnaly don't like to commit vendor dependencies. It makes the code review more complicated before a merge request cause the files you need to review are lost in the middle of an ocean of files you don't need to review.

In your case I would have a CI job which would be run on `release` branches and would exec `composer install` then generate a `.tar.gz` file containing all the files (including `/vendor`). That CI job would then push the `.tar.gz` on a repository manager like Nexus. And finally a deploy job in `Jenkins` would get the last hosted release on the repository manager, push it to the final host, untar it and run drush commands to update the site.
> 3 votes

# Answer
It's definitely a lot less work to commit everything. If you take that approach, you're basically already done.

Mirroring the dependencies sounds like a lot of work for little gain. If the concern is to minimize the repository size, you could make two repositories, one slimmed-down repository that just has composer and your custom code, and a second repository that includes all the builds with vendor and everything else. For an example of this approach, see the Terminus Build Tools plugin for Pantheon. This example is hosting-platform specific so it can't be used as-is, but may give you some ideas.
> 1 votes

---
Tags: composer
---


# Question
Title: How to make exposed filters more readable in the URL?
I'm trying to make my URLs a bit more readable (and persistent) which includes query parameters of a view's page. Usually the URL would look like this when I define an exposed filter which is addressed by the parameter `vocabulary-foo`: `https://www.example.com/view?vocabulary-foo[]=1234`. As you might have noticed, this is a filter for taxonomy terms of a specific vocabulary. There are two problems with the usage of IDs in the URL, which I'd like to solve:

* If I uninstall my custom module that creates the taxonomy terms, these are gone and will get another ID when I install the module again. So I can't assume a link to a specific filtered view page would then still be the same.
* It's not readable (and memorizable). Using the term's value instead of the ID would probably already help me. On the other hand, if it is possible to define a query parameter `preset=something` which translates to `vocabulary-foo[]=<The id of the term which has a specific value>`, I'd rather do that as it enables me to combine multiple query parameters to one preset, which makes it shorter.

In my specific case, the view exposes a form which can be used to search for content. A preset as described would pre-select some form controls with only one clean URL parameter.

One idea that came to my mind was somehow using PHP's `$_GET` variable and conditionally changing its content before the view is created. Unfortunately, I don't know which hook would be suitable for that.

Has somebody faced a similar issue in the past? How could I solve these problems in Drupal 9? Thanks!

# Answer
> 3 votes
There's no easy way to do that .. views better\_exposed\_filters is quite nice, but does not provide clean urls. Drupal 7 had query\_parameters\_to\_url, for Drupal 8 they link to a sandbox! project ... This may be a starting point for you.

There may be a simpler approach here: Redirect based on query string using a redirect event subscriber:

```
<?php
    static function getSubscribedEvents()
    {
        $events[KernelEvents::REQUEST][] = array('Redirect', 20);
        return $events;
    }

```

So you could provide at least clean urls to "somewhere".

# Answer
> 0 votes
Assuming you have a term name called "Hello World"

So you want `https://www.example.com/view?vocabulary-foo=hello-world` to work.

```
/**
 * Implements hook_views_pre_view.
 */
function mymodule_views_pre_view(\Drupal\views\ViewExecutable $view, $display_id, array &$args) {
  $term_name = \Drupal::request()->query->get('vocabulary-foo'); // equals hello-world
  if (!empty($term_name)) {
    $args = [];
    $term_name = str_replace('-', ' ', $term_name); // equals hello world
    // get term id from name
    $term = \Drupal::entityTypeManager()->getStorage('taxonomy_term')
      ->loadByProperties(['name' => $term_name, 'vid' => 'vocabulary_foo']);
    $term = reset($term);
    $term_id = $term->id();
    // set argument
    $args[] = $term_id;
  }
}

```

---
Tags: views, hooks, 9
---


# Question
Title: How do I generate PDF content from a node?
We are looking for a way to convert the Drupal pages into PDF on click of a button for D8. Initially we thought we could use Print Module, but that only has a D7 version.

How do you create a button in D8 so that on click, it will convert the Drupal node into a PDF keeping the current theme styling and elements appropriately? We have been unable to find any D8 modules or process that can allow for this.

# Answer
> 7 votes
You can achieve with several solutions

*Use Entity Print Module*

> Entity Print allows you to print any Drupal entity (Drupal 7 and 8) or View (Drupal 8 only) to PDF.
>
> The module is lightweight compared to other modules like the Print module, has full test coverage and is ready to be used in production for both D7 and D8.

*Use new host of print module (Printable Module)*

> This is the new home of the print module. The module makes use of pdf\_api module to generate PDFs.

Use PrintFriendly Module (it supports localization very good)

> The #1 Print and PDF button for your Drupal site. Printer Friendly pages without coding, css, or print.css. Fast, easy, and professional.
>
> The Print Friendly & PDF button saves paper and ink when printing or creating a PDF. It's fast, easy, and looks great when printed. Add the button now, and your users will see the difference.
>
> How Print Friendly & PDF Works The Print Friendly & PDF button automatically creates printer friendly and PDF versions of your pages without the hassle of having to create a print CSS file. No coding, hacking or programming required. Simply install the Print Friendly & PDF plugin, activate, and choose settings for full customization. It also gives your user the ability to remove images and paragraphs of text, so they really only have to print exactly what they want.

*And final solution* is kind of tricky solution, instead of converting the page to PDF just provide a print theme style for your nodes, when a user clicks on the print button (or link) trigger `javascript:window.print()` action. most of the new OS has PDF printer build-in

By the way, I recommend PrintFriendly Module

# Answer
> 1 votes
Having a D8 custom module, a very easy way is:

1. install the mpdf library

```
composer require mpdf/mpdf

```
2. pass your output to mpdf

```
$html = 'content for my pdf';
$mpdf = new \Mpdf\Mpdf(['tempDir' => 'sites/default/files/tmp']);
$mpdf->WriteHTML($output);
$mpdf->Output('file.pdf', 'D');
exit;

```

You should also add mpdf as dependency in your composer.json. See https://www.drupal.org/docs/creating-custom-modules/add-a-composerjson-file

---
Tags: 8, theming, nodes
---


# Question
Title: How do I set the height and width for images that use a responsive images style?
When using the core Image module, the height and width of images are automatically set. But when I use the Responsive Images module and a Responsive Image style, then no height or width is set.

Users don't like this because it makes the website look janky because images can pop into place and change the layout suddenly. Google doesn't like this because it slows down the page. When testing with Lighthouse, it gives the following recommendation:

> Set an explicit width and height on image elements to reduce layout shifts and improve CLS. Learn more

There was also an article in Smashing Magazine this year about setting height and width.

How can I do this in the Responsive Image module?

# Answer
> 6 votes
The code for this is actually pretty simple.

There are a few important points.

1. For this to work, all of the responsive images in a single responsive image style must have the same aspect ratio. They can have different heights and widths, but the aspect ratio must be the same.
2. You have to set the height and width to be the maximum possible (the height and width of the largest image in the responsive image style).

Assuming your responsive image style has a machine name of **hero**, here's some example code:

```
/**
 * Implements hook_preprocess_responsive_image() for MYMODULE.
 *
 * {@inheritDoc}
 */
function MYMODULE_preprocess_responsive_image(&$variables) {
  $style_id = $variables['responsive_image_style_id'];
  if ($style_id === 'hero') {
    // Set the height + width to the aspect ratio for all images.
    // Use the largest possible height + width that may be displayed.
    $variables['img_element']['#attributes']['height'] = 450;
    $variables['img_element']['#attributes']['width'] = 800;
  }
}

```

---
Tags: 8, media, performance
---


# Question
Title: Where is the pager data in the Views object
I am trying to alter the number of items per page in a View, programmatically. When I display the Views object returned in hook\_views\_pre\_execute, I see fields for in $view-\>query for items per page, etc., but despite the view initially having a setting of Display a specified number of items: 6, it appears nowhere in the object, that I can find.

# Answer
In hook\_views\_pre\_execute (hook\_views\_pre\_build is too early), the pager data, in general, can be found at

```
$view->pager

```

and the specific piece of data I asked about can be found at

```
$view->pager->options['items_per_page']

```
> 0 votes

---
Tags: views
---


# Question
Title: How to autoexpand everything on a view translation edit form?
To fully translate a view into one language I have to expand dozens of collapsed panels, most of them with only one or two subelements.

I've reported it here. But is there a quick workaround, like a module or setting that automatically expands all these panels?

I tried using `hook_form_FORM_ID_alter` but changing the `#open` value is ignored (note that it's a top-level Displays panel `#open` which is `true` by default):

```
 /**
 * Implements hook_form_FORM_ID_alter().
 */
function custom_admin_form_config_translation_edit_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  foreach ($form['config_names'] as $key => $config_name) {
    if (substr( $key, 0, 1 ) !== '#') {
      $display = $config_name['display'];
      $display['#open'] = false;
    }
  }
}

```

# Answer
> 0 votes
It's set to closed at https://git.drupalcode.org/project/drupal/-/blob/8.9.x/core/modules/config\_translation/src/FormElement/ListElement.php#L70

by

```
            '#open' => empty($base_key),

```

so I'll just add a patch to composer to change it to

```
            '#open' => true,

```

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


# Question
Title: Adding a variable to a menu twig template
Im trying to use bootstrap for an accordion menu. My issue is that I need unique ID's for each accordion item. I found some similar topics here: Add Unique ID to Menu Item and here: How to add a custom variable that can be accessed on bootstrap's menu--account.html.twig?

Id like to know how I can get a unique ID for each item. Preferably an ID I can store within a variable which I can then pass to the data target attribute. As you can see in my code below, I'm trying to achieve something like that. The issue is that I cannot use the variable in a twig template that I declared within the preprocess function. Help me understand what I'm doing wrong.

Here is my code in my .theme file:

```
function my_theme_preprocess_menu__main(array &$variables) {
    $id = 0;
    foreach ($variables['items'] as $key => $item) {
      $variables['items'][$key]['accordionNav']=[];
      $key_hash = hash('crc32b', $key);
      $variables['items'][$key]['accordionNav'] = $key_hash ;
}
}

```

Here is my twig file menu--main.html.twig:

```
{% import _self as menus %}

{#
  We call a macro which calls itself to render the full tree.
  @see http://twig.sensiolabs.org/doc/tags/macro.html
#}
{{ menus.menu_links(items, attributes, 0) }}
{% macro menu_links(items, attributes, menu_level) %}
  {% import _self as menus %}
  {% if items %}

    {% if menu_level == 0 %}

      <ul{{ attributes.addClass('nav navbar-nav').setAttribute('id', 'accordion') }}>
    {% else %}
      <ul class="sub-menu card-body">

    {% endif %}

    {% for item in items %}

      {%
        set classes = [
          menu_level ? 'sub-item' : 'nav-item',
          item.in_active_trail ? 'active',
          item.below ? 'card',
        ]
      %}
      <li{{ item.attributes.addClass(classes) }}>
        {%
          set link_classes = [
            not menu_level ? 'nav-link',
            item.in_active_trail ? 'active',
            item.url.getOption('attributes').class ? item.url.getOption('attributes').class | join(' '),
            'nav-link-' ~ item.url.toString() | clean_class,
          ]
        %}
        {% if item.below %}
        {% if item.in_active_trail %}
        <div class="card-header" id="heading{{ip}}">
        <button class="btn btn-link" data-toggle="collapse" data-target="{{accordionNav}}" aria-expanded="true" aria-controls="collapse{{ip}}">

          {{ item.title }}
         </button>
         </div>

         <div id="collapse{{ip}}" class="collapse show" aria-labelledby="heading{{ip}}" data-parent="#accordion">
          {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
          {% else %}
          <div class="card-header" id="heading{{ip}}">
        <button class="btn btn-link" data-toggle="collapse" data-target="{{accordionNav}}" aria-expanded="false" aria-controls="collapse{{ip}}">

          {{ item.title }}
         </button>
         </div>

         <div id="collapse{{ip}}" class="collapse" aria-labelledby="heading{{ip}}" data-parent="#accordion">
          {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
         {% endif %}

        </div>
        {% else %}
          {{ link(item.title, item.url, {'class': link_classes}) }}

        {% endif %}

      </li>

    {% endfor %}
    </ul>
  {% endif %}
{% endmacro %}

```

# Answer
> 0 votes
You could use directly the derivative id (which will be unique) of the menu item in twig, with:

```
item.original_link.getDerivativeId()

```

otherwise you need to add a custom unique id in preprocess function to each item, like:

```
function yourtheme_menu_link_alter(&$item) {
  if($item['menu_name'] == 'custom-menu')
  {
    $item['uuid'] = \Drupal\Component\Utility\Html::getUniqueId($item['menu_name']);
  }
}

```

which you then access in twig with:

```
item.uuid

```

---
Tags: 8, theming, bootstrap-theme
---


title: Twig attribues.addclass nesting issue

text:
# Question
Title: Twig attribues.addclass nesting issue
Apologies if this has been asked before, but I'm on my first week working with drupal and twig.

I have the following code:

```
{%
  set container_classes = [
    'paragraph',
    'paragraph--type--' ~ paragraph.bundle|clean_class,
    view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
    not paragraph.isPublished() ? 'paragraph--unpublished',
    'container'
  ]
%}
{% set image_classes = [
  'col-12'
]
%}
{% block paragraph %}

  {% block content %}
    <div{{ attributes.addClass(container_classes) }}>
      <div class='row'>
        <div{{ attributes.addClass(image_classes) }} data-type='image'>
          {{ content.field_two_column_image }}
        </div>
        <div class='col-12 col-lg-auto' data-type='copy'>
          {{ content.field_two_column_copy }}
        </div>
      </div?>
    </div>
  {% endblock %}

{% endblock paragraph %}

```

My issue is the nested attributes.addClass. When I look at the HTML, I'm also seeing the container\_classes classes, which is not what I'm looking for.

So how can I separate the two?

# Answer
`attributes` is a variable containing attributes information (class, id, others..) for the main container of the template.
It should usually be used only once.

You can create a new attribute variable like this :

`{% set my_attribute = create_attribute() %}|`

And you can use it as usual :

```
<div{{ my_attribute.addClass(image_classes).setAttribute('data-type', 'image') }}>
  {{ content.field_two_column_image }}
</div>

```

More information about using the `attributes` variable in Twig templates :
https://www.drupal.org/docs/8/theming-drupal-8/using-attributes-in-templates
https://www.drupal.org/docs/8/theming-drupal-8/modifying-attributes-in-a-theme-file
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Template%21Attribute.php/class/Attribute/8.2.x
> 6 votes

---
Tags: theming
---


# Question
Title: Are there any custom block type template naming conventions?
With our ability to create custom block types and manually add additional fields in Drupal 8, is there a simple naming convention to create block--custom\_block\_type.html.twig to handle the layout of additional fields?

Example: using theme hook suggestions for content types: node--content\_type.html.twig

Are custom block types able to be handled this way without going the module route?

# Answer
> 16 votes
Here's one way to do it, in a module or theme:

```
function MYMODULEORTHEME_theme_suggestions_block_alter(&$suggestions, $variables) {
  $content = $variables['elements']['content'];
  if (isset($content['#block_content']) && $content['#block_content'] instanceof \Drupal\block_content\BlockContentInterface) {
    $suggestions[] = 'block__' . $content['#block_content']->bundle();
  }
}

```

Results in template suggestions like:

`block--custom-block-type.html.twig`

The `instanceof` might be overcautious, take it or leave it.

# Answer
> 2 votes
This page gives a very good overview of drupal 8 naming conventions, also for custom blocks:

Drupal 8 - Template naming conventions

This page says about block templates:

> For example, "block--block--1.html.twig" would be used for the first user-submitted block added from the block administration screen since it was created by the block module with the id of 1. Region-specific block templates are not available in Drupal 8.
>
> If you had a block created by a custom module called "custom" and a delta of "my-block", the theme hook suggestion would be called "block--custom--my-block.html.twig."
>
> Also one more example with Views, if you have a block created by views with a view name "front\_news" and display id "block\_1" then the theme hook suggestion would be: block--views-block--front-news-block-1.html.twig (notice, when you have underscores in a display id or in a view name - you have to transform them in to a single dash)
>
> Be aware that module names are case sensitive in this context. For instance if your module is called 'MyModule', the most general theme hook suggestion for this module would be "block--MyModule.html.twig."

Hope that helps. Have a nice day.

# Answer
> 2 votes
@Cottser answer works. I just modified it to keep the right specificity using `array_splice`, otherwise the bundle type template gets applied later in the chain than block instance suggestions.

```
$suggestion = 'block__' . $content['#block_content']->bundle();
array_splice( $suggestions, 2, 0, $suggestion );

```

There is an issue to fix this in core for all entities

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

# Answer
> 1 votes
A simple/more precise usage with block type along with view mode is as below:

```
/**
  * Implements hook_theme_suggestions_block_alter()
  */
function hook_theme_suggestions_block_alter(&$suggestions, $variables) {
  $content = $variables['elements']['content'];
  if (isset($content['#block_content']) && $content['#block_content'] instanceof \Drupal\block_content\BlockContentInterface) {
    $suggestions[] = 'block__' . $content['#block_content']->bundle() . '__' . $content['#view_mode'];
  }
}

```

# Answer
> 0 votes
Not exactly as you wish, but **Yes**, you just need to stare it carefully.

\*Make sure you have **debugging mode on**. Refer here to turn it on.

In my case, I have created **'Custom Block Type'**

Then created two block of this block type (*Just to confirm*). Assigned them in a region. Then inspect any one of the block. You can see clearly in attached image, there is a template suggestion(marked red) which is common for both the block.

---
Tags: theming, blocks, 8
---


# Question
Title: How to change text format of summary/trimmed field?
Is there a straightforward way to change the summary/trimmed text to "full html" in Drupal 8?

There are workarounds such as creating separate body fields and using them as the summary but I am specifically asking about changing the text format of default summary/trimmed field of "Text (formatted, long, with summary)".

To put it another way, how to I add the CKEditor bar to the summary/trimmed text.

# Answer
You can't, it always has the same format. The field only stores a single format. And it has bugs with ckeditor, as you've found.

I would definitely recommend to use two fields. We'd like to remove the text with summary field type, it's unnecessary complexity but it was too late for 8.x.
> 5 votes

# Answer
Try this in the twig template, works for me.

```
    {% autoescape false %}
      {{ node.body.summary}}
    {% endautoescape %}

```
> 0 votes

# Answer
So the key here is that the summary field will run the text through whatever filters you have enabled for the text format of the long text portion of the field.

I was able to add a `<p>` tag around my summary by enabling the **Convert line breaks into HTML (i.e. \<br\> and \<p\>)** filter.
> 0 votes

---
Tags: 8, wysiwyg, entities
---


# Question
Title: Composer updates .htaccess file when updating
I am using composer with Drupal lightning. If I update Drupal via composer, it updates the .htaccess file.

Is there any way to prevent the .htaccess file from being overwritten?

# Answer
```
 "extra": {
   "drupal-scaffold": {
       "source": "http://cgit.drupalcode.org/drupal/plain/{path}?h={version}",
       "excludes": [ ".htaccess", "robots.txt" ]
       }
}

```

Put this above code in your composer.json file.
> 15 votes

# Answer
While the accepted answer is correct and this prevent the .htacces file from being overwritten, most updates done to that files are linked to security issues. You should patch the file instead, as described in this answer : https://drupal.stackexchange.com/a/271147/25673

Here's a copy of the answer by Stef Van Looveren

> In the `scripts` section of your composer.json file, use the following:
>
> ```
> "post-drupal-scaffold-cmd": [
>   "patch -p0 < patches/htaccess.patch"
> ]
>
> ```
>
> (this requires "drupal-composer/drupal-scaffold" in your `require` section)
> 3 votes

# Answer
One way to append your changes at end of `.htaccess` file once its been updated by scaffold.

`htaccess-custom-changes.txt` contains your custom changes require to add.

```
"drupal-scaffold": {
  "file-mapping": {
    "[web-root]/.htaccess": {
      "append": "patches/htaccess-custom-changes.txt"
     }
}

```
> 2 votes

---
Tags: 8, composer
---


# Question
Title: Use custom content entity theme suggestions in own module?
I have a custom content entity called 'offer'.

I've added `template_preprocess_offer()` and `offer_theme()` to the offer.module file.

```
function offer_theme($existing, $type, $theme, $path) {
  return [
    'offer' => [
      'render element' => 'elements',
    ],
  ];
}

function template_preprocess_offer(array &$variables) {
  foreach (Element::children($variables['elements']) as $key) {
    $variables['content'][$key] = $variables['elements'][$key];
  }
}

```

In *modules/custom/offer/templates/offer.twig.html*, I successfully render the entity.

Next, I've added theme suggestions because I've added a view mode 'full' via the UI.

```
/**
 * Adds template possibility for view modes
 * Implements hook_provider_theme_suggestions_hook_alter
 */
function offer_theme_suggestions_offer_alter( array &$suggestions, array $vars, $hook ) {
  if ( $offer = $vars['elements']['#offer'] ) {
    if (isset($vars['elements']['#view_mode'])) {
      $suggestions[] = 'offer__' . $vars['elements']['#view_mode'];
    }
  }
}

```

After clearing caches:

```
<!-- THEME DEBUG --> <!-- THEME HOOK: 'offer' --> <!-- FILE NAME SUGGESTIONS: * offer--full.html.twig x offer.html.twig --> <!-- BEGIN OUTPUT from 'modules/custom/offer/templates/offer.html.twig' -->

```

This **only** works if I place a offer--full.html.twig inside the **theme's** templates folder. It **doesn't work in the custom module template folder**. Inside *modules/custom/offer/templates*, the template file with the view mode won't get used. While the template suggestions suggests offer--full.html.twig, offer.html.twig is used instead.

Why does it happen? How can I solve it?

**Edit**: I'm on drupal 9. My custom entity has no bundles. I've made sure the id inside @ContentEntityType is "offer".

# Answer
To make a theme suggestion work in the module folder you need an additional theme hook:

```
function offer_theme($existing, $type, $theme, $path) {
  return [
    'offer' => [
      'render element' => 'elements',
    ],
    'offer__full' => [
      'base hook' => 'offer',
    ],
  ];
}

```
> 10 votes

# Answer
> This only works if I place a offer--full.html.twig inside the theme's templates folder.
>
> It doesn't work on the custom module. Inside modules/custom/offer/templates.

My guess, it's because you're using `_alter`.

Since this is your module, you don't need to alter it. Instead use `hook_theme_suggestions_HOOK()`.

```
/**
 * Implements hook_theme_suggestions_HOOK().
 */
function offer_theme_suggestions_offer(array $variables) {
  $suggestions = [];
  $offer = $variables['elements']['#offer'];
  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');

  $suggestions[] = 'offer__' . $sanitized_view_mode;

  return $suggestions;
}

```
> 1 votes

---
Tags: theming, 9
---


# Question
Title: How can I get the customer name in an order confirmation e-mail?
How can I get the customer name from the billing information variable in the commerce-order-receipt.twig.html template file used in the order confirmation e-mail?

# Answer
> 2 votes
First, you have to create function as @NoSSweat suggested (thanks for the hint) and from it get it like:

```
function hook_preprocess_commerce_order_receipt(&$variables)
{
  $givenName = $variables['billing_information']['#profile']->get('address')[0]->given_name;
  $variables['given_name'] = $givenName;
}

```

(was incredible hard to figure this out :) ) Field name for last name would be "family\_name". Checkout the file:

**/modules/contrib/address/src/Plugin/Field/FieldType/AddressItem.php**

for other available fields.

I added this function to my module, but adding it to theme file should also work.

That way you are assigning variable which is now available in twig template so you can print it simple as:

```
{{ given_name }}

```

Don't forget to clear the cache.

---
Tags: 8, commerce, emails
---


# Question
Title: Can I store media files in the private directory?
The normal behavior, described also in Give access to private files to certain role? seem to be the following.

> Once configured, files stored in the private directory are inaccessible via a direct link; however, if Drupal constructs a link to the file, the file will be accessible to anyone who can see the link.

Does it work for media type fields? How can it be configured?

I would like the files to be accessible only from users who authenticate themselves using CAS.

# Answer
It is possible to use private files by default with Media.

You just need to click the Field settings tab for the field you want to store files in your private folder
> 2 votes

# Answer
You can use the private file system with media entities. Users who have permission to view the entity they are attached to will be able to access the files. So if your file is attached to a media entity that is attached to a publicly visible node, the node is public, so the file will be open to anyone. If you add some sort of viewing permissions to the node through a contributed module or something, then the files will only be visible to those users. It is however possible to do custom permissions, using hook\_file\_download().
> 1 votes

# Answer
We have ended up using the protected file module.

File medias chosen to be protected are only accessible to authentified users.

```
[https://www.drupal.org/project/protected_file][1]

```
> 0 votes

# Answer
Currently the only true solution to this is to set permissions by roles on the media entities themselves. I was able to achieve this by using the Permissions by Term module and it's sub-module "Permissions by Entity". Add a Taxonomy field to your media types and configure as appropriate.

Note that that this utilizes content\_access and may require rebuilding permissions. In my experience, if using this at any kind of scale you should also setup Node Access Rebuild Progressive.

Source
> 0 votes

---
Tags: 8, media
---


# Question
Title: Making some Views Exposed Filters auto-submit but not others
**Background**

I'm using **Views** and **Better Exposed Filters** and **Search API**. I have my filters set to '**autosubmit**' so when a user makes a change to a filter it auto-updates the search result.

**What I want to accomplish**

This is cool but I only want the results to auto-update when CERTAIN selections are made. Otherwise I want the user to have to click the 'search button'.

**Example**

For example, I want the user to have to click the 'search button' for some things such as the text boxes and some of the radio buttons, but for SOME of the checkboxes I want the search results to auto-update when a new selection is made.

**Question**

Is this possible programmatically (or I suppose in Views itself) and if so, how?

# Answer
> 4 votes
Gonna add my 2 cents too on the topic, since I recently did my reading-into this topic (autosubmit for exposed filters).

**Related:**

This answer here answers a very similar problem =\> https://drupal.stackexchange.com/a/198274/57183.

**Usefull things to know**

The most important piece of relevant documentation lies inside the ctools/js/auto-submit.js file of CTools, at the top of that file.

**Form API programming**

Following that documentation, you should use the FAPI to programmatically do one of the following:

1. Exclude the specific filters that you don't want to be trigger an autosubmit (if you have autosubmit active, like in your case):

> If you want to exclude a field from the ctool-auto-submit-full-form auto submission, add the class ctools-auto-submit-exclude to the form element. With FAPI, add:
>
> '#attributes' =\> array('class' =\> array('ctools-auto-submit-exclude')),
2. Include the filters that you want to trigger an autosubmit (if you have autosubmit deactivated, not your case)

> On gadgets you want to auto-submit when changed, add the ctools-auto-submit class. With FAPI, add:
>
> '#attributes' =\> array('class' =\> array('ctools-auto-submit')),

After that, you already have the functionality you need.

**Example to the Example**

Following your example here is some example code (with inline comments):

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

  // Assumption: Auto-submit is activated via the Views/BEF configuration for all filters
  // Therefore, we will exclude "the text boxes and some of the radio buttons..."

  $exposed_filters_to_deactivate = array(
    'full_text_search', // a text field
    'field_categories', // a radio button
  );

  foreach($exposed_filters_to_deactivate as $exposed_filter_name) {

    // This will disable auto-submitting the form for our filter element
    $form[$exposed_filter_name]['#attributes'] = array('class' => array('ctools-auto-submit-exclude'));

  }

}

```

This should do it, now the exposed filters full\_text\_search' and 'field\_categories' will not trigger an autosubmit event, all other filters will.

Hope this helps!

**Addendum (follow-up question):**

To get specific checkboxes from a BEF-checkbox group to trigger a form submit, you need to do the following:

Modify you form\_alter implementation:

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

  // Assumption: Auto-submit is activated via the Views/BEF configuration for all filters
  // Therefore, we will exclude "the text boxes and some of the radio buttons..."

  $exposed_filters_to_deactivate = array(
    'full_text_search', // a text field
    'field_categories', // a radio button
    'field_areas_of_interest_checkbox', // a BEF-checkboxes widget
  );

  foreach($exposed_filters_to_deactivate as $exposed_filter_name) {

    // This will disable auto-submitting the form for our filter element
    $form[$exposed_filter_name]['#attributes'] = array('class' => array('ctools-auto-submit-exclude'));

  }

  // This is the name of the select values and their target url
  $bef_checkboxes_autosubmit = array(
    '#area_of_interest_checkbox_1',
    '#area_of_interest_checkbox_3',
  );

  // This will attach a javascript to the checkboxes element
  $form['field_areas_of_interest_checkbox']['#attached']['js'][] = drupal_get_path('module', 'somemodule') . '/somemodule.js';
  $form['field_areas_of_interest_checkbox']['#attached']['js'][] = array(
    'data' => array(
      'bef_checkboxes_autosubmit' => array(
        'form_id' => $form['#id'],
        'checkboxes_ids' => $bef_checkboxes_autosubmit,
      )
    ),
    'type' => 'setting'
  );
}

```

Now, you also need a javascript file (somemodule.js) that will look sth like this:

```
(function($){

Drupal.behaviors.BEFCustomRedirect = {
  attach: function(context, settings) {
    $(settings.bef_checkboxes_autosubmit.checkboxes_ids).each( function( idx ) {
      $('.ctools-auto-submit-exclude.form-checkboxes input' + this).change(function() {
        $('#' + settings.bef_checkboxes_autosubmit.form_id).submit();
      });
    });
  }
}

})(jQuery);

```

# Answer
> 2 votes
Slight modification to existing accepted answer due to changes in BEF.

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

  // Assumption: Auto-submit is activated via the Views/BEF configuration for all filters
  // Therefore, we will exclude "the text boxes and some of the radio buttons..."

  $exposed_filters_to_deactivate = array(
    'full_text_search', // a text field
    'field_categories', // a radio button
  );

  foreach($exposed_filters_to_deactivate as $exposed_filter_name) {

    // This will disable auto-submitting the form for our filter element
    $form[$exposed_filter_name]['#attributes'] = array('data-bef-auto-submit-exclude' => '');

  }

}

```

# Answer
> 0 votes
For selected exposed filter auto-submit, you can use jQuery for those filters something like :

```
// Wait until document fully loaded
jQuery(document).ready(function($) {
    // Check if the filter exists
    if($('.views-exposed-form select').length){
        // Your change function
        $('.views-exposed-form select').change(function() {
            // Submit the form
            $(this).parents('form').submit();
        });
    }
});

```

# Answer
> 0 votes
You can use jQuery to automatically click something (in your case the submit button) when you click a certain div class or id.

For Example:

```
(function($) {
  $( "#clickme, #clickme2" ).click(function() {
     $('.submit-form')[0].click();
  });
})(jQuery);

```

**JS Fiddle Example**

---
Tags: views
---


# Question
Title: flysystem error message. Driver is missing
In my Drupal 8 project, I want to use the **Flysystem module** in order to manage files directly on a remote FTP server.

I installed the module and all external libraries via composer. I also edited settings.php and added the FTP schema based on the README file.

Everything seems to be right, but in the status report, I always see a "Driver is missing" error message.

I don't know what wrong. I searched the Drupal website and module issue page, but I found no solution or guidelines for FTP.

Does any body know how can we use the module with FTP?

# Answer
> 3 votes
## Requirements

If you look at the flysystem.install file (it's currently the same whether you installed 2.0.x or 8.x-1.x), you can see the code used for `flysystem_requirements()`.

The general structure of the checking is as follows:

1. Validate the schemes in settings.php
2. Make sure the dependencies are installed:
a) `League\Flysystem\Filesystem`
b) `League\Flysystem\Replicate\ReplicateAdapter`
c) `Twistor\FlysystemStreamWrapper`
3. Then, it calls `ensure()` on the plugin for each scheme, and makes sure the plugin can be instantiated.

This 3rd step calls this code (**src/FlysystemFactory.php**):

```
  public function getPlugin($scheme) {
    if (!isset($this->plugins[$scheme])) {
      $settings = $this->getSettings($scheme);

      $this->plugins[$scheme] = $this->pluginManager->createInstance($settings['driver'], $settings['config']);
    }

    return $this->plugins[$scheme];
  }

```

It also provides the defaults:

```
  protected $defaults = [
    'driver' => '',
    'config' => [],
    'replicate' => FALSE,
    'cache' => FALSE,
    'name' => '',
    'description' => '',
  ];

```

Given the above information, your plugin and schema should have declared your driver with `'driver' => 'ftp'`.

## Solution?

Also, on the main module page under "supported adapters", it says:

> Ftp (Requires the ftp extension)

Though I'm not sure, since it doesn't link to another module like the other adapters, I think it means the **PHP extension**. Try installing the `ftp` PHP extension. Here's the page for setup instructions.

---
Tags: 8
---


# Question
Title: Why we use dependencies keyword in {theme}libraries.yml ? and not just include the file?
in the **{theme}.libraries.yml** why we need to declare the jquery js or any other library as a **depedency** :

```
  js:
    assets/lib/bootstrap-4.0.0-dist/js/bootstrap.js: {}
    assets/script.js: {}

 dependencies:
     - core/jquery

```

an not just include it for example as a simple js, before all other js that depends on it :

```
  js:
    assets/jquery.js: {} # load dependency library before the dependent libraries.
    assets/lib/bootstrap-4.0.0-dist/js/bootstrap.js: {}
    assets/script.js: {}

```

in the 2nd scenario the js file ex: jquery will be loaded before the other js files.

so what is the difference?

# Answer
A library is a set of files (CSS or JavaScript) which could be local or loaded from another site. Declaring a dependency from another library has the vantage of not requiring to know:

* Which files need to be loaded
* Where those files are located
* Which dependencies that library has

Using a library and declaring its dependencies also means that:

* A file is loaded only once
* There is only a copy of a file for all the modules
* A module that depends from a library doesn't need to update the list of files (which are part of that library) when the library changes its files
> 2 votes

---
Tags: javascript
---


# Question
Title: Why is my custom webform handler, when called via cron, doesn't load and email attachments?
I created a custom webform handler that on postSave adds webform id to the queue:

public function postSave(WebformSubmissionInterface $webform\_submission, $update = TRUE) {

```
$item = array(
  'submission' => $webform_submission,
);

// Add the item to the queue.
$queue_factory = \Drupal::service('queue');
$queue = $queue_factory->get('custom_send_emails');
$queue->createItem($item);

```

} } This is the QueueWorker:

```
/**
 * Send Emails
 *
 * @QueueWorker(
 *   id = "custom_send_emails",
 *   title = @Translation("send emails"),
 *   cron = {"time" = 120}
 * )
 */
class CustomEmailQueue extends CustomEmailQueueBase {}

```

and this is the QueueWorkerBase that on processItem send the email that is build by a custom mail handler:

```
public function processItem($item) {
    $this->custom_send_emails($item['submission']);
  }

  function custom_form_send_emails(WebformSubmissionInterface $submission) {
    $webform = $submission->getWebform();
    $handler = $webform->getHandler('local_email');
    $handler->sendMessage($submission);
  }

```

I have tried everything! When Cron runs, it takes the first item of the queue create the message correctly and send the email with the attachments. Then it continues to the rest of the items and for all of them it doesn't build correct the message. The to\_email is empty. The $attachments array of the $message is empty.

Why does it do that? Why the first item of the queue is send correctly and the rest fail?

With Debug I found that in the first queue item process, it calls from EmailWebformHandler.php the getMessageAttachments() and the getElementsInitializedAndFlattened fetches more elements(the attachments and everything) than in next calls? WHY?

Eventually I found that this segment of code in my local\_email handler causes the problem and I don't understand why. In this handler I want to send the email in the language selected in one specific field. This is why I get the language from the field and then I do this

```
$this->languageManager->setConfigOverrideLanguage($language);

```

that causes the issue!!!

```
 //get communication language
    $values = $webform_submission->getData();
    $language = $this->languageManager->getLanguage($values['communication_language']);
    $this->languageManager->setConfigOverrideLanguage($language);
    $mail_config = \Drupal::config('webform.webform.sme_fund');
    $subject = $mail_config->get('handlers.local_email.settings.subject');
    $subject = $this->replaceTokens($subject, $webform_submission);
    $body = $mail_config->get('handlers.local_email.settings.body');
    $current_langcode = $values['communication_language'];
    $message['subject'] = $subject;
    $message['body'] = $body;

```

# Answer
> 0 votes
If your code works when you don't change langage, that could be that you just forgot to restore the original langage after processing - as it is the same process running, it means that the next item in your queue will be processed with a langage manager set from the previous item which could be different.

Try to do something like :

```
$original_language = $this->languageManager->getConfigOverrideLanguage();
// your processing code
$this->languageManager->setConfigOverrideLanguage($original_language);

```

---
Tags: webforms, cron, queue
---


# Question
Title: How to better search: replacing %20 with +
When I search for "asus laptop type:product" the url is "search/node/asus%20laptop%20type%3Aproduct" but how to make it like "search/node/asus+laptop+type:product". So how to repalce %20 with + and %3A with : on Drupal 7. Thank you.

# Answer
> 0 votes
I don't know what you mean by "better search", as the search works as-is. However, I think the reason it works this way is because `drupal_goto()` eventually calls `drupal_http_build_query()`, which calls `rawurlencode()`. Drupal uses this for URL query parameters. The docs for the function say it returns:

> a string in which all non-alphanumeric characters except -\_. have been replaced with a percent (%) sign followed by two hex digits. This is the encoding described in RFC 1738 for protecting literal characters from being interpreted as special URL delimiters, and for protecting URLs from being mangled by transmission media with character conversions (like some email systems).

https://php.net/manual/en/function.rawurlencode.php

**RFC 1738:** https://www.rfc-editor.org/rfc/rfc1738

To change this, you could create your own module or function that does not does escape `:`. If you use an exposed view search form, it should already encode spaces as `+`.

---
Tags: search
---


# Question
Title: Integrating Drupal into an existing site to manage comments
I am involved in a project that wishes to post a wide range of products, and allows users to review these products. I don't want to use Drupal for the design, layout, etc. I am only interested in using Drupal for managing all of the user generated reviews. Is this integration possible, or recommended?

Could anyone please point me in the right direction for more information about the subject?

# Answer
> 0 votes
Though this is an old question, and it probably depends on what your project is using other than Drupal, from what I hear there are some decent "hybrid" CMS options out there.

You can combine Drupal with NodeJS or AngularJS.

Since you said you don't want Drupal for the design, that is called "**headless/decoupled Drupal**".

Here is some more information: Headless Drupal: The What, Why and How

---
Tags: users, comments
---


# Question
Title: General error: 1366 Incorrect integer value while uploading image
I am using Drupal 7 and I got the following error while uploading an image.

**PDOException: SQLSTATE\[HY000\]: General error: 1366 Incorrect integer value: ''** for column 'field\_third\_section\_image\_width' at row 1:

```
INSERT INTO {field_data_field_third_section_image} (entity_type, entity_id, revision_id, bundle, delta, language, field_third_section_image_fid, field_third_section_image_alt, field_third_section_image_title, field_third_section_image_width,
field_third_section_image_height) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4,
 :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7,
 :db_insert_placeholder_8, :db_insert_placeholder_9, :db_insert_placeholder_10);
     Array ( [:db_insert_placeholder_0] => node
    [:db_insert_placeholder_1] => 107
    [:db_insert_placeholder_2] => 107
    [:db_insert_placeholder_3] => page
    [:db_insert_placeholder_4] => 0
    [:db_insert_placeholder_5] => und
    [:db_insert_placeholder_6] => 12464
    [:db_insert_placeholder_7] =>
    [:db_insert_placeholder_8] =>
    [:db_insert_placeholder_9] =>
    [:db_insert_placeholder_10] => )

    in field_sql_storage_field_storage_write() (line 514 of /mysite/modules/field/modules/field_sql_storage/field_sql_storage.module).

```

Its also give some image related error on recent logs

**Unable to generate the derived image located at public://styles/thumbnail/public/imac1.png.**

Whenever I trying to upload the image and save the node then it gives the following error. I have already given the writable permission to files directory and tmp directory.

Any Idea?

# Answer
You don't have any values for these columns in the SQL query: field\_third\_section\_image\_alt, field\_third\_section\_image\_title, field\_third\_section\_image\_width, field\_third\_section\_image\_height

So there must have something for these fields in order for the query to work. Have a look at the code and see why they are not set.
> 0 votes

---
Tags: 7
---


# Question
Title: Adding accept attribute to managed_file field to specify file types client-side
I've got a Drupal 7 file field in a custom form like this:

```
  $form['image_upload'] = array(
    '#type' => 'managed_file',
    '#title' => t('Image upload'),
    '#description' => t('Upload png images'),
    '#upload_location' => 'public://',
    '#process' => array('file_managed_file_process'),
    '#attributes' => array('accept' => '.png'),
  );

```

As you can see I've added an #attributes array setting the "accept".

1. The accept value doesn't show up in the resulting HTML. I'm surprised it isn't at least set somewhere.
2. If I change the array key from `accept` to `class` then it shows up on the parent div and not on the input element where I expect it.

So, it seems like there are 2 problems to overcome to get to use this feature.

# Answer
Still not sure if this is a bona fide bug; the file\_managed element has several elements inside it, so there's no real way to specify which of those you're targeting with the `#attributes` property.

So in one respect it does make sense that they'd be ignored, because of the ambiguity. But it works for classes, so it makes less sense. Would need a bit more digging to find out why I suspect.

Either way, you can work around it by adding your own process callback to the element:

```
$form['image_upload'] = array(
  '#type' => 'managed_file',
  '#title' => t('Image upload'),
  '#description' => t('Upload png images'),
  '#upload_location' => 'public://',
  '#process' => array('file_managed_file_process', 'MYMODULE_file_managed_file_process'),
);

function MYMODULE_file_managed_file_process($element) {
  $element['upload']['#attributes']['accept'] = '.jpg';
  return $element;
}

```
> 4 votes

# Answer
For drupal 8:

```
    $form['audio-file'] = [
        '#type' => 'managed_file',
        '#title' => 'select file:',
        '#upload_location' => 'private://',
        '#upload_validators' => [
            'file_validate_extensions' => array('mp3 m4a wav'),
        ],
        '#accept'   =>  '.wav,.mp3,.m4a',
    ];

```

It's all...
> 4 votes

# Answer
For drupal 8, something like this will work, when used in a custom module:

```
function my_module_field_widget_form_alter(&$element, FormStateInterface &$form_state, $context) {
  if (isset($element['#field_name']) && $element['#field_name'] === 'my_field_name') {
    $element['#process'][] = 'app_icon_image_file_validate';
    return $element;
  }
}

function app_icon_image_file_validate(&$element, FormStateInterface &$form_state, &$complete_form) {
  $element['upload']['#attributes']['accept'] = '.svg';
  return $element;
}

```
> 2 votes

# Answer
Extending Clive answer.

You can use **hook\_element\_info\_alter** to call always the custom process function:

```

/**
 * Implements hook_element_info_alter().
 *
 * @param $type
 */
function MYMODULE_element_info_alter(&$type) {
  // Custom process managed_file element.
  $type['managed_file']['#process'][] = 'MYMODULE_file_managed_file_process';
}

/**
 * @param $element
 * @param $form_state
 * @param $form
 *
 * @return mixed
 */
function MYMODULE_file_managed_file_process($element, &$form_state, $form){
  if(isset($element['#upload_attributes'])){
    $element['upload']['#attributes'] = $element['#upload_attributes'];
    unset($element['#upload_attributes']);
  }
  return $element;
}

```

In this way, you can use the custom attribute `#upload_attributes` to give every kind of attributes to the inner `upload` element
> 2 votes

---
Tags: 7, forms, files
---


# Question
Title: How to add JavaScript or CSS library to Composer project?
For some cases, there is the need to add a JavaScript or CSS package to a project. One of those cases was the DropzoneJS package for the `drupal/entity_browser`. All recommendations I could read online read like

> 1. Download *manually*
> 2. Install *manually*

or like

> Use Drush

This is not really satisfying as there should be a way without user interaction or working around interaction in setup scripts.

# Answer
> 16 votes
The library can be installed into a custom path by utilizing `extra : installer-paths` to for e.g.:

```
web/sites/libraries/{$name}

```

Additional to that, we define the required package repository with the needed `type` of `drupal-library`. Example `composer.json` for a project:

```
{
    "name"              : "example-composer/example-project",
    "description"       : "Project template for Drupal 8 projects with composer",
    "type"              : "project",
    "minimum-stability" : "dev",
    "prefer-stable"     : true,
    "scripts"           : {
        "post-install-cmd" : "sh ./scripts/composer/post-install.sh"
    },
    "require"           : {
        "composer/installers"       : "^1.0.20",
        "drupal/entity_browser"     : "8.1.0-alpha1",
        "cweagans/composer-patches" : "~1.0",
        "drupal/core"               : "8.0.*",
        "drush/drush"               : "~8.0",
        "drupal/console"            : "~0.9",
        "drupal/devel"              : "dev-8.x-1.x",
        "drupal/entity_browser"     : "8.1.0-alpha1",
        "drupal/inline_entity_form" : "8.1.0-alpha2",
        "drupal/dropzonejs"         : "8.1.*@dev",
        "enyo/dropzone"             : "dev-master"
    },
    "repositories"      : [
        {
            "type" : "composer",
            "url"  : "https://packagist.drupal-composer.org"
        },
        {
            "type"    : "package",
            "package" : {
                "name"    : "enyo/dropzone",
                "version" : "dev-master",
                "type"    : "drupal-library",
                "dist"    : {
                    "url"  : "https://github.com/enyo/dropzone.git",
                    "type" : "drupal-library"
                },
                "source"  : {
                    "url"       : "https://github.com/enyo/dropzone.git",
                    "type"      : "git",
                    "reference" : "origin/master"
                }
            }
        }
    ],
    "extra"             : {
        "installer-paths" : {
            "web/core"                    : [
                "type:drupal-core"
            ],
            ...
            "web/sites/libraries/{$name}" : [
                "type:drupal-library"
            ]
        }
    }
}

```

The `dist` part can be left off and is only needed for `--prefer-dist` cases when installing via `php composer.phar update --prefer-dist` (opposite: `--prefer-source`). To install a **version** and not the latest from the `master` branch, you need to set the version directly at the package to require then from there. Example:

```
"require" : {
    "enyo/dropzone" : "v4.2.*@dev"
},
"repositories" : [
    {
        "type"    : "package",
        "package" : {
            "name"    : "enyo/dropzone",
            "version" : "v4.2.0",
            "type"    : "drupal-library",
            "source"  : {
                "url"       : "https://github.com/enyo/dropzone.git",
                "type"      : "git",
                "reference" : "origin/master"
            }
        }
    }
]

```

# Answer
> 1 votes
An alternative answer, "don't use composer".

We've had pretty good success using a root npm package called "copy-files-from-to" https://www.npmjs.com/package/copy-files-from-to

Example `package.json`

```
{
  "license": "MIT",
  "scripts": {
    "postinstall": "copy-files-from-to"
  },
  "dependencies": {
    "blazy": "^1.8.2",
    "copy-files-from-to": "^2.3.0",
    "select2": "github:select2/select2"
  },
  "copyFiles": [
    {
      "from": "node_modules/blazy/*.js",
      "to": "public/libraries/blazy/"
    },
    {
      "from": "node_modules/select2/dist/**",
      "to": "public/libraries/select2/dist/"
    }
  ]
}

```

---
Tags: javascript, 8, theming, composer
---