# Question
Title: Cloudflare Clear Cache For One URL, Convert Curl Command to Drupal::httpClient() Or php
I am creating a custom module to clear caches on cloudflare for one url. **The original curl command:**

```
curl -X POST "https://api.cloudflare.com/client/v4/zones/123456789/purge_cache" \
     -H "Authorization: Bearer 123456789" \
     -H "Content-Type: application/json" \
     --data '{"files": ["https://example.com", {"url": "https://example.com/my-url"}]}'

```

**Drupal::httpClient**

```
try {
  $client = \Drupal::httpClient();
  $url = "https://api.cloudflare.com/client/v4/zones/123456789/purge_cache";
  $options = [
    'headers' => [
      'Authorization' => 'Bearer 123456789',
    ],
    'json' => [
      'files' => 'https://example.com',
      'url' => 'https://example.com/my-url'
    ],
  ];
  $response = $client->request('POST', $url, $options);
  $code = $response->getStatusCode();
  if ($code == 200) {
    return $code;
  }
}
catch (RequestException $e) {
  watchdog_exception('module_name', $e);
}

```

**php version:**

```
$data = Json::encode(['files' => 'https://example.com', 'url' => 'https://example.com/my-url' ] );
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.cloudflare.com/client/v4/zones/123456789/purge_cache');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$headers = array();
$headers[] = 'Authorization: Bearer 123456789';
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_exec($ch);
curl_close($ch);

```

I got one working by clearing all caches on clouldflare. Original:

```
curl -X POST "https://api.cloudflare.com/client/v4/zones/123456789/purge_cache" \
     -H "Authorization: Bearer 123456789" \
     -H "Content-Type: application/json" \
     --data '{"purge_everything":true}'

```

**The working Drupal Version:**

```
    try {
      $client = \Drupal::httpClient();
      $options = [
        'json' => [
          'purge_everything' => TRUE,
        ],
        'headers' => [
          'Authorization' => 'Bearer ' . $authorization,
        ],
      ];
      $response = $client->request($method, $url, $options);
      $code = $response->getStatusCode();
      if ($code == 200) {
        return $code;
      }
    }
    catch (RequestException $e) {
      watchdog_exception('cloudflare_purge', $e);
    }

```

The drupal version return 200, but it is not doing anything and the php version I could not get it work. I would appreciate any input.

# Answer
> 0 votes
https://api.cloudflare.com/#zone-purge-files-by-url **I found the solution, so this command**:

```
curl -X POST "https://api.cloudflare.com/client/v4/zones/abcdefghijklabcdefghijkl/purge_cache" \
     -H "Authorization: Bearer abcdefghijklabcdefghijkl" \
     -H "Content-Type: application/json" \
     --data '{"files": ["https://example.com", {"url": "https://example.com/url"}]}'

```

**It will be in Drupal like:**

```
      $client = \Drupal::httpClient();
      $options = [
        'headers' => [
          'Authorization' => 'Bearer abcdefghijklabcdefghijkl',
        ],
        'json' => [
          'files' => ['https://example.com/url']
        ],
      ];
      $response = $client->request('POST', $url, $options);
      $data = $response->getBody()->getContents();
      $data = json_decode($data, TRUE);
      if ($data['success']  == TRUE){
        return TRUE;
      }

```

---
Tags: caching, http-request
---


# Question
Title: How does Acquia Dev Desktop create the connection to the database?
I am using Acquia Dev Desktop 2 on my windows 10 PC in order to develop Drupal 8 websites.

As far as I know, every Drupal website requires a connection between its files and the database which is accomplished by using the following code in the setting.php file.

```
$databases = array(
  'default' => array(
    'default' => array(
      'database' => 'databasename',
      'username' => 'sqlusername',
      'password' => 'sqlpassword',
      'host' => 'localhost',
      'port' => '',
      'driver' => 'mysql',
    ),
  ),
);

```

I downloaded Drupal 8 and I imported it in Acquia Dev Desktop 2 using the *Import local Drupal site* option.

>

>

The site is correctly imported and installed; a new database has been created.

I cannot see the above database connection code anywhere in the settings.php file.

I noticed, however, that the following code is added to the bottom of the setting.php file.

```
// <DDSETTINGS>

// Please don't edit anything between <DDSETTINGS> tags.

// This section is autogenerated by Acquia Dev Desktop.

if (isset($_SERVER['DEVDESKTOP_DRUPAL_SETTINGS_DIR']) && file_exists($_SERVER['DEVDESKTOP_DRUPAL_SETTINGS_DIR'] . '/loc_sitename_dd.inc')) {
   require $_SERVER['DEVDESKTOP_DRUPAL_SETTINGS_DIR'] . '/loc_sitename_dd.inc';
}

// </DDSETTINGS>

```

How does Acquia Dev Desktop 2 create the connection between the site's files and the database without using the common database connection code shown above?

When moving my website from the local development server (Acquia Dev Desktop) to a remote server, I must create a connection to the database. Is it safe to delete the code between the `<DDSETTINGS>` tags added by Acquia Dev Desktop 2\*?

# Answer
> 3 votes
Thank you all for your help and point me to the right direction !

I will give a detailed explanation because i believe this will benefit plenty of people with common error as mine !

Acquia Dev desktop 2, while creating/importing you website, will create a hidden file (**loc\_your\_site\_dd.inc**) within its folders where the database connection code is located and then it will refer to that file by adding at the bottom of your setting.php file, few lines of codes similar to:

```
// <DDSETTINGS>

// Please don't edit anything between <DDSETTINGS> tags.

// This section is autogenerated by Acquia Dev Desktop.

if (isset($_SERVER['DEVDESKTOP_DRUPAL_SETTINGS_DIR']) && file_exists($_SERVER['DEVDESKTOP_DRUPAL SETTINGS_DIR'] . '/loc_sitename_dd.inc')) {
require $_SERVER['DEVDESKTOP_DRUPAL_SETTINGS_DIR'] . '/loc_sitename_dd.inc';
}

// </DDSETTINGS>

```

Actually this is not a problem and this is how Acquia Dev desktop handle the database connection and other configuration codes.

However, if you are using **Drush** with your Drupal 8 website but you are using it **from a Git Bash** instead of using the **built-in cmd** inside Acquia Dev Desktop, you will be facing a problem similar to this one:

```
The drush command 'XXX' could not be executed.
[error] Drush was not able to start (bootstrap) the Drupal database.

```

The problem here is that Drush won’t be able to find the which it was added to your sites settings.php file and so it will not be able to find a connection to the database and in result will display the above error.

**SOLUTION:**

The best solution here is to find the hidden file created by Acquia Dev Desktop which is usually in Windows is located at (\*C:\Users\username.acquia\DevDesktop\DrupalSettings\*) and copy and pasted all of its contents to your settings.php file and then from inside the settings.php file, delete the code codes added by Acquia Dev desktop.

Doing so, now Drush will be able to find a connection to the database and all will be working as expected.

# Answer
> 0 votes
You can actually avoid having to paste the database connections into your settings.php for every site you spin up if you just add one environment variable in your user PATH.

**For Windows**:

Go to **Control Panel\All Control Panel Items\System** and click **Advanced System Settings** then click **Environment Variables**. The under **User variables for users** select Path, and click **New**. Now paste the following path variable to the Drupal Settings folder. For me this was:

```
DEVDESKTOP_DRUPAL_SETTINGS_DIR=C:\Users\user\.acquia\DevDesktop\DrupalSettings

```

Now every time you set up a new Drupal 8 site, drush will find the database through the environment variable.

You can find more on this in this article. I just did it manually instead of doing it through the command line. Just remember the article is setting the path to `$HOME` which won't work on windows. :) Hope this helps someone!

---
Tags: 8, database, configuration, acquia-dev-desktop
---


# Question
Title: How can I programmatically get various common user profile related URLs?
I'd like to get the following URLs in Drupal 8:

* /user/register
* /user/login
* /logout
* /user

I already know I can use `\Drupal::service('path.current')->getPath()` to get the current path. I want to build links to redirect users.

How do I get these paths programatically?

# Answer
The user URLs (or routes to be more "Drupal correct") are defined by the core user module (core/modules/user/user.routing.yml)

E.g.

```
user.register:
  path: '/user/register'
  ...

user.login:
  path: '/user/login'
  ...

user.logout:
  path: '/user/logout'
  ...

user.page:
  path: '/user'
  ...

```

So you can programmatically build links to these routes like so:

```
<?php

use Drupal\Core\Link;

// Replace user.login with other routes such as user.page
$user_login_link = Link::createFromRoute(
  t('User log in link'), // The link text
  'user.login', // The link URL generated from the route
);

```
> 2 votes

---
Tags: 8, routes
---


# Question
Title: URL-dependent templates only evaluated once, incorrectly cached
I have a twig template that controls the HTML of the page based off of some URL-specific information. However, this template seems to be evaluated once on the server and then gets cached, never to be evaluated again. The result is that the first page loaded displays the correct information inside this particular block, but every page after that displays the same information as the first page in the block, even though the URLs are obviously different.

To illustrate, page A should have data A loaded on the side in a block, page B should have data B loaded on the side, and so on. If you go to page B first, then you will see data B loaded correctly. However, after that, if you go to page A, you will still see data B loaded on the side, rather than data A. Note that this bug only pertains to the portion of the page that is controlled by the URL-specific logic; the rest of each page loads correctly.

If I go to Home \>\> Administration \>\> Configuration \>\> Development and clear the cache, the next page loads correctly, but then I'm just stuck with a new incorrectly cached chunk of data for all the other pages.

Why is Drupal caching this block whose display is dependent on the URL? More importantly, how can I get rid of this behavior without disabling caching completely?

**Update 1:** I have tried going to the view for the block (Home \>\> Administration \>\> Structure \>\> Views) and under Advanced Settings selecting None for Caching, but this has no effect.

**Update 2:** I don't have a custom block with code to modify, so not sure how to incorporate fixes from questions like this.

# Answer
> 0 votes
As stated you would need a cache context for the block, more specifically the "url.path" cache context. You could add it in a preprocess hook, but it requires some PHP knowledge.

You could try the Blocache module which lets you change the Cacheability metadata for any block. Once enabled, select "Contexts" and check "url.path". Disclaimer: I have not tried this module myself, but it looks like it would solve your problem.

---
Tags: blocks, caching
---


# Question
Title: Using twig, how to show a message on the frontend if a field is empty?
Using twig, I would like to show a message on the frontend if a field is empty. My question refers to a date field, but I think this question could apply to other field types.

In my event content type I have smart\_date field with unlimited cardinality. I do not want to make this a required field, but if the field is empty I want to show a message to visitors. Something like 'No dates are currently scheduled'.

I have created a template file called field--smartdate.html.twig and into this I have pasted the content of field.html.twig my base theme (Bootstrap). Copied below.

```
  {%
    set classes = [
      'field',
      'field--name-' ~ field_name|clean_class,
      'field--type-' ~ field_type|clean_class,
      'field--label-' ~ label_display,
    ]
  %}
  {%
    set title_classes = [
      'field--label',
      label_display == 'visually_hidden' ? 'sr-only',
    ]
  %}

  {% if label_hidden %}
    {% if multiple %}
      <div{{ attributes.addClass(classes, 'field--items') }}>
        {% for item in items %}
          <div{{ item.attributes.addClass('field--item') }}>{{ item.content }}</div>
        {% endfor %}
      </div>

    {% else %}
      {% for item in items %}
        <div{{ attributes.addClass(classes, 'field--item') }}>{{ item.content }}</div>
      {% endfor %}
    {% endif %}
  {% else %}
    <div{{ attributes.addClass(classes) }}>
      <div{{ title_attributes.addClass(title_classes) }}>{{ label }}</div>
      {% if multiple %}
        <div class="field--items">
      {% endif %}
      {% for item in items %}
        <div{{ item.attributes.addClass('field--item') }}>{{ item.content }}</div>
      {% endfor %}
      {% if multiple %}
        </div>
      {% endif %}
    </div>
  {% endif %}

```

I have read Checking for empty fields in Twig templates is complicated And, yes it does seem complicated and I am still unsure what to do.

I have also tried the Empty Fields module but I am hoping this can be done via the theme.

So what changes must I make to the code to display a message if the field is empty?

# Answer
The fact that you are in the field template is proof for a non-empty field. So you need code outside of the field template to show a message. This can be PHP like the module you've linked or TWIG in a different template.

For example:

*node.html.twig*

```
{% if node.field_example.isempty %}
  <p>Field is empty</p>
{% endif %}

```
> 1 votes

---
Tags: 8, theming
---


# Question
Title: How do I make multilangual content synchronization between two sites?
I'm trying to figure out how to synchronize content between 2 sites. Before migration to D8 I was using views data export on site1, and feeds import on site2. My problem is, that in D8 I'm not able to create view where on one row will be English and French content - they can be only two separated rows. But this way I don't know how to set up feeds, to consider these 2 lines as translations of 1 node.

# Answer
**On the source site:**

1. Make sure that your view has a column that contains an unique identifier for the item. This value must be the same for every language of the item.
2. Add a column to the view that contains the language code. For English this would be 'en' and for French this would be 'fr'.

**On the target site:**

3. On the feed type, map the unique identifier either to:

* A non-translatable field;
    * Feeds item: GUID.

And mark that as unique on the feed type.
4. Map to all the fields that you want to map to.
5. Map the langcode value to the "Language" target.

### Known issues

Note that there are some known issues with importing multilingual content using Feeds. I'm doing my best to resolve them.

You can currently run into the following errors:
> 1 votes

---
Tags: views, i18n-l10n, feeds
---


# Question
Title: Iterate through multiple value content field in Twig template
I need to take control over the rendering of a `field_admin_tags` field in a `node.html.twig` template.

This WORKS:

* `{{ content.field_admin_tags }}` — Renders everything (label + all field values)
* `{{ content.field_admin_tags.0 }}` — Renders only the first value in the field, and no label

PROBLEM: I have no control over the markup surrounding the tags, e.g. `<ul><li>...</li></ul>`.

So my idea was to **iterate over the render array**.

But that DOES NOT work:

```
{% for tag in content.field_admin_tags %}
  {{ tag }}
{% endfor %}

```

I get: `Exception: Object of type Drupal\node\Entity\Node cannot be printed`.

I think **I'm iterating over the keys/values of the render array** vs the items inside the field (if I print out an "X" in each loop, I get 20 X's while I only have two or three values in this field).

I'd like to iterate over `content.field_admin_tags.0`, `content.field_admin_tags.1`, etc.

Any idea how to fix this? Thanks.

# Answer
> 25 votes
You can fix this in a field twig. There you can use the existing loop to iterate over the field items:

**node.html.twig**

```
{{ content.field_admin_tags }}

```

**field--field-admin-tags.html.twig**

```
<ul{{ attributes }}>
  {% for item in items %}
    <li>{{ item.content }}</li>
  {% endfor %}
</ul>

```

This example replaces `<div>` with `<ul>`. Don't remove `{{ attributes }}` or bypass the field template, see What can break quickedit, and how do I fix it?

# Answer
> 36 votes
Agree with 4k4 the field template is the best place, if you really want it in the entity template (e.g. node) you can do something like this:

```
{% for key, item in content.field_tags if key|first != '#' %}
  <div class="item-{{ key + 1 }}">{{ item }}</div>
{% endfor %}

```

But honestly I think it's a bit ugly, the field template is the right place.

# Answer
> 18 votes
If you, like me, are looking for a way to iterate through paragraphs on a node's twig template, here is how to do it:

Suppose you have a node with a multivalued paragraph field, so a content editor can create multiple paragraphs and you wish to iterate through each paragraph on the nodes twig template (for example to add a wrapper around each paragraph):

```
{% for key,value in node.my_paragraph_field.value %}
    {{ content.my_paragraph_field[key] }}
{% endfor %}

```

UPDATE: I needed to find another way to print all paragraphs without using content. The content variable contains everything you set up in the 'Manage display' section of the node, but my current work method is to never use 'Manage display' nor layouts since you can actually access all data in the node twig file, and almost all settings you would do on 'Manage display', like applying an image style, or setting a date format, ... you can do directly in twig.

For me this is an advantage because I know that everything I see comes from the twig file, and I do not need to look for some obscure field settings that may add classes somewhere. So everything I see comes from just one place (the nodes twig file) and not a combination of the twig file and the manage display screen.

Anyway, using the awesome Twig Tweak module, here is how to print a multi value paragraph field in a node's twig file without having to use the content variable:

```
{% for item in node.field_paragraphs %}
    {{ drupal_entity('paragraph', item.target_id) }}
{% endfor %}

```

# Answer
> 17 votes
I found a method that is similar to the answer by @chris-ruppel, but a bit more elegant IMHO. It uses the `keys` filter to get an array of available indexes. I use it to build an HTML list.

```
<ul>
  {% for i in content.field_foo['#items']|keys %}
    <li>{{ content.field_foo[i] }}</li>
  {% endfor %}
</ul>

```

# Answer
> 6 votes
I have found the `#items` property to be useful when building loops of unknown length in Twig:

```
print number of values within field:
{{ content.field_admin_tags['#items']|length }}

---

{# remember length in variable (minus 1 because it starts from 0): #}
{% set numTagsIndex = content.field_admin_tags['#items']|length - 1 %}

{# loop until the max value is reached: #}
{% for i in 0..numTagsIndex %}
  {{ content.field_admin_tags[i] }}
{% endfor %}

```

# Answer
> 2 votes
The below also works

```
{% for tag in node.field_tag %}
   {{ tag.entity.name.value }}
{% endfor %}

```

# Answer
> 1 votes
If you want to place additional wrappers around the fields inside the paragraph field or need for some reason a particular paragraph reference field value, you can do the following:

```
{% for key,value in node.paragraph_field_name.value %}

<div class="example-wrapper">
{{ content.paragraph_field_name[key]['#paragraph'].field_content.value }}
</div>

{% endfor %}

```

By doing `{{kint(content.paragraph_field_name[key])}}`, you'll see that the fields are accessible inside the \['#paragraph'\] part of the array.

# Answer
> 0 votes
I needed to iterate a multiple field in twig, what I did was add the value to it.

```
{% for tag in content.field_admin_tags %}
  {{ tag**.value** }}
{% endfor %}

```

This worked for me.

---
Tags: theming, 8
---


# Question
Title: How can I get Slick Slider to display the images?
I have a "test" content type with a title, body, and a media entity field that allows for multiple images. I installed Slick Slider 2.2. I mostly followed the steps outlined here: https://www.ostraining.com/blog/drupal/how-to-use-the-slick-module-in-drupal-8/.

I configured the field to use the Slick Media formatter.

When I add a node with the "test" content type and add two images in the image field, the next/prev buttons appear but I can't see the images. See video of slider animation.

I tried this on two different content types and I also tried using layout builder and got the same result.

I don't see any console errors.

I am running:

* **Drupal**: 8.9.3
* **Slick**: 2.2

# Answer
I accomplished what you're trying to do using Slick Carousel together with Slick Views.

You can create a content-type that you intend to be aggregated into the slideshow. In my case a testimonial type consisting of a background image and overlying text.

You can create a views block and set its format to Slick Carousel. You will be provided with setting options to configure the slideshow as you wish.

Filter your view by the content-type you want to comprise your slideshow, in my case testimonial.

lastly, pull your views block slideshow into another piece of content via entity reference.
> 0 votes

# Answer
For anyone that has a similar issue although it's unlikely, the problem was the SCSS below:

```
.sr-only {
  position: absolute !important; /* Outside the DOM flow */
  height: 1px; width: 1px; /* Nearly collapsed */
  overflow: hidden;
  clip: rect(1px 1px 1px 1px); /* IE 7+ only support clip without commas */
  clip: rect(1px, 1px, 1px, 1px); /* All other browsers */
}

[aria-hidden="true"] {
  @extend .sr-only;
}

```

More specifically, the `position: absolute` line.
> 0 votes

---
Tags: javascript
---


# Question
Title: Why can't I apply patches in the recommended-project?
I just created a new site and I cannot apply the patches with Composer in Drupal 8.9

Here is my composer.json file :

```
{
    "name": "drupal/recommended-project",
    "description": "Project template for Drupal 8 projects with a relocated document root",
    "type": "project",
    "license": "GPL-2.0-or-later",
    "homepage": "https://www.drupal.org/project/drupal",
    "support": {
        "docs": "https://www.drupal.org/docs/user_guide/en/index.html",
        "chat": "https://www.drupal.org/node/314178"
    },
    "repositories": [
        {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        }
    ],
    "require": {
        "composer/installers": "^1.2",
        "drupal/advanced_pwa": "^1.2",
        "drupal/allowed_formats": "^1.3",
        "drupal/antibot": "^1.4",
        "drupal/bootstrap": "^3.23",
        "drupal/bootstrap_basic_image_gallery": "^1.4",
        "drupal/bootstrap_languages": "1.x-dev",
        "drupal/ckwordcount": "^1.1",
        "drupal/commerce": "^2.20",
        "drupal/commerce_checkout": "^2.20",
        "drupal/commerce_marketplace": "1.x-dev",
        "drupal/commerce_pos": "^2.5",
        "drupal/commerce_pricelist": "^2.0@RC",
        "drupal/commerce_recurring": "^1.0@beta",
        "drupal/commerce_reports": "^1.0@beta",
        "drupal/commerce_shipping": "^2.0@RC",
        "drupal/commerce_stock": "^1.0@alpha",
        "drupal/commerce_stripe": "^1.0@RC",
        "drupal/core-composer-scaffold": "^8.8",
        "drupal/core-project-message": "^8.8",
        "drupal/core-recommended": "^8.8",
        "drupal/diff": "^1.0",
        "drupal/entity": "^1.1",
        "drupal/entity_legal": "^3.0@beta",
        "drupal/entity_print": "^2.2",
        "drupal/entity_reference_revisions": "^1.8",
        "drupal/facets": "^1.5",
        "drupal/field_validation": "^1.0@alpha",
        "drupal/flag": "^4.0@beta",
        "drupal/flag_search_api": "^1.4",
        "drupal/flood_unblock": "^3.0",
        "drupal/form_mode_manager": "2.x-dev",
        "drupal/geolocation": "3.x-dev",
        "drupal/group": "^1.2",
        "drupal/image_delta_formatter": "^1.1",
        "drupal/image_widget_crop": "^2.3",
        "drupal/masquerade": "^2.0@beta",
        "drupal/message": "^1.0",
        "drupal/message_notify": "^1.1",
        "drupal/message_ui": "1.x-dev",
        "drupal/metatag": "^1.14",
        "drupal/office_hours": "^1.3",
        "drupal/paragraphs": "^1.12",
        "drupal/pathauto": "^1.8",
        "drupal/poll": "^1.4",
        "drupal/price_difference_formatter": "^1.2",
        "drupal/private_message": "2.x-dev",
        "drupal/private_message_flood": "^1.0@beta",
        "drupal/profile": "^1.1",
        "drupal/pwa": "^1.4",
        "drupal/redirect": "^1.6",
        "drupal/redirect_after_login": "^2.6",
        "drupal/schema_metatag": "^1.7",
        "drupal/search_api": "^1.17",
        "drupal/search_api_autocomplete": "^1.4",
        "drupal/search_api_location": "^1.0@alpha",
        "drupal/search_api_solr": "^4.1",
        "drupal/shariff": "^1.6",
        "drupal/simple_sitemap": "^3.7",
        "drupal/swiftmailer": "^2.0@beta",
        "drupal/token": "^1.7",
        "drupal/tour_ui": "^1.0@beta",
        "drupal/twig_tweak": "^2.6",
        "drupal/upgrade_status": "^2.9",
        "drupal/user_online_status": "^1.0",
        "drupal/views_block_filter_block": "^1.0",
        "drupal/views_bootstrap": "3.x-dev",
        "drupal/views_infinite_scroll": "^1.7",
        "drupal/viewsreference": "^1.4",
        "drupal/webform": "^6.0",
        "drupal/webform_views": "^5.0@alpha",
        "drupal/yoast_seo": "^2.0",
        "drush/drush": "^10.3"
    },
    "conflict": {
        "drupal/drupal": "*"
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "config": {
        "sort-packages": true
    },
    "extra": {
        "drupal-scaffold": {
            "locations": {
                "web-root": "web/"
            }
        },
        "installer-paths": {
            "web/core": [
                "type:drupal-core"
            ],
            "web/libraries/{$name}": [
                "type:drupal-library"
            ],
            "web/modules/contrib/{$name}": [
                "type:drupal-module"
            ],
            "web/profiles/contrib/{$name}": [
                "type:drupal-profile"
            ],
            "web/themes/contrib/{$name}": [
                "type:drupal-theme"
            ],
            "drush/Commands/contrib/{$name}": [
                "type:drupal-drush"
            ],
            "web/modules/custom/{$name}": [
                "type:drupal-custom-module"
            ],
            "web/themes/custom/{$name}": [
                "type:drupal-custom-theme"
            ]
        },
        "patches": {
            "drupal/commerce": {
                "Allow products to be duplicated": "https://www.drupal.org/files/issues/2019-03-26/3042258-2-duplicate-product.patch"
            },
            "drupal/group": {
                "Add a field to view and edit content's groups": "https://www.drupal.org/files/issues/2019-11-13/group-field_to_view_and_edit_content_groups-2813405-215.patch"
            },
            "drupal/commerce_stripe": {
                "Do not run cookies and script stripe on all pages (the RC3 version now tracks all users)": "https://www.drupal.org/files/issues/2020-02-03/3083393-21.patch"
            },
            "drupal/private_message": {
                "The messages are sent and remain in the form": "https://www.drupal.org/files/issues/2020-08-12/private_message-sent_messages_not_clearing-3158769-5.patch"
            }
        },
        "drupal-core-project-message": {
            "include-keys": [
                "homepage",
                "support"
            ],
            "post-create-project-cmd-message": [
                "<bg=blue;fg=white>                                                         </>",
                "<bg=blue;fg=white>  Congratulations, you’ve installed the Drupal codebase  </>",
                "<bg=blue;fg=white>  from the drupal/recommended-project template!          </>",
                "<bg=blue;fg=white>                                                         </>",
                "",
                "<bg=yellow;fg=black>Next steps</>:",
                "  * Install the site: https://www.drupal.org/docs/8/install",
                "  * Read the user guide: https://www.drupal.org/docs/user_guide/en/index.html",
                "  * Get support: https://www.drupal.org/support",
                "  * Get involved with the Drupal community:",
                "      https://www.drupal.org/getting-involved",
                "  * Remove the plugin that prints this message:",
                "      composer remove drupal/core-project-message"
            ]
        }
    }
}

```

If I update my site with this command, the patches are not applied. Same thing if I remove the module to re-download it:

```
ubuntu@ov-KJKJ7:~/www-drupal-com$ composer update --with-dependencies
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
Package container-interop/container-interop is abandoned, you should avoid using it. Use psr/container instead.
Generating autoload files
44 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

```

# Answer
You are missing `cweagans/composer-patches`.

It's mentioned in the docs under Patching projects using Composer.

So simply run `composer require cweagans/composer-patches` once to have it added to your dependencies and then the patches will be applied.
> 4 votes

---
Tags: 8, composer
---


# Question
Title: Replacement for _drush_file_private_path()
I'm trying to get File Permissions working in Drupal 8.9 with Drush 9. The old code calls `_drush_file_private_path()`, which doesn't exist anymore, and `_drush_file_public_path()` is probably a no-go as well.

What is the proper way to do the following in Drush 9?

```
define('DS', DIRECTORY_SEPARATOR);

// Define default paths and variables.
$default = 'sites' . DS . 'default';
$private = $default . DS . 'private';
$files = $default . DS . 'files';
$directories = array();

// Check for Private Files subdirectory.
$private_directory = _drush_file_private_path();
if (empty($private_directory)) {
  $private_directory = $private;
}
$directories[] = $private_directory;

// Check for Public Files subdirectory.
$public_directory = _drush_file_public_path();
if (empty($public_directory)) {
  $public_directory = $files;
}
$directories[] = $public_directory;

```

As an additional note, it would be amazing if a resource existed to see all deprecated/removed functions and their equivalent replacements. I can't even get decent results when using a search engine and the function name.

# Answer
* `_drush_file_private_path()`
* `_drush_file_public_path()`

in the end were just wrapper functions of

* `\Drupal\Core\StreamWrapper\PrivateStream::basePath()`
* `\Drupal\Core\StreamWrapper\PublicStream::basePath()`

And you probably get the same from

* `\Drupal::service('file_system')->realpath('private://')`
* `\Drupal::service('file_system')->realpath('public://')`
> 1 votes

---
Tags: drush
---


# Question
Title: How can I load a custom twig template depending on a view mode?
Currently I have the following code in my module file:

```
function mymodule_theme_suggestions_credit_report(array $variables) {
  return [
    'pdf_report__' . $variables['elements']['#view_mode']
  ];
}

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

```

And I have inside /mymodule/templates/ 2 twig files

1. pdf-report.html.twig (just added the code from entity-html.twig)
2. pdf-report--new-style.html.twig

And I have a view mode in my pdf-report called new\_style.

I've read documentation and it looks like this should work, but it doesn't.

I tried doing the following:

```
function mymodule_theme_suggestions_credit_report(array $variables) {
  return [
    'pdf_report__' . $variables['elements']['#view_mode']
  ];
}

function mymodule_theme($existing, $type, $theme, $path) {
  return [
    'pdf_report' => [
      'render element' => 'elements',
      'template'  => 'pdf-report--orcutt-style',
      'base hook' => 'pdf_report',
    ]
  ];
}

```

But this replaces all of the view modes, not just the one I want.

# Answer
> 1 votes
Now the new theme hook is the same as the base hook. You need to declare the more specific theme suggestion as hook:

```
function mymodule_theme($existing, $type, $theme, $path) {
  return [
    'pdf_report__new_style' => [
      'base hook' => 'pdf_report',
    ],
  ];
}

```

---
Tags: theming
---


# Question
Title: Why am I getting an error message in my dashboard for unprotected private files?
I have a site with Drupal 8.9

Why am I getting an error message in my dashboard for unprotected private files ?

When I go to the link it says this is for Drupal 6 and 7.

```
PRIVATE FILES DIRECTORY
Not fully protected
See https://www.drupal.org/SA-CORE-2013-003 for information about the recommended .htaccess file which should be added to the private:// directory to help protect against arbitrary code execution.

```

https://www.drupal.org/forum/newsletters/security-advisories-for-drupal-core/2013-11-20/sa-core-2013-003-drupal-core

# Answer
> 0 votes
The error, which is reported by `system_requirements()`, means that either that directory doesn't contain any .htaccess file, or that .htaccess file doesn't contain the following lines.

```
<Files *>
  # Override the handler again if we're run later in the evaluation list.
  SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
</Files>

```

Together the lines added from a previous security advisory, they avoid files in that directory can be executed.

```
# Set the catch-all handler to prevent scripts from being executed.
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
<Files *>
  # Override the handler again if we're run later in the evaluation list.
  SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
</Files>

```

Before showing that error message, Drupal tries to create the .htaccess file. (See `HtaccessWriter::write()`.) If it's not able to create it, or write into that file, you should manually create the .htaccess file containing the following lines.

```
# Deny all requests from Apache 2.4+.
<IfModule mod_authz_core.c>
  Require all denied
</IfModule>

# Deny all requests from Apache 2.0-2.2.
<IfModule !mod_authz_core.c>
  Deny from all
</IfModule>

# Turn off all options we don't need.
Options -Indexes -ExecCGI -Includes -MultiViews

# Set the catch-all handler to prevent scripts from being executed.
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
<Files *>
  # Override the handler again if we're run later in the evaluation list.
  SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
</Files>

# If we know how to do it safely, disable the PHP engine entirely.
<IfModule mod_php7.c>
  php_flag engine off
</IfModule>

```

The same lines are shown in the error message contained in the Drupal log.

---
Tags: 8, installation, security
---


title: Sanitization of the q parameter

text:
# Question
Title: Sanitization of the q parameter
I'm using Drupal 7. My question regards the sanitization of the "q" parameter. We know about SQL injection, so I was wondering if this parameter may be a vector for this kind of security flaw. I've searched the Drupal core files for the `$_GET['q']` string. It is used several times but I could't find any kind of sanitization. Perhaps I've missed something.

My opinion is that Drupal does not uses the `$_GET['q']` inside any kind of query or if it does it will be sanitized by the database API itself.

# Answer
Actually, Drupal uses `$_GET['q']` for querying the database, but since it uses its own functions for querying the database, there isn't any risk of SQL injection.

```
function drupal_path_initialize() {

  // Ensure $_GET['q'] is set before calling drupal_normal_path(), to support
  // path caching with hook_url_inbound_alter().
  if (empty($_GET['q'])) {
    $_GET['q'] = variable_get('site_frontpage', 'node');
  }
  $_GET['q'] = drupal_get_normal_path($_GET['q']);

```

`drupal_get_normal_path()` is the function querying the database, via `drupal_lookup_path()`, which contains the following code.

```
      if ($path_language == LANGUAGE_NONE) {
        // Prevent PDO from complaining about a token the query doesn't use.
        unset($args[':language']);
        $result = db_query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language = :language_none ORDER BY pid ASC', $args);
      }
      elseif ($path_language < LANGUAGE_NONE) {
        $result = db_query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language IN (:language, :language_none) ORDER BY language ASC, pid ASC', $args);
      }
      else {
        $result = db_query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND language IN (:language, :language_none) ORDER BY language DESC, pid ASC', $args);
      }

```

On Drupal, you won't find code that sanitizes a value entered from a user to avoid SQL injection when the value isn't used in a database query. You won't find any `$_GET['q'] = sanitize_for_sql_injection($_GET['q']);` line or similar lines.
> 0 votes

# Answer
The request sanitization is an important part of Drupal security. Probably you can find the most important code in the DrupalRequestSanitizer class.

Here you have the sanitize method:

```
 /**
   * Modifies the request to strip dangerous keys from user input.
   */
  public static function sanitize() {
    if (!self::$sanitized) {
      $whitelist = variable_get('sanitize_input_whitelist', array());
      $log_sanitized_keys = variable_get('sanitize_input_logging', FALSE);

      // Process query string parameters.
      $get_sanitized_keys = array();
      $_GET = self::stripDangerousValues($_GET, $whitelist, $get_sanitized_keys);
      if ($log_sanitized_keys && $get_sanitized_keys) {
        _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from query string parameters (GET): @keys', array('@keys' => implode(', ', $get_sanitized_keys))), E_USER_NOTICE);
      }

      // Process request body parameters.
      $post_sanitized_keys = array();
      $_POST = self::stripDangerousValues($_POST, $whitelist, $post_sanitized_keys);
      if ($log_sanitized_keys && $post_sanitized_keys) {
        _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from request body parameters (POST): @keys', array('@keys' => implode(', ', $post_sanitized_keys))), E_USER_NOTICE);
      }

      // Process cookie parameters.
      $cookie_sanitized_keys = array();
      $_COOKIE = self::stripDangerousValues($_COOKIE, $whitelist, $cookie_sanitized_keys);
      if ($log_sanitized_keys && $cookie_sanitized_keys) {
        _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from cookie parameters (COOKIE): @keys', array('@keys' => implode(', ', $cookie_sanitized_keys))), E_USER_NOTICE);
      }

      $request_sanitized_keys = array();
      $_REQUEST = self::stripDangerousValues($_REQUEST, $whitelist, $request_sanitized_keys);

      self::$sanitized = TRUE;
    }
  }

```

There a few more functions but this one is the most important.

As you think sanitizing request input is very important. One of the worst Drupal core issues were related to this (in fact, this file was patched, if I'm not wrong). See "Drupal core - Highly critical - Remote Code Execution - SA-CORE-2018-002" security report.

**Implications**

Given Drupal has a Security Team you don't have to worry about request sanitization unless you develop your own code that deals directly with the request.
> 1 votes

---
Tags: 7, security
---


# Question
Title: Display custom form mode in twig with drupal_entity_form
I am using the form\_mode\_manager module for creating new form modes.

I have currently a new edit form mode which is called applicant, but whenever I add the drupal\_entity\_form function in my twig template, it says:

The "node" entity type did not specify a "applicant" form class.

Does anyone know how to resolve this?

# Answer
You need to create a custom module

Let say you call it `module_name`

In your `module_name.module` file you'll have to use the `hook_entity_type_build()`

```
/**
 * Implements hook_entity_type_build().
 */
function module_name_entity_type_build(array &$entity_types) {
  $entity_types['node']->setFormClass('applicant', 'Drupal\node\NodeForm');
}

```

Then enable your `module_name` module and flush the cache.
> 2 votes

---
Tags: 8
---


# Question
Title: How to add a new join table by using a hook view?
How should we alter a query of a view by using the hook\_views\_query\_alter, by adding a new join table.

I tried

```
 $join = new views_join();

```

but it seems to be for drupal 7 not 8.

Please help.

# Answer
Here is a solution to add a join table to an SQL query in views.

Let's consider a view for a *Person* entity. We want to add a join to a *PersonTag* entity. *Person* has an *id* field (the primary key); *PersonTag* has a *person\_id* field that contains the *PersonTag* ID.

In your module\_name.module, you would add this `hook_views_query_alter()` implementation.

```
function module_name_views_query_alter($view, $query) {
  if ($view->id() == 'views_id') {
    $definition = [
      'table' => 'person_tag_field_data',
      'field' => 'person_id',
      'left_table' => 'person_field_data',
      'left_field' => 'id',
    ];
    $join = Drupal::service('plugin.manager.views.join')->createInstance('standard', $definition);
    $query->addRelationship('person_tag_field_data', $join, 'person');
  }
}

```

After clearing the cache, you could check the SQL query used by the view and notice `INNER JOIN` is added to the query.

*module\_name* is the name of your module, *views\_id* is the ID of your view, *person\_tag\_field\_data* is the table name for the *PersonTag* entity, and *person\_field\_data* is the table name for the *Person* entity.
> 13 votes

# Answer
You can join table using:

```
/**
 * Implements hook_views_pre_execute().
 */
function YOUR_MODULE_views_pre_execute(\Drupal\views\ViewExecutable $view) {
  if ($view->id() == 'VIEWID' && $view->current_display == 'DISPLAY') {
    $input = $view->exposed_raw_input;
    // Views Query.
    $query = $view->build_info['query'];
    // Left Join any table here.
    $query->leftJoin('node__field_comp', 'node__field_comp', 'node_field_data.nid = node__field_comp.entity_id');
    // Add fields of table you joined.
    $query->fields('node__field_comp');
    $query->distinct();
    // Re-construct the Views Query by adding left join.
    $view->build_info['query'] = $query;
    $view->build_info['count_query'] = $query;
  }
}

```
> 4 votes

# Answer
Note that the default join type is a LEFT join when 'type' is not supplied in the join plugin configuration.

For this SQL:

```
INNER JOIN {two} ON one.field_a = two.field_b AND one.field_c = 'some_val'

```

Use this configuration:

```
$configuration = array(
  'type' => 'INNER',
  'table' => 'two',
  'field' => 'field_b',
  'left_table' => 'one',
  'left_field' => 'field_a',
  'operator' => '=',
  'extra' => array(
    0 => array(
      'left_field' => 'field_c',
      'value' => 'some_val',
    ),
  ),
);
$join = Views::pluginManager('join')
  ->createInstance('standard', $configuration);

```
> 1 votes

---
Tags: 8, views
---


# Question
Title: How should a custom configuration entity define a dependency on other configuration?
In a custom module I am defining a defaults Configuration entity that references a role. I would like to define a dependency on the role. This is my first attempt.

```
public function calculateDependencies() {
  $this->dependencies = parent::calculateDependencies();
  $this->addDependency('module', 'user');
  if (isset($this->role_id)) {
    $this->addDependency('config', "user.role.{$this->role_id}");
  }
  return $this; // Also tried return $this->dependencies;
}

```

The Drupal documentation on dependencies references the Block configuration class that looks very similar:

```
  public function calculateDependencies() {
    parent::calculateDependencies();
    $this->addDependency('theme', $this->theme);
    return $this;
  }

```

However I am seeing an error shown below when trying to save the entity.The backtrace indicates it is coming from the attempt to add a dependency on the user module. I chose to add that dependency by taking an example from `system.action.user_add_role_action.administrator`.

> PHP Error: Cannot use object of type Drupal/my\_module/Entity/MyAccessDefaults as array in /app/web/core/lib/Drupal/Core/Entity/DependencyTrait.php on line 32

For example I am trying to test with this code:

```
$values = [
  'id' => 'administrator', 'label' => 'Administrator role grants',
  'grant_type' => 'role', 'role_id' => "administrator",
  'grants' => ['grant_view' => 1]
];
$default_admin_config = \Drupal::entityTypeManager()->getStorage('my_entity')->create($values);
$default_admin_config->save();

```

# Answer
> 1 votes
`ConfigEntityInterface::calculateDependencies` returns `$this`, so this line:

```
$this->dependencies = parent::calculateDependencies();

```

Is causing problems (replacing the dependencies array with the instance of the current class, which is presumably a `MyAccessDefaults`).

Looking at the code, and other core classes which implement `ConfigEntityInterface`, your code should be:

```
public function calculateDependencies() {
  parent::calculateDependencies();
  $this->addDependency('module', 'user');
  if (isset($this->role_id)) {
    $this->addDependency('config', "user.role.{$this->role_id}");
  }
  return $this;
}

```

---
Tags: entities
---


# Question
Title: How to have config from a ConfigFormBase immediately take effect without needing to export it?
I created a simple test module that adds a text banner to all nodes if a checkbox is checked in the form of the modules configuration. Currently it is working halfway as I want.

When the checkbox is checked and the configuration is exported the text banner displays on all nodes.

So far this is correct. But I don't want to have to export the configuration for the text banner to display. I want it to display immediately after checking the checkbox.

An example is in Devel. If you go to the admin area of Devel and check the box 'Display $page array' The page array displays on every node afterwards without having to export the configuration

To display a text banner on all nodes I am using hook\_node\_view. Then getting the checkbox value from my custom module settings.yml file.

```
function my_form_configy_node_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {

  $config = \Drupal::config('my_form_configy.settings')->get('checkbox');

  if ($config === TRUE) {

      $build['layout_test'] = [
        '#markup' => '<h2> Extra, Extra read all about it.</h2>',
      ];
    }
}

```

This is my form

```
namespace Drupal\my_form_configy\Form;

use Drupal\Core\Database\Database;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\ConfigFormBase;

class MyForm extends ConfigFormBase {

  public function getFormId() {
    return 'my_form_configy_1346';
  }

  const SETTINGS = 'my_form_configy.settings';

  protected function getEditableConfigNames() {
    return [
      static::SETTINGS,
    ];
  }

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

  $config = $this->config(static::SETTINGS);

    $check = \Drupal::config('my_form_configy.settings')->get('checkbox');

    $form['checkbox'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Do you want to add the text banner to all nodes? Checking this box will add a large h2 text banner to add nodes. You must export the config and reload a node page'),
      '#default_value' => $check,
      '#weight' => '0',
    ];

    $form['#theme'] = 'my_form';
      return parent::buildForm($form, $form_state);
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    $this->configFactory->getEditable(static::SETTINGS)
      ->set('checkbox', $form_state->getValue('checkbox'))
      ->save();
    parent::submitForm($form, $form_state);
  }

}

```

Devel is using the same method I am, but if you check the box 'Display $page array' the dpm feature works on nodes immediately without having to export the configuration.

```
function devel_page_attachments_alter(&$page) {
  if (\Drupal::currentUser()->hasPermission('access devel information') && \Drupal::config('devel.settings')->get('page_alter')) {
    dpm($page, 'page');
  }
}

```

I have searched for ConfigFormBase in core and contrib modules and read this. https://www.drupal.org/docs/drupal-apis/configuration-api/working-with-configuration-forms and https://www.drupal.org/docs/8/api/form-api/configformbase-with-simple-configuration-api

Update. 4k4 comment below put me in the right place. According to this post https://drupal.stackexchange.com/a/266393/58880. I needed to apply addCacheableDependency

```
\Drupal::service('renderer')->addCacheableDependency($variables, $config);

```

Since I am using hook\_node\_view. I changed $variables to $build

```
\Drupal::service('renderer')->addCacheableDependency($build, $config);

```

Now when I click the checkbox the value of chechbox is correct and its not coming form the config. The text banner is displayed on all nodes. My change is below.

```
function my_form_configy_node_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {

  $config = \Drupal::config('my_form_configy.settings')->get('checkbox');
  // add the cache tag, so that the output gets invalidated when the config is saved
  \Drupal::service('renderer')->addCacheableDependency($build, $config);

```

I am trying to understand what this does? Where is the value of 'checkbox' being stored now. Its not in my modules settings.yml file because I have not exported the configuration yet. Is it stored in browser cache, or Drupal cache? Since I am developing I disabled all twig and drupal cache in settings.local.php with.

```
$settings['cache']['bins']['render'] = 'cache.backend.null';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';

```

The Devel module is not using addCacheableDependency

Clicking the checkbox 'Display $page array' The dpm feature works immediately.

```
function devel_page_attachments_alter(&$page) {
  if (\Drupal::currentUser()->hasPermission('access devel information') && \Drupal::config('devel.settings')->get('page_alter')) {
    dpm($page, 'page');
  }
}

```

# Answer
> 1 votes
`hook_ENTITY_TYPE_view()` is probably the most misunderstood/misused hook in Drupal 8, mainly because it behaves differently than it did in Drupal 7 so you will find many misleading examples which no longer work in the current version of Drupal.

In short, `hook_ENTITY_TYPE_view()` is only called when the entity is being rendered - after the entity has been rendered, core Drupal caches the rendered entity and will use the cached version of the rendered entity.

So by design, `hook_ENTITY_TYPE_view()` will NOT be called again when the rendered entity is loaded from the cache. And specifically it is NOT called every time you visit that node page.

There are all sorts of other ways to do what you want. Since you're already using your own theme function it might be easiest to pass your configuration variable to the Twig template and display/don't display something in the template based on that variable. Another way would be to invalidate the cache when the form is submitted (if the configuration value has changed) so that the node(s) get re-rendered next time they're loaded.

---
Tags: 8, forms, configuration
---


# Question
Title: Embedded views into another view via twig_tweaks, but the results only update after clearing drupal caches
I have a view that needs to embed child views, which I did using the twig\_tweaks module to insert the child view as a field in my parent view, by using a custom text field:

```
{{ drupal_view('my_child_view', 'block_1', arguments.null, tid) }}

```

The first argument `arguments.null` is the group id, which the child views get from the URL

`example.com/group/58/parent-view`

It all works perfectly when i view the results for a given group id. However, when I then open the view for another group id, I get the results for the first queried group id. The results will only change after i delete the Drupal caches. Then I can display the view correctly for any group id, but afterwards, it will again never change the results.

My best guess is that the results of the embedded view are cached? Is there any way to disable this? I tried including `{'#cache': {'max-age': 0}}` into the custom text embedding the child view, but this did not help either.

# Answer
Use the Views Field View module instead.

> There are a lot of cases in views where you want to embed a list inside each row. One example could be, you have a list of groups, and for each groups you want to list the first and last name of all of their members.

Then in the Views UI add view embed as field.
> 0 votes

# Answer
I found an easy solution: just disable the caching for the parent view itself in its advanced settings.
> -1 votes

---
Tags: views
---


# Question
Title: Is it possible to expose custom table data to Views without custom code?
I have a custom table that I'd like to expose to administrators so that they can perform simple searches on the table data. I know I can create a series of custom views handlers for each field, but is there is a way to expose and search through the custom table data without custom coding? I expect there is a contrib module out there that solves this problem, but my Googling has come up dry.

# Answer
> 3 votes
Apparently Views Custom Table does that:

> View custom table module provide you functionality to integrate your custom table data to views, and access all it's column in views. This module use hook\_view\_data to add custom tables in views. this module provides you following functionalities.
>
> 1. Auto integrate custom table data to views
> 2. Auto map mysql data types with drual data types
> 3. Extend relationship of custom table data to drupal entities

---
Tags: 8, views
---


# Question
Title: How can I hide the entity ID on an autocomplete widget?
I have an autocomplete widget for a taxonomy entity reference.

Every term shows its entity ID between parentheses; plus, if the term name contains spaces, it appears between quotes, e.g. *"Lorem ipsum (125)"*.

How do I remove the entity ID and the quotes?

# Answer
> 3 votes
You should have a look on Chosen module.

> Chosen uses the Chosen jQuery plugin to make your elements more user-friendly.

Follow this steps:

1. Install, enable and configure the Chosen module.
2. Change the widget type of your field to "Select list" at Manage Form Display of your content type
3. Check "apply chosen on this field" at Manage Fields \> Edit of your field

# Answer
> 3 votes
Here is an example for Drupal 8, Javascript only solution without the need to install any additional modules - full article can be found here: Hide entity ID on autocomplete field widget in Drupal 8

```
 (function ($, Drupal) {

  'use strict';

  /**
   * Remove entity reference ID from "entity_autocomplete" field.
   *
   * @type {{attach: Drupal.behaviors.autocompleteReferenceEntityId.attach}}
   */
  Drupal.behaviors.autocompleteReferenceEntityId = {
    attach: function (context) {
      // Remove reference IDs for autocomplete elements on init.
      $('.form-autocomplete', context).once('replaceReferenceIdOnInit').each(function () {
        let splitValues = (this.value && this.value !== 'false') ?
          Drupal.autocomplete.splitValues(this.value) : [];

        if (splitValues.length > 0) {
          let labelValues = [];
          for (let i in splitValues) {
            let value = splitValues[i].trim();
            let entityIdMatch = value.match(/\s*\((.*?)\)$/);
            if (entityIdMatch) {
              labelValues[i] = value.replace(entityIdMatch[0], '');
            }
          }

          if (labelValues.length > 0) {
            $(this).data('real-value', splitValues.join(', '));
            this.value = labelValues.join(', ');
          }
        }
      });
    }
  };

  let autocomplete = Drupal.autocomplete.options;
  autocomplete.originalValues = [];
  autocomplete.labelValues = [];

  /**
   * Add custom select handler.
   */
  autocomplete.select = function (event, ui) {
    autocomplete.labelValues = Drupal.autocomplete.splitValues(event.target.value);
    autocomplete.labelValues.pop();
    autocomplete.labelValues.push(ui.item.label);
    autocomplete.originalValues.push(ui.item.value);

    $(event.target).data('real-value', autocomplete.originalValues.join(', '));
    event.target.value = autocomplete.labelValues.join(', ');

    return false;
  }

})(jQuery, Drupal);

```

# Answer
> 0 votes
In addition to the comment of f0ns, you can also use a Entity Reference view display to define the fields you want to search on and how they're displayed. You can use this view as an input for your autocomplete widget.

---
Tags: taxonomy-terms
---


# Question
Title: Problem Trying to upgrade webform to latest version using composer
I've been trying to upgrade webform 5.19 to version 6 using composer but I keep getting this error:

```
Your requirements could not be resolved to an installable set of packages.
Problem 1
drupal/webform_ui 5.19.0 requires drupal/webform 5.19.0 -> satisfiable by drupal/webform[5.19.0] but these conflict with your requirements or minimum-stability.

```

I asked over at the module's help and was to to try here. Has anyone seen this or have an idea what I'm doing wrong?

# Answer
Manually editing composer.json to add `"drupal/webform": "^6.0"` did the trick.
> 2 votes

---
Tags: webforms, composer
---


title: Link video (media_youtube) to node

text:
# Question
Title: Link video (media_youtube) to node
I have a content type called 'webtv' for adding videos from youtube with media, media\_youtube modules. On the webtv page I want to add blocks with video preview image and node title.

My problem is that the video preview image is not linked to the node. I followed the instrunctions of the link but is not working as the field in not output to link

https://www.drupal.org/forum/support/post-installation/2011-12-25/making-preview-images-using-modules-media-and-media-for#comment-5644588

I also tried to use Content:Path and add it later but still not working.

PS. file\_entity\_link is not working because the field is a multimedia asset

Any ideas?

Using media youtube 7.x-3.9 version

# Answer
The way it worked for me was by adding \[path\] at the end of the fields of the view and using css (position: absolute).

The best way would be to rewrite the image as link but never worked so I did it by css.
> 0 votes

---
Tags: 7, media
---


# Question
Title: What does the array_filter key in $form do?
I'm following this tutorial on creating a settings form for a module in Drupal 8. The instructions say to implement the `buildForm` method of `ConfigFormBase` in the following way:

```
  public function buildForm(array $form, FormStateInterface $form_state, Request $request = NULL) {
    $types = node_type_get_names();
    $config = $this->config('rsvplist.settings');
    $form['rsvplist_types'] = array(
      '#type' => 'checkboxes',
      '#title' => $this->t('The content types to enable RSVP collection for'),
      '#default_value' => $config->get('allowed_types'),
      '#options' => $types,
      '#description' => t('On the specified node types, an RSVP option will be available and can be enabled while that node is being edited.'),
    );

    $form['array_filter'] = array('#type' => 'value', '#value' => TRUE);

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

```

Everything here makes sense to me except I can't find any documentation on the role that they `'array_filter'` key in the `$form` variable plays. What does this value do? Where is it documented?

# Answer
Nice catch! It does nothing. You can safely remove it. Looks like some kind of forgotten relict.

Ah, yeah. The same pattern can be found in core's book module: `BookSettingsForm.php`.

And there is a 12(!) years old open issue to have it removed. \[#315176\] Clean-up remains of $form\['array\_filter'\] hack with array\_filter in book module
> 5 votes

---
Tags: 8, forms
---


# Question
Title: Convert Acquia Clear Varnish For One URL Curl Command to Drupal::httpClient()
I am trying to convert a command to php curl or Drupal::httpClient().

The original command

```
Curl -k -X PURGE -H "X-Acquia-Purge:[site-name]" --compressed -H "Host: example.com" https://bal-12345.prod.hosting.acquia.com/my-url

```

Here is the conversion I tried (but it is not working) This one returns 200 status code but it is not working.

```
$varnishUrl = "https://bal-12345.prod.hosting.acquia.com/my-url"
$headers = [
  'X-Acquia-Purge'  => "site-name",
  'Host'            => "example.com"
];
$options = ['headers' => $headers, 'body' => $varnishUrl];
try {
  $client = \Drupal::httpClient();
  $response = $client->request('PURGE', $domainUrl, $options);
  $code = $response->getStatusCode();
  if ($code == 200) {
    return $code;
  }
}
catch (RequestException $e) {
  watchdog_exception('module_name', $e);
}

```

This is the second conversion to php and also not working.

```
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $varnishUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PURGE');
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
$headers = array();
$headers[] = 'X-Acquia-Purge: site-name';
$headers[] = 'Host: example.com';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_exec($ch);
curl_close($ch);

```

I would appreciate any input.

# Answer
I found the solution: https://docs.acquia.com/cloud-platform/performance/varnish/manually-purge/#manually-clearing-caches-for-applications-using-ssl

***PHP way:***

```
    $varnishUrl = 'https://bal-' . $elbDomain . '.prod.hosting.acquia.com' . $nodeUrl;
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $varnishUrl);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PURGE');
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    $headers = [];
    $headers[] = "X-Acquia-Purge: {$xAcquiaPurge}";
    $headers[] = "Host: example.com";
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_exec($curl);
    $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    if ($code == 200) {
      return $code;
      curl_close($curl);
    }
    $errorMsg = curl_getinfo($curl);
    \Drupal::logger('module_name')->error(json_encode($errorMsg));
    curl_close($curl);

```

***Drupal way:***

```
    $varnishUrl = 'https://bal-' . $elbDomain . '.prod.hosting.acquia.com' . $nodeUrl;
    $options = [
         'verify' => false,
         'headers' => [
           'X-Acquia-Purge' => $xAcquiaPurge,
           'Host' => 'example.com',
         ],
       ];
       try {
         $client = \Drupal::httpClient();
         $response = $client->request('PURGE', $varnishUrl, $options);
         $code = $response->getStatusCode();
         if ($code == 200) {
           return $code;
         }
       }
       catch (RequestException $e) {
         watchdog_exception('module_name', $e);
       }

```
> 0 votes

---
Tags: caching, http-request, acquia-cloud
---


# Question
Title: What is the quickest way to dump a node to insert into a test case?
Is there a script, console, drush command etc that can dump a node in the format needed to create a test case?

How can I rapidly fill out

```
$this->drupalCreateContentType(['type' => 'bond',
  'name' => 'Bond',
  'field_bond_amt_issued' => '1000000000',
]);

```

# Answer
You can use drush:

```
drush ev "var_export(\Drupal\node\Entity\Node::load(123)->toArray());"

```

and delete stuff you don't need like uuid, revision\_\*, ...

By the way if you are wondering why does this output old style array syntax, see https://stackoverflow.com/questions/24316347/how-to-format-var-export-to-php5-4-array-syntax

... or paste the output into your IDE and configure it to autocorrect the format.
> 2 votes

---
Tags: testing
---


# Question
Title: How can I auto-rotate an image on file upload in a custom form?
I'm using the FAPI to provide the user an upload field for an image. The field is:

```
$form['product_img'] = [
  '#type' => 'managed_file',
  '#description' => 'Upload a PNG or JPG image of the product.',
  '#multiple' => FALSE,
  '#required' => TRUE,
  '#upload_location' => 'public://',
  '#upload_validators' => [
    'file_validate_is_img' => [],
    'file_validate_extensions' => ['png jpg jpeg']
  ]
];

```

A lot of the users are uploading images taken with their mobile device, resulting in the image in landscape.

The solutions I've seen involve the default file upload widget, but I need something that will automatically rotate the image after the upload.

# Answer
you can try the next code. You will have to create a new image style which rotates the image and then use it in prerendering on image preview.

```
$form['product_img'] = [
  '#type' => 'managed_file',
  '#description' => 'Upload a PNG or JPG image of the product.',
  '#multiple' => FALSE,
  '#required' => TRUE,
  '#upload_location' => 'public://',
  '#upload_validators' => [
    'file_validate_is_img' => [],
    'file_validate_extensions' => ['png jpg jpeg']
  ],
  '#process' => array('custom_managed_file_element_process'),
];

// Process callback

function custom_managed_file_element_process($element, &$form_state, $form) {

  $element = file_managed_file_process($element, $form_state, $form);

  $element['#pre_render'][] = 'custom_managed_file_element_preview';

  return $element;
}

function custom_managed_file_element_preview(array $element) {

  if (empty($element['#file'])) {
    hide($element['remove_button']);
  }
  else {

    $file = $element['#file'];
    hide($element['upload']);
    hide($element['upload_button']);

      $info = image_get_info($file->uri);
      $variables = [
        'alt' => $file->filename,
        'path' => $file->uri,
        'style_name' => 'thumbnail', // change your style name here
        'attributes' => [
          'class' => ['upload-preview'],
        ],
      ];

      if (is_array($info)) {
        $variables += $info;
      }

      $element['preview'] = [
        '#type' => 'markup',
        '#weight' => -150,
        '#markup' => theme('image_style', $variables)
      ];

  }

  return $element;

}

```
> 1 votes

---
Tags: 8, forms, media
---


# Question
Title: PHPUnit testing a method that changes an entity field
Let's say I have an entity with certain fields and a method that does the following

```
public function changeEntityField(Entity $entity) {
  $entity->set('field_xyz', 20);
  $entity->save();
  return $entity;
}

```

I know how to mock an entity and set its field values via `$entity->expects($this->any())->method('get')->with('field_xyz')->willReturn(10)` etc. and pass it to the function to be tested.

What I don't get yet is how to test the function does really set the `field_xyz` to 20 ?

I tried

```
$entity = $this->getMockBuilder(Application::class)
  ->disableOriginalConstructor()
  ->getMock();
$field = $this->getMockBuilder(FieldItemListInterface::class)
      ->disableOriginalConstructor()
      ->getMock();
$field->expects($this->any())
      ->method('__get')
      ->with('value')
      ->willReturn(10);
$entity->expects($this->any())
  ->method('get')
  ->with('field_xyz')
  ->willReturn($field);
$result = $this->service->changeEntityField($entity);
$this->assertEqual($result->get('field_xyz')->value, 20);

```

but it returns 10. How do I mock the -\>set() methods of the entity? Or do I have to work with real entities and not mocks in such cases?

# Answer
> 2 votes
You can't do that in a **unit test**, you have to work with real entities in a **functional test** since `$entity->save();` needs the database to be loaded.

And as `$result = $this->service->changeEntityField($entity);` will return an entity there's no way `$result` can be equal to 10 or 20. It will be equal to an entity. But in a functional test you'll be able to load the entity and check if the field has the good value or not after your function has been called.

---
Tags: testing
---


# Question
Title: How to programatically hide node field on viewing?
Using Drupal 9,

How do I hide a node field when viewing it?

Let's say I have field `info`. I would like to conditionally not display the label or the value.

I assume I use hook\_node\_view\_alter but I'm not familiar with how to manipulate the build render array.

Thanks!

# Answer
You could make use of the **hook\_preprocess**. If its on the specific entity such as the case of a paragraph it will look something like this where I am hiding some labels from a view based on some condition:

```
function [MODULE_NAME]_preprocess_paragraph(&$variables){
    $paragraph = $variables['paragraph'];
    // Get the parent bundle.
    $parentBundle = $paragraph->getParentEntity()->bundle();
    //check View type
    if ($parentBundle && $parentBundle == 'category_views') {
      if ($variables['content']['field_language_name']['#object']->get('field_language_name')->value != 'English') {
       //Removing labels
        unset($variables['content']['field_language_name']);
        unset($variables['content']['field_language']);
      }
    }
}

```
> 1 votes

---
Tags: nodes, 9
---


# Question
Title: How to use presave hook to save a field value as node title?
I have a custom date field in a node type 'day'. When the node is saved (or edited then saved), I would like to get the field\_date value (not the published date) and save it into the title field.

I would like to know how, perhaps using a module to:

hook\_presave

* GET FIELD VALUE
* SET TITLE AS FIELD VALUE
* SAVE NODE

# Answer
You need to implement the hook\_entity\_presave()

```
/**
 * Implements hook_entity_presave().
 */
function YOUR_MODULE_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
  switch ($entity->bundle()) {
    // Here you modify only your day content type
    case 'day':
      // Setting the title with the value of field_date.
      $entity->setTitle($entity->get('field_date')->value);
     break;
  }
}

```
> 21 votes

# Answer
For entity of type profile i have used below code

```
/**
 * Implements hook_entity_presave().
 */
function YOUR_MODULE_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
  if ($entity->getEntityType()->id() == 'profile') {
    $zipcode = $entity->field_zip_code->value;
    $url = "http://maps.googleapis.com/maps/api/geocode/json?address=".$zipcode."&sensor=false";
    $details=file_get_contents($url);
    $result = json_decode($details,true);
    $lat=$result['results'][0]['geometry']['location']['lat'];
    $lng=$result['results'][0]['geometry']['location']['lng'];
    $entity->field_geolocation->lat = $lat;
    $entity->field_geolocation->lng = $lng;
 }
}

```
> 5 votes

# Answer
For entity of type user

```
/**
 * Implements hook_entity_presave().
 */
function YOUR_MODULE_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
  $entity->field_uhid->value = 'testing';     //set value for field
}

```
> 4 votes

# Answer
This worked for me to get and set the date field value using presave hook based on content type

```
/**
 * Implements hook_entity_presave().
 */

function YOUR_MODULE_global_entity_presave(Drupal\Core\Entity\EntityInterface $entity)
{
  if ($entity->bundle() == 'blog') {
    $published = $entity->get('created')->value;
    $entity->set('field_published_date', date('Y-m-d\TH:i:s', $published));
 }
}

```
> 1 votes

# Answer
You can alter and save the title to any available field using Automatic Entity Label https://www.drupal.org/project/auto\_entitylabel
> 0 votes

---
Tags: nodes, 8, hooks, entities
---


# Question
Title: How do I populate report page using a controller?
I'm following this tutorial on creating a report page for a custom plugin, but note that I'm using Drupal 9, and not Drupal 8 as per the tutorial.

I've created a `report()` method inside my implementation of `ControllerBase`:

```
<?php
/**
 * file
 * Contains \Drupal\rsvplist\Controller\ReportController
 */

namespace Drupal\rsvplist\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Database;
use Symfony\Component\HttpFoundation\Response;

/**
 * Controller for RSVP List Report
 */

class ReportController extends ControllerBase {

  /**
   * Gets all RSVPs for all nodes.
   *
   * @return array
   */
  protected function load() {
    $select = Database::getConnection()->select('rsvplist', 'r');

    // join the users table, so we can get the entry creator's username
    $select->join('users_field_data', 'u', 'r.uid = u.uid');

    // join the node table, so we can get the event's name
    $select->join('node_field_data', 'n', 'r.nid = n.nid');

    // Select the specific fields for the output
    $select->addField('u', 'name', 'username');
    $select->addField('n', 'title');
    $select->addField('r', 'mail');

    $entries = $select->execute()->fetchAll(\PDO::FETCH_ASSOC);

    return $entries;
  }

  /*
   * Creates the report page
   *
   * @return array
   *   Render array for report output.
   */
  public function report() {
    $headers = [
      t('Name'),
      t('Event'),
      t('Email'),
    ];

    $rows = [];
    foreach ($this->load() as $entry) {
      // sanitise each entry
      $rows[] = array_map('Drupal\Component\Utility\SafeMarkup::checkPlain', $entry);
    }

    return [
      ['table'] => [
        '#type' => 'table',
        '#header' => $headers,
        '#rows' => $rows,
        '#empty' => t('No entries available'),
      ],
      ['message'] => [
        '#markup' => t('Below is a list of all Event RSVPs including username, email address and the name of the event they will be attending.'),
      ]];

  }
}

```

My routing file seems to be set up correctly since I see the link to the report page:

However, when I navigate to the report page, I just see a blank page;

I thought perhaps I'm supposed to return a `HTTPFoundation\Response` object, so I tried this;

```
$response = new Response();
$response->setMaxAge(0);
$response->setContent('hello world');

return $response

```

But that seemed to have the effect of completely nuking the HTML of my page and just printing "hello world" to the screen with all menu items gone, so clearly that's not correct either. What am I doing wrong here? Better yet, where should I go to learn about how to do this correctly?

# Answer
> 2 votes
A controller needs to return a render array for the page content. It is explained in Routing API and page controllers / Route controllers for simple routes.

> The only requirement is that the method specified in your \*.routing.yml file returns:
>
> * A render array (see the Theme and render topic for more information). This render array is then rendered in the requested format (HTML, dialog, modal, AJAX are supported by default). In the case of HTML, it will be surrounded by blocks by default: the Block module is enabled by default, and hence its Page Display Variant that surrounds the main content with blocks is also used by default.
> * A `\Symfony\Component\HttpFoundation\Response` object.

It's exactly what `DbLogController::overview()`, the controller method for the *Recent log messages* (/admin/reports/dblog) route, does.

```
  $build['dblog_table'] = [
    '#type' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#attributes' => [
      'id' => 'admin-dblog',
      'class' => [
        'admin-dblog',
      ],
    ],
    '#empty' => $this->t('No log messages available.'),
    '#attached' => [
      'library' => [
        'dblog/drupal.dblog',
      ],
    ],
  ];
  $build['dblog_pager'] = [
    '#type' => 'pager',
  ];
  return $build;

```

(The Database Logging module also adds a pager, which is helpful when the rows to show could be too much, or they would make the rest of the page rendered too low in the page.)

What is wrong in your code is that it uses an array containing a string as array index, instead of a string. Any PHP version that supports the short array syntax would throw Fatal error: Illegal offset type. (The other versions would throw *Parse error: syntax error, unexpected '\['* since they don't support the short array syntax.)

The return instruction should be the following one.

```
    return [
      'table' => [
        '#type' => 'table',
        '#header' => $headers,
        '#rows' => $rows,
        '#empty' => t('No entries available'),
      ],
      'message' => [
        '#markup' => t('Below is a list of all Event RSVPs including username, email address and the name of the event they will be attending.'),
      ]
    ];

```

---
Tags: 9
---


title: JS scripts not loading on certain pages

text:
# Question
Title: JS scripts not loading on certain pages
When logged in as a user (not admin), some JS scripts do not load on certain pages.

I found out about this issue because I am using the module EU Cookie Compliance and the scripts it uses (`eu_cookie_compliance.js`, `jquery.cookie.shim.js`, `js.cookie.min.js`) aren't always loaded.

I am using a JS method provided by the EU Cookie Compliance module in my custom theme and found out it triggered an error on some pages (because the scripts aren't loaded).

For example, the scripts load on `/user/2` but don't on `/user/2/orders` or `/user/2/customer` as you can see on the below image. **Why does this happen?**

I can see no option in EU Cookie Compliance module that prevents loading the script on some pages. Nor did I find anything in the code.

### Edit:

I have now included `eu_cookie_compliance` as a dependency in my theme:

```
dependencies:
  - core/drupal
  - core/jquery
  - core/jquery.once
  - core/drupalSettings
  - eu_cookie_compliance/eu_cookie_compliance
  - eu_cookie_compliance/eu_cookie_compliance_bare

```

And this fixed the fact that the scripts weren't loaded on all pages. That said, I now have errors on these specific pages.

All I do in my theme's JS (`radix_sub.script.js`) is using `Drupal.eu_cookie_compliance.hasAgreed()` which now triggers the following errors:

I have tried declaring only `eu_cookie_compliance` and only `eu_cookie_compliance_bare` and both in my theme libraries, and the errors are identical.

# Answer
I don't know why it's not loading on some pages, but ultimately it's because the library isn't required for those pages. If a module's library is required by your theme then you need to declare it as a dependency.

You can do this for your library in your theme's *libraries.yml* file. See the Declaring dependencies documentation.

```
# my_theme.libraries.yml
# It's not clear if you want the bare or full cookie compliance library
my_library:
  js:
    js/my_libary.js: {}
  dependencies:
    - eu_cookie_compliance/eu_cookie_compliance
    - eu_cookie_compliance/eu_cookie_compliance_bare

```
> 1 votes

---
Tags: 8, commerce, javascript
---


# Question
Title: How to flag an entity when it is created or updated?
I have a Drupal 8 site with the Flag module.

I want when a user creates or updates a node, product, store, group, ... the updated entity is flagged.

How to flag an entity when it is created or updated ?

I'm testing the "Rules" module which is finally (usable) in production.

But how do you flag down a new entity when it is created ?

What should be put in "Action", because it is no longer like in Drual 7 with an interface.

# Answer
> 1 votes
You can use HOOK\_entity\_presave to trigger when node gets created. I updated code for you. Make sure that you change the capital letters to correct values.

```
function MODULENAME_entity_update(Drupal\Core\Entity\EntityInterface $entity) {
  // Check which content type would you like to flag.
  // You can use https://www.php.net/manual/en/function.in-array.php to check for
  // multiple content types
  if (in_array($entity->bundle(), ['mycontentype1', 'mycontentype2'])) {
    $flag_id = 'yourflagname';

    $flag_service = \Drupal::service('flag');
    $flag = $flag_service->getFlagById($flag_id);

    // Flag an entity with a specific flag.
    // https://www.drupal.org/docs/drupal-apis/entity-api/introduction-to-entity-api-in-drupal-8
    $flag_service->flag($flag, $entity);
  }
}

```

---
Tags: 8, entities, flags
---


# Question
Title: How do I install core on Windows 10 with Nginx server?
I Want to install Drupal 8 on Windows 10 with nginx server. I do know how to install with Apache using XAMPP.

I use PHP 7.2, Microsoft SQL as the db.

I installed nginx 1.18.0 and PHP in C:/

I connected them with php-cgi -b 127.0.0.1:9000

my root file for the server is C:/nginx/html.

I copied the extracted drupal file to the C:/nginx/html/ folder. In the internet explorer i try to run the installation of drupal, 403 forbiden appear.

So how do I install Drupal 8 on Windows 10 with nginx server.??

my nginx configuration is:

#user nobody; worker\_processes 1;

#error\_log logs/error.log; #error\_log logs/error.log notice; #error\_log logs/error.log info;

#pid logs/nginx.pid;

events { worker\_connections 1024; }

http { include mime.types; default\_type application/octet-stream;

```
#log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
#                  '$status $body_bytes_sent "$http_referer" '
#                  '"$http_user_agent" "$http_x_forwarded_for"';

#access_log  logs/access.log  main;

sendfile        on;
#tcp_nopush     on;

#keepalive_timeout  0;
keepalive_timeout  65;

#gzip  on;

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    location / {
        root   html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    location ~ \.php$ {
        root           html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
#    listen       8000;
#    listen       somename:8080;
#    server_name  somename  alias  another.alias;

#    location / {
#        root   html/ltts;
#        index  index.html index.htm;
#    }
#}

# HTTPS server
#
#server {
#    listen       443 ssl;
#    server_name  localhost;

#    ssl_certificate      cert.pem;
#    ssl_certificate_key  cert.key;

#    ssl_session_cache    shared:SSL:1m;
#    ssl_session_timeout  5m;

#    ssl_ciphers  HIGH:!aNULL:!MD5;
#    ssl_prefer_server_ciphers  on;

#    location / {
#        root   html/ltts;
#        index  index.html index.htm;
#    }
#}

```

}

# Answer
You can use Laragon https://laragon.org it's a dead-simple configuration and you can install a blank drupal 8 projects (+ tons of other options).

If you are more advanced user you can use Docker or Vagrant. I would prefer Docker-based (Lando, Docksal...)
> 1 votes

---
Tags: 8, installation
---


title: Module uninstall dependencies

text:
# Question
Title: Module uninstall dependencies
I'v got a question regarding dependencies & configuration. I created a module providing a content type, field type, widget & formatter.

* While wanting to uninstall the module, I get the following message:

> The following reason prevents `module` from being uninstalled:
>
> + Fields type(s) in use
* So I go to structure, try to delete the content type & get the following:

> `module's content type` is used by `x` pieces of content on your site. You may not remove `module's content type` until you have removed all of the `module's content type` content.
* I go delete all my nodes first as it seems this needs to be done first. I retry uninstalling the module & get message:

> Fields pending deletion
* I run cron & am now able to uninstall my module with message:

> The following modules will be completely uninstalled from your site, and all data from these modules will be lost!

I can see that dependencies are met well, but this gives it a long run before one can uninstall a module. Is there a way I can keep dependency integrity while once I am willing to uninstall the module to automatically remove configuration & content from start till end dependency?

# Answer
You can, if you write the code for doing that yourself. Core currently doesn't offer a way to do that automatically.

See Impossible to uninstall Flag and the linked issue for Simplenews for inspiration.
> 5 votes

# Answer
Google sent me to this page when I was searching for `uninstall module drupal 8 "Fields pending deletion"`. I was unable to uninstall Feeds module with the message `Fields pending deletion`.

**The solution was to run the cron several times**.

See this.
> 3 votes

# Answer
The problem with cron is that you might have to run it very often, and it might only start to work after fix hours.

But here's how to force Drupal to clear out fields pending deletion:

`drush php:eval 'field_purge_batch(50000);'`

You may need to provide an even bigger value. When this command returns quickly, uninstall will work.
> 0 votes

---
Tags: 8, configuration
---


# Question
Title: What is the correct way to set cache contexts on custom blocks?
I have run into an issue where a block that should be unique per page isn't for logged-out users. The issue is a custom block plugin I have on a views search page that contains custom filters (sort of like a custom replacement for exposed filters. the block placed through /admin/structure/block).

Based on what I have learned about Drupal 8, I added the cache contexts to my build array:

```
  public function build() {

    $search_form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\SearchForm');
    return [
      'search_form' => $search_form,
      '#cache' => ['contexts' => ['url.path', 'url.query_args']]
    ];

  }

```

But it seems this must be incorrect because when logged-out, the block would get cached on the first view, and when the url changed, it wasn't showing a new version of the block.

I thought it might be the view page that was causing the issue, but even when I turned caching off on the view page, the issue remained.

I was able to fix the issue several ways, for example, by using a preprocess\_block hook:

```
function mymodule_preprocess_block__mycustomsearchblock(&$variables) {
  $variables['#cache']['contexts'][] = 'url.path';
  $variables['#cache']['contexts'][] = 'url.query_args';
}

```

But it bothered me I couldn't just put the cache contexts into my block's build array.

Since my block extends BlockBase, I decided to try out the getCacheContexts() method, especially since I saw some modules within core are doing it this way.

```
  public function getCacheContexts() {
    return Cache::mergeContexts(parent::getCacheContexts(), ['url.path', 'url.query_args']);
  }

```

This is also fixed the issue, but interestingly, when I output the variables in the preprocess block function, these are not showing in $variables\['#cache'\]\['contexts'\], but they do show in $variables\['elements'\]\['#cache'\]\['contexts'\]

```
array:5 [▼
  0 => "languages:language_interface"
  1 => "theme"
  2 => "url.path"
  3 => "url.query_args"
  4 => "user.permissions"
]

```

I'm trying to figure out how this works, and why it wasn't working from the build function.

Looking at /core/modules/block/src/BlockViewBuilder.php at the viewMultiple() function, it looks like it pulls the cache tags from the entity and the plugin:

```
'contexts' => Cache::mergeContexts(
  $entity->getCacheContexts(),
  $plugin->getCacheContexts()
),

```

So that explains why adding a getCacheContexts() method to my block plugin adds the contexts to my block. Also, looking at the preRender method in the same class, it looks like it doesn't use the cache array in the blocks build function, which confuses me, as it seems the way to add caching in Drupal 8 is to add a #cache element to render elements.

So my question is,

1) Are cache contexts added directly on the array in a block plugin ignored?

2) If so, is there a way around that, do we need to add it to a child element of the build array?

3) If context added directly is ignored, is adding a getCacheContexts() the way to go for block plugins in custom modules?

# Answer
> 15 votes
In most cases, you just set the cache context directly on the render array you return in your build() method.

I have finally found what my issue was, with the help of @Berdir and @4k4. If you are using a custom template, such as block--myblock.html.twig and you output the variables individually, such as {{ content.foo }} instead of all at the same time like {{ content }}, it ignores your cache contexts passed directly into your block build array, when logged out. See What is the correct way to set cache contexts on custom blocks?

So, to answer the original question:

1) Cache contexts passed directly into a custom block plugin are sometimes ignored. You can test this by altering the SyndicateBlock, and then creating a custom template in your theme block--syndicate.html.php in which you output the variables individually like this:

```
{% block content %}
  {{ content.foo }}
{% endblock %}

```

As you change the url arguments, you'll see the block doesn't respect the cache context.

Now if you change it output all the content as a piece, it works:

```
{% block content %}
  {{ content }}
{% endblock %}

```

Now, it respects the cache context, and the block is unique per page.

2) For now, to work around this, you can just output what's in your block in it's own template.

```
 public function build() {

    $search_form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\SearchForm');
    return [
      '#theme' => 'mycustomtemplate',
      '#search_form' => $search_form,
      '#cache' => ['contexts' => ['url.path', 'url.query_args']]
    ];

  }

```

This circumvents the block module's esoteric caching exceptions and your form is now unique per page when logged out.

3) Should you create your own theme template to fix this, or just add a method for getCacheContexts() in your custom Block plugin? It's better to create a new theme template, rather than add a getCacheContexts() method that overrides the natural order of bubbling up of cache contexts, and may break metadata deeper in your build array.

# Answer
> 8 votes
For anyone else who finds this...

The reason that rendering `content` (or `content|without()`) works is that there is an element in the render array `content['#cache']` that contains all of the cacheable metadata for the content.

If you do not allow this to be rendered in twig, either `content` or `{{'#cache': content['#cache']|render }}`, the page **does not know it has cacheable metadata** (eg. it never bubbles up).

Sounds like you are not doing custom twig though. If you are using something like Varnish, that could also be a culprit for anonymous users.

# Answer
> 4 votes
I also ran into this issue and the workaround I came up with was to create a new block\_content variable based on a filtered version of the main content variable excluding any custom fields I want to render manually:

```
{% set block_content = content|without('field_mycustomfield', 'field_mycustomfield2') %}

```

Then instead of rendering the "content.body" variable directly later, I call:

```
{{ block_content }}

```

If you want to render every field individually, you can just keep adding them to the "without" filter so that rendering block\_content doesn't do anything except fix caching.

# Answer
> 2 votes
When using cache contexts for **anonymous users**, be sure to **disable** the *internal page cache module*, as mentioned in cache context documentation.

It took me while to figure this out as well :-)

# Answer
> 1 votes
The easier method to achieve this is by declaring and defining the `getCacheContexts()` method

```

  public function build() {

    $search_form = \Drupal::formBuilder()->getForm('Drupal\mymodule\Form\SearchForm');
    return [
      'search_form' => $search_form
    ];

  }

  /**
   * {@inheritdoc}
   */
  public function getCacheMaxAge() {
    // If you need to redefine the Max Age for that block
    return 0;
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    return ['url.path', 'url.query_args'];
  }

```

Check out the CacheableDependency documentation, it should contains everything you need ;)

---
Tags: 8, blocks, caching
---


title: Get base URL in a custom block

text:
# Question
Title: Get base URL in a custom block
How can I get the base URL in the custom block?

# Answer
> 0 votes
First of all, don't prepend the base url by hand, use the core PHP function file\_create\_url or TWIG file\_url:

```
<img src="{{ file_url('core/modules/image/sample.png') }}" />

```

And then, as commented, you can't use Twig out-of-the-box in Ckeditor. You need to install a module like Twig Input Filter and enable the Twig filter in /admin/config/content/formats for your text format.

---
Tags: 8, blocks
---


# Question
Title: Custom contraint validator: show an error message with a link
We use a custom constraint on a custom entity type. In this entity type we have a string field "url basis" which is used to create aliases for many kinds of pages and data related to this entity.

Therefore it is important that this url basis is unique with every single entity. Here is the constraint:

```
class UniqueParliamentBasisUrl extends Constraint {
  public $notUniqueURLBasis = 'The basis URL needs to be unqiue but the set basis URL %basisurl is already in use: @parliament_link';
}

```

In UniqueParliamentBasisUrlValidator-\>validate() I try the following:

```
    $link = $parliament_using_basis_url->toLink($parliament_using_basis_url->label(), 'edit-form', ['attributes' => ['target' => '_blank']])->toString();
    $this->context->addViolation($constraint->notUniqueURLBasis, ['%basisurl' => $item->value, '@parliament_link' => $link]);

```

Here $link becomes the HTML markup for a link so that the user can easily switch to the entity which already uses this url basis in order to edit it. Unfortunately the markup becomes escaped so that the user does not see a clickable link on the form but the markup:

```
The basis URL needs to be unqiue but the set basis URL bundestag is already in use: <a href="/admin/parliament-watch/parliaments/5/edit" target="_blank" hreflang="und">Bundestag</a>

```

Is there a way to add markup to the violation message without being escaped?

# Answer
> 4 votes
You shouldn't chain up placeholders / use HTML inside placeholders. And for URLs use the `:placeholder` notation with double dots

```
 $notUniqueURLBasis = 'The basis URL needs to be unqiue but the set basis URL %basisurl is already in use: <a href=":existing_url">@link_text</a>';

```

See https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Component%21Render%21FormattableMarkup.php/class/FormattableMarkup/8.2.x

and

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Component%21Render%21FormattableMarkup.php/function/FormattableMarkup%3A%3AplaceholderFormat/8.2.x

---
Tags: 8
---