# Question
Title: Commerce custom taxtype wrong calculation
I want to add spanish recharge tax to drupal commerce. It is calculated like VAT but only for some customer in a B2B bussines, and It is a second tax, that is, you have to calculate VAT and "recharge" in the same order. Because It works more or less like European Union Vat tax type, I have copied this file and I have changed it like this:

```
/**
 * Provides spanish recharge tax.
 *
 * @CommerceTaxType(
 *   id = "spanish_recharge",
 *   label = "Recargo equivalencia",
 * )
 */
class RecargoTaxType extends LocalTaxTypeBase {

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildConfigurationForm($form, $form_state);
    $form['rates'] = $this->buildRateSummary();
    $form['rates']['#markup'] = $this->t('Recharge:');
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  protected function resolveZones(OrderItemInterface $order_item, ProfileInterface $customer_profile) {

    $zones = $this->getZones();
    /** @var \Drupal\address\AddressInterface $customer_address */
    $customer_address = $customer_profile->get('address')->first();
    $customer_country = $customer_address->getCountryCode();
    $customer_zones = $this->getMatchingZones($customer_address);
    if (empty($customer_zones)) {
      // The customer is not in the EU.
      return [];
    }

    $order = $order_item->getOrder();
    $store = $order->getStore();
    $store_address = $store->getAddress();
    $store_country = $store_address->getCountryCode();
    $store_zones = $this->getMatchingZones($store_address);
    $store_registration_zones = array_filter($zones, function ($zone) use ($store) {
      /** @var \Drupal\commerce_tax\TaxZone $zone */
      return $this->checkRegistrations($store, $zone);
    });

    $customer_tax_number = '';
    if (!$customer_profile->get('tax_number')->isEmpty()) {
      /** @var \Drupal\commerce_tax\Plugin\Field\FieldType\TaxNumberItemInterface $tax_number_item */
      $tax_number_item = $customer_profile->get('tax_number')->first();
      if ($tax_number_item->checkValue('european_union_vat')) {
        $customer_tax_number = $tax_number_item->value;
      }
    }

    // Since january 1st 2015 all digital goods sold to EU customers
    // must use the customer zone. For example, an ebook sold
    // to Germany needs to have German VAT applied.
    $taxable_type = $this->getTaxableType($order_item);
    $year = $order->getCalculationDate()->format('Y');
    $is_digital = $taxable_type == TaxableType::DIGITAL_GOODS && $year >= 2015;
    if (empty($store_zones) && !empty($store_registration_zones)) {
      // The store is not in the EU but is registered to collect VAT for
      // digital goods.
      $resolved_zones = [];
      if ($is_digital) {
        $resolved_zones = $customer_tax_number ? [$zones['ic']] : $customer_zones;
      }
    }
    elseif ($customer_tax_number && $customer_country != $store_country) {
      // Intra-community supply (B2B).
      $resolved_zones = [$zones['ic']];
    }
    elseif ($is_digital) {
      $resolved_zones = $customer_zones;
    }
    else {
      // Physical products use the origin zone, unless the store is
      // registered to pay taxes in the destination zone. This is required
      // when the total yearly transactions breach the defined threshold.
      // See http://www.vatlive.com/eu-vat-rules/vat-registration-threshold/
      $resolved_zones = $store_zones;
      $customer_zone = reset($customer_zones);
      if ($this->checkRegistrations($store, $customer_zone)) {
        $resolved_zones = $customer_zones;
      }
    }

    return $resolved_zones;
  }

  /**
   * {@inheritdoc}
   */
  public function buildZones() {
    // Avoid instantiating the same labels dozens of times.
    $labels = [
      'standard' => $this->t('Standard'),
      'intermediate' => $this->t('Intermediate'),
      'reduced' => $this->t('Reduced'),
      'second_reduced' => $this->t('Second Reduced'),
      'super_reduced' => $this->t('Super Reduced'),
      'special' => $this->t('Special'),
      'zero' => $this->t('Zero'),
      'vat' => $this->t('Recharge'),
    ];

    $zones = [];
    $zones['es'] = new TaxZone([
      'id' => 'es',
      'label' => $this->t('Spain'),
      'display_label' => $labels['vat'],
      'territories' => [
        // Spain without Canary Islands, Ceuta and Melilla.
        ['country_code' => 'ES', 'excluded_postal_codes' => '/(35|38|51|52)[0-9]{3}/'],
      ],
      'rates' => [
        [
          'id' => 'standard',
          'label' => $labels['standard'],
          'percentages' => [
            ['number' => '0.052', 'start_date' => '2012-09-01'],
          ],
          'default' => TRUE,
        ],
        [
          'id' => 'reduced',
          'label' => $labels['reduced'],
          'percentages' => [
            ['number' => '0.014', 'start_date' => '2012-09-01'],
          ],
        ],
        [
          'id' => 'super_reduced',
          'label' => $labels['super_reduced'],
          'percentages' => [
            ['number' => '0.005', 'start_date' => '1995-01-01'],
          ],
        ],
      ],
    ]);

    return $zones;
  }

  /**
   * {@inheritdoc}
   */
  public function applies(OrderInterface $order) {
    $store = $order->getStore();

    if ($this->matchesAddress($store) || $this->matchesRegistrations($store)) {

      // Check if customer is in "recharge" situation
      $usuario = $order->getCustomerId();
      $user = User::load($usuario);
      if ($user->get('field_isRecharged')->value == 1) {
        return TRUE;
      }
      else return FALSE;
    }
    else return FALSE;
  }

}

```

I have deleted all countries zones and I have left only Spain. I have defined `applies` function to check if the customer is in this situation and "recharge" needs to be added.
After rebuild cache, I have created a new tax type with this new extension. Then I have two taxes. One with Europen Union Vat extension and the other with my new extension.
In my product variation I have a tax field that point out the type of tax for this product. I use Commerce Product Tax module to select the right tax percentage for every product. It works good.
My problem is this new tax is not applied in the right way and always return 'standard' percentage even if the product has reduced or super reduced tax, because tax resolver is called only one time. I have added some log messages and this is the sequence:

1. VAT is the first tax calculated. `resolveZones` function in EurepeanUnionVat.php is fired and return spanish zone (standard, reduced and super reduced).
2. `resolve` function in TaxRateResolver.php (Commerce product tax) is fired and select the right percentage reading product variation tax field. It returns "reduced" percentage tax.
3. VAT is calculated with reduced tax. That is right.
4. Recharge begin to be calculated. `resolveZones` function, in my custom tax type RecargoTaxType.php, is fired and return spanish zone (standard, reduced and super reduced with its percentages). I have logged it.
5. Nothing more on the log ...
6. The cart is showed with VAT (reduced) and my custom "recharge" but with "standard" percentage.

What I was expecting is on step 5, `resolve` funtion in TaxRateResolver.php were called again to select the right percentage for "recharge", but It isn't called. I don't know why. Then, it adds standard percentage for recharge but It should be "reduced".
Could someone help me with this issue? Thanks.

# Answer
After some more test I realised that product variation tax field is applied only for one tax, and then `resolve` function is fired, but It doesn't find a field for my new type of tax.
I have create another field in product variation for my new taxtype and now it works good.
> 0 votes

---
Tags: 8, commerce
---


title: Bootstrap from external script

text:
# Question
Title: Bootstrap from external script
I am trying to create Drupal entity instances from an external script that is not part of Drupal or a Drupal module.

For Drupal 7 there was `drupal_bootstrap` to load the required Drupal dependencies. However, after a long search all I found for Drupal 8 was a note that `drupal_bootstrap` is deprecated for Drupal 8.

And indeed, I get a

> Call to undefined function drupal\_bootstrap()

when I try to call it after including as in

```
define('DRUPAL_ROOT', __DIR__ .'/../drupal');
require_once DRUPAL_ROOT . '/core/vendor/autoload.php';
require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

```

So how can I use the Drupal 8 API from an outside script?!

# Answer
For current version of drupal 8.x:

```
define('DRUPAL_DIR', '/usr/share/nginx/html');
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;
require_once DRUPAL_DIR . '/core/includes/database.inc';
require_once DRUPAL_DIR . '/core/includes/schema.inc';
// Specify relative path to the drupal root.
$autoloader = require_once DRUPAL_DIR . '/autoload.php';

$request = Request::createFromGlobals();

// Bootstrap drupal to different levels
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
$kernel->boot();
$kernel->prepareLegacyRequest($request);

$em = $kernel->getContainer()->get('entity.manager');

$entity = $em->getStorage('node')->create(
        array(
          'type' => "article",
          'title'=> "test entity",
          'body' => "body body body",
        ));

$entity->save();

```
> 9 votes

# Answer
I finally ended up with this code. It has some ugly extra includes but at least it works:

```
define('DRUPAL_DIR', __DIR__ .'/../drupal');

use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;

$autoloader = require_once DRUPAL_DIR . '/autoload.php';
$request = Request::createFromGlobals();
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
$kernel->boot();

require_once DRUPAL_DIR . '/core/includes/database.inc';
require_once DRUPAL_DIR . '/core/includes/schema.inc';

$em = $kernel->getContainer()->get('entity.manager');

$entity = $em->getStorage('my_entity')->create(array(
        'id' => "116",
        'name' => "test entity",
));
$entity->save();

```
> 5 votes

# Answer
Firstly: Always look for change notices. You can find them here: https://www.drupal.org/list-changes

Here's the main one dealing with `drupal_bootstrap()`: https://www.drupal.org/node/2275139

Have a look at Drupal 8's front controller (`index.php`).

You make an instance of the kernel and then have it handle requests.

But since you only want to poke entities into it, you won't handle requests. You just need to bootstrap the kernel and then use the various services to add your entities. The list of services is in `core/core.services.yml` and is quite huge. You might look for `entity_manager`.

Also, D8 has a RESTful API built in, so you might just be able to let D8 do all the work while you ping it over http.
> 3 votes

# Answer
You can use the following to bootstrap Drupal 8 from an external script to query the database:

```
use Drupal\Core\DrupalKernel;
use Drupal\Core\Site\Settings;
use Symfony\Component\HttpFoundation\Request;

define('DRUPAL_DIR', __DIR__ .'/../drupal');

// Bootstrap
$autoloader = require DRUPAL_DIR . '/autoload.php';
require_once DRUPAL_DIR . '/core/includes/bootstrap.inc';
require_once DRUPAL_DIR . '/core/modules/node/node.module'; // necessary when saving nodes
$request = Request::createFromGlobals();
Settings::initialize(dirname(dirname(DRUPAL_DIR)), DrupalKernel::findSitePath($request), $autoloader);
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod')->boot();

$em = $kernel->getContainer()->get('entity.manager');
$node_storage = $em->getStorage('node');
// ...

```
> 3 votes

# Answer
To bootstrap Drupal 8 from an external script, I would use the following code, similar to the code used in the authorize.php file.

```
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

// Change the directory to the Drupal root.
chdir('the Drupal root directory');
$autoloader = (require_once 'autoload.php');

try {
  $request = Request::createFromGlobals();
  $kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
  $kernel->boot();
  $kernel->preHandle($request);

  // Ensure the request includes the session if appropriate.
  if (PHP_SAPI !== 'cli') {
    $request->setSession($kernel->getContainer()->get('session'));
  }

  // Your code.

} catch (HttpExceptionInterface $e) {
  $response = new Response('', $e->getStatusCode());
  $response->prepare($request)->send();
  exit;
}

```

The database.inc file contains only deprecated functions, and it should not be used. The schema.inc file isn't necessary to run queries on entities.

To be able to query node entities, the code needs to load the *System* and the *Node* modules.

```
\Drupal::moduleHandler()->addModule('system', 'core/modules/system');
\Drupal::moduleHandler()->addModule('node', 'core/modules/node');
\Drupal::moduleHandler()->load('system');
\Drupal::moduleHandler()->load('node');

```
> 2 votes

---
Tags: 8, bootstrapping, external-scripts
---


title: Add a unique Banner Image to each page

text:
# Question
Title: Add a unique Banner Image to each page
I've been teaching myself Drupal 7 for the past 2 weeks. So far, I've gotten the general idea, and figured out how to use Views (i think) but it's the most difficult CMS I've ever had to learn and I've pulled out lots of hair.

The problem I'm stuck on now is that I want to be able to let the site administrators attach a unique banner image that will appear at the top of every page in my theme. There is a 'banner' region in the theme that was intended to hold this image. I've added a banner image field to the Basic Page content type. But now I can't figure out how to get that image to show up in the banner region and not in the flow of the rest of the page content (body).

I've tried a few things with views and blocks, but nothing works. Please Help!

# Answer
> 6 votes
This method is pretty similar to what Shoaid Nawaz has said above. For Drupal 7, you can use the Views module. Coupled with a custom theme region, you can create a block using the views module which will show an image for each node from a custom image field specified for the content type. You need to have a basic working knowledge of the Views module.

Here is how:

* Create a custom theme region, name it something like "Banner Region"
* In your content type, add an image field, name it something like "Banner image". If you need description, enable Alt tags for the image field. If you do not need slideshow, restrict the number of image to 1. For slideshow, you can use the views\_slideshow module.
* To create similar sized banner images, you can create a new image style.
* Create a new View. Name it something like "Banner". Choose "block" display and not "page".
* In the filter criteria, choose your content type.
* Add a contextual filter for "Content: Nid" and save the view.
* Now go to the your blocks administration page and add the newly created views block to your new banner region.

In short:

* Banner image is a new image field in an existing content type.
* Views module understands which image is attached with which node using the contextual filter.

Tip: You might want to disable this block on the frontpage if your frontpage is not a node.

Further tip: You might consider adding other content types to the filter criteria if you banners for multiple content types. Alternatively, you can create a block for each content type and block control visibility using "No results behaviour" in the views' settings.

# Answer
> 1 votes
There is Header Image, a module but unfortunately not for Drupal 7. I do not think if you can port it yourself.

Here is another guide for alternate purpose.

# Answer
> 1 votes
I managed it in a different way in an experiment using Views and content type.

A Content type (Banner) with two additional (Content) fields.

```
1. Image field
2. Visibility Location (URL) field

```

Then I created a view with `block` display type.

Fields:

```
 - Image field (Imagecache output)

```

Filter:

```
 - Node type: Banner
 - Published: True

```

Contextual filter:

```
- Content: Visibility Location

```

I then edited the options under this contextual filer as:

```
1. Select "Provide default value"
2. then select type as "PHP code"

```

I then added `PHP contextual filter code` as under

```
if(drupal_is_front_page()){
  return '<front>';
}else{
  return drupal_lookup_path('alias',$_GET['q']);
}

```

**TEST:** I put the views block in header region and created two nodes of banner types

* For node 1 I selected *`Visibility Location`* as `<front>`
* For node 2 I selected *`Visibility Location`* as `contact-us`

And it worked!

# Answer
> 0 votes
Not sure if it's too late to answer this question but I think it will come in handy when upgrading from Drupal 7 to 8 or 9.

You could give this module a try: Dynamic Banner

It has been around for a while (since 2010), and seems like the maintainer is committed to make it compatible with Drupal 8 and 9.

---
Tags: 7, theming
---


title: Removing line breaks in Twig

text:
# Question
Title: Removing line breaks in Twig
My twig file is adding line breaks in the HTML which results in white spaces, as shown in this picture:

In the browser inspector:

When I remove the line breaks in the inspector, the white spaces disappear.

The default code in the file *views-view-field.html.twig* is:

```
{{ output -}}

```

I have researched the problem quite a bit and tried the following already, without success:

```
{{ output|replace({"\n":''}) }}
{{ output|trim }}
{% spaceless %}{{ output }}{% endspaceless %}
{% spaceless %}{{ output|render|trim }}{% endspaceless %}

```

I'm working on Drupal 8.7.6.

Any help would be appreciated.

# Answer
> 3 votes
The cause of the problem is probably not the template but how the field is configured in Views. You should be able to find a solution there, even if it means you need to rewrite the field output.

If you want to try solving it in this template you have to check what is inside of `output`. Views usually puts the field output in a markup object. Then you have to render it first before applying twig filters:

```
{{ output|render|striptags|trim }}

```

I've also added `|striptags`, otherwise you would see HTML tags in plain text on the screen because they are escaped by trim.

# Answer
> 0 votes
The solution

```
{{ body|replace({"\n": "", "\r": "", "\t": ""}) }}

```

works for me in views Global/Custom text field. It removes new lines from the body field.

---
Tags: theming
---


# Question
Title: How capture video thumbnail , when video is uploaded under media video type file?
I'm using Core media module to upload video\[Media Type is video,which has field video of 'file field type'\].
This module will refer video.png as thumnail for all video uploaded from the local system.

I want to capture first frame of video as thumbnail when video is uploaded from the local system in media section. I have seen 'PHP ffmpeg' , module , But i don't know the approach to follow to capture first frame of video. If i need to write a custom module to capture thumnail while saving media type of video, which hook function I need to use or please suggest me what apprach I can follow?

# Answer
> 0 votes
You can use https://www.drupal.org/project/media\_thumbnails\_video for this.

It has a dependency (`php-ffmpeg/php-ffmpeg`) that requires both the FFMpeg and FFProbe binaries to be installed on your server.

---
Tags: 8, files, media
---


# Question
Title: How do I consume REST data with an external service?
I want to integrate RESTful API with drupal 8.

What I want to achieve is my a project which is built in drupal 8 is the consumer and RESTful API is integrated into another website using CodeIgniter.

I want to create a page in drupal using routing and all data will be coming from another website.

Example:

```
http://mywebsite.com/products [drupal 8]
http://webservice.com/products/list.json [CI]

```

My website will consume web service of webservice.com and will display the products on my website.

What is the better way or structure to achieve it?

# Answer
I actually have implemented a similar thing in my project.

I created a module structure like as follow.

```
 my_module [directory]
        products [directory]
          products.info.yml
          products.module
          products.routing.yml
          src[directory]
            Controller[directory]
              - ProductsController.php
          templates[directory]
              - products-list.html.twig
        my_module.info.yml
        my_module.module
        my_module.routing.yml

```

### products.routing.yml

```
 products.list:
    path: '/products'
    defaults:
      _controller: '\Drupal\products\Controller\ProductsController::getList'
      _title: 'Get List'
    requirements:
      _permission: 'access content'

```

### src/Controller/ProductsController.php

```
    /**
     * @file
     * Contains \Drupal\products\Controller\ProductsController.
     */
    namespace Drupal\products\Controller;

    use Drupal\Core\Controller\ControllerBase;

    /**
     * Controller routines for products routes.
     */
    class ProductsController extends ControllerBase {

      /**
       * Callback function to get the data from REST API
       */
      public function getList() {

        $data = array();
        $response = $data = $result = null;

        if (function_exists('my_module_reponse')) {
          $response = my_module_reponse('http://webservice.com/products/list', 'GET');
        }

        if ($response) {

          $result = json_decode($response);
          $data = array();

          // # add all the data in one multiple dim array
          $data['title'] = 'products to consume REST API';
          $data['users'] = $result;

          // display the content in the middle section of the page
          $build = array(
            '#theme' => 'products_list', // assign the theme [products-list.html.twig]
            '#title' => 'products to consume REST API', // assign the page title
            '#pagehtml' => 'data is coming from : products/list ', // assign the string message like this
            '#data' => $data
          ); // assign the array like this to access in twig file
        }
        return $build;
      }
    }

```

### templates/products-list.html.twig

```
<div class="container">
  <h1> {{ data.title }} </h1>
  <div><strong> {{ pagehtml }} </strong></div>

  {% for item in data.users %}
    <div>{{ item.yourproductnamekey}}</div>
  {% endfor %}

</div>

```

### my\_module.module

```
      /**
       * @file
       * Test API module.
       */
      function my_module_reponse($url, $method = 'GET', $params = array()) {
        $methods = [
          'POST',
          'GET',
          'PUT',
          'DELETE'
        ];
        $result = array();

        try {
          if (empty($url)) {
            throw new Exception("Invalid url");
          }
          if (in_array(strtoupper($method), $methods) === FALSE) {
            throw new Exception("Invalid method");
          }
          else {
            // will need a request call for GET, POST, PUT
            switch (strtoupper($method)) {
              case 'GET':
              case 'POST':
              case 'PUT':
              case 'DELETE':
                if (function_exists('my_module_call_request')) {
                  $result = my_module_call_request($url, $method, $params);
                }
                break;
              default:
                throw new Exception("Invalid method");
                break;
            }
          }
        }
        catch (Exception $e) {
          echo $e->getMessage();
        }

        return $result;
      }

      function my_module_call_request($requesturl, $method, $params = array()) {

        // request url
        $url = $requesturl;

        try {

          // initialized curl
          $ch = curl_init();

          // set header for curl request
          $headers = array(
            "Cache-Control: no-cache",
            "Pragma: no-cache"
          );

          // set required setting with curl configuration
          curl_setopt($ch, CURLOPT_URL, $url);
          curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
          curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
          curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
          curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);

          // pass the additional values
          curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));

          // close the curl connection
          $result = curl_exec($ch);
          curl_close($ch);

          return $result;
        }
        catch (Exception $e) {
          echo $e->getMessage();
        }
      }

```

### products.module

```
    /**
     * implements hook_theme();
     * description: create the file as per below
     * eg : products-list.html.twig  for "products_list"
     */
    function example_theme($existing, $type, $theme, $path) {
      return array(
        'products_list' => array(
          'variables' => array(
            'pagehtml' => NULL,
            'data' => NULL
          )
        ),
      );
    }

```

Each submodule will contain the individual routing file and function related to each page. It will make easy for you to maintain the code as well.
> 11 votes

# Answer
There's a contrib module which can be used for this purpose too. The name is External Entities

Module itself will take care of caching and other things. And you will be able to create twig template for theming purpose.
> 0 votes

---
Tags: 8
---


# Question
Title: How do I add fields to an existing custom entity?
I have a custom entity that fieldable. I need to add a field to it, and I want to do it through the UI. The entity was created in a custom module, which I can modify.

How can I make the entity fieldable?

```
/**
 * Defines the Quiz entity.
 *
 * @ingroup qwizard
 *
 * @ContentEntityType(
 *   id = "qwiz",
 *   label = @Translation("Quiz"),
 *   bundle_label = @Translation("Quiz type"),
 *   handlers = {
 *     "storage" = "Drupal\qwizard\QwizStorage",
 *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
 *     "list_builder" = "Drupal\qwizard\QwizListBuilder",
 *     "views_data" = "Drupal\qwizard\Entity\QwizViewsData",
 *
 *     "form" = {
 *       "default" = "Drupal\qwizard\Form\QwizForm",
 *       "add" = "Drupal\qwizard\Form\QwizForm",
 *       "edit" = "Drupal\qwizard\Form\QwizForm",
 *       "delete" = "Drupal\qwizard\Form\QwizDeleteForm",
 *     },
 *     "access" = "Drupal\qwizard\QwizAccessControlHandler",
 *     "route_provider" = {
 *       "html" = "Drupal\qwizard\QwizHtmlRouteProvider",
 *     },
 *   },
 *   base_table = "qwiz",
 *   revision_table = "qwiz_revision",
 *   revision_data_table = "qwiz_field_revision",
 *   admin_permission = "administer quiz entities",
 *   entity_keys = {
 *     "id" = "id",
 *     "revision" = "vid",
 *     "bundle" = "type",
 *     "label" = "name",
 *     "uuid" = "uuid",
 *     "uid" = "user_id",
 *     "langcode" = "langcode",
 *     "status" = "status",
 *   },
 *   links = {
 *     "canonical" = "/admin/structure/qwizard/qwiz/{qwiz}",
 *     "add-page" = "/admin/structure/qwizard/qwiz/add",
 *     "add-form" = "/admin/structure/qwizard/qwiz/add/{qwiz_type}",
 *     "edit-form" = "/admin/structure/qwizard/qwiz/{qwiz}/edit",
 *     "delete-form" = "/admin/structure/qwizard/qwiz/{qwiz}/delete",
 *     "version-history" = "/admin/structure/qwizard/qwiz/{qwiz}/revisions",
 *     "revision" = "/admin/structure/qwizard/qwiz/{qwiz}/revisions/{qwiz_revision}/view",
 *     "revision_revert" = "/admin/structure/qwizard/qwiz/{qwiz}/revisions/{qwiz_revision}/revert",
 *     "revision_delete" = "/admin/structure/qwizard/qwiz/{qwiz}/revisions/{qwiz_revision}/delete",
 *     "collection" = "/admin/structure/qwizard/qwiz",
 *   },
 *   bundle_entity_type = "qwiz_type",
 *   field_ui_base_route = "entity.qwiz_type.edit_form"
 * )
 */

```

# Answer
You just need to add a `field_ui_base_route` to the entity annotation. The value should be the route ID for the edit form of the config entity type used to provide the bundles.

So if your entity ID is `foo` and the bundle config entity ID is `foo_type`, that would be:

```
@ContentEntityType(
  id = "foo",
  ...
  field_ui_base_route = "entity.foo_type.edit_form"
)

```

Rebuild the cache, and you should see the relevant menu links and tabs when you manage your bundles in the UI.
> 1 votes

---
Tags: entities, 9
---


title: Bootstrap failing with Drush 9.1.0

text:
# Question
Title: Bootstrap failing with Drush 9.1.0
I had Drush 9 working before it got upgraded to 9.1.0 and am a little bit at my wits end why Bootstrap is failing and why I get "Bootstrap failed" or "! \[NOTE\] Drupal root not found. Pass --root or a @siteAlias in order to see Drupal-specific commands."

* My build directory is separate from my vendor directory. (shorthanded below to `[build]` and `[composer]`)
* There are a couple of debugged commands below, one trying to use an alias, and one just using the help command.
* There are a couple extra alias paths (the last two) which are not valid and I can't figure out where they come from (they are not in my `drush.yml` anywhere), but my alias file is found... `@default.dev` does seem to work.
* adding `-r` or `-uri` (or using that in place of the alias) does not make any difference... I still get the Bootstrap failed.

What has changed from earlier versions of Drush 9, or what am I doing incorrectly here? There was similar things with Drush 8 at some point, but none of the solutions that I saw in there worked, and I didn't see anything specific to Drush 9.

```
[794e@794elmp01 htdocs]$ drush @default.dev cr -d
 [preflight] Config paths: /../.drush/drush.yml,/var/..[composer]/vendor/drush/drush/drush.yml
 [preflight] Alias paths: /../.drush/sites,/var/..[build]/sites,/var/..[build]/drush/sites,/var/..[composer]/drush/sites
 [preflight] Commandfile search paths: /var/../vendor/drush/drush/src
 [bootstrap] Bootstrap to site [0.2 sec, 10.19 MB]
  [Exception]
  Bootstrap failed.
Exception trace:
 () at /var/..[composer]/vendor/drush/drush/src/Boot/BootstrapHook.php:31
 Drush\Boot\BootstrapHook->initialize() at /var/..[composer]/vendor/consolidation/annotated-command/src/Hooks/Dispatchers/InitializeHookDispatcher.php:34
 Consolidation\AnnotatedCommand\Hooks\Dispatchers\InitializeHookDispatcher->callInitializeHook() at /var/..[composer]/vendor/consolidation/annotated-command/src/Hooks/Dispatchers/InitializeHookDispatcher.php:27
 Consolidation\AnnotatedCommand\Hooks\Dispatchers\InitializeHookDispatcher->initialize() at /var/..[composer]/vendor/consolidation/annotated-command/src/CommandProcessor.php:117
 Consolidation\AnnotatedCommand\CommandProcessor->initializeHook() at /var/..[composer]/vendor/consolidation/annotated-command/src/AnnotatedCommand.php:391
 Consolidation\AnnotatedCommand\AnnotatedCommand->initialize() at /var/..[composer]/vendor/symfony/console/Command/Command.php:229
 Symfony\Component\Console\Command\Command->run() at /var/..[composer]/vendor/symfony/console/Application.php:859
 Symfony\Component\Console\Application->doRunCommand() at /var/..[composer]/vendor/symfony/console/Application.php:206
 Symfony\Component\Console\Application->doRun() at /var/..[composer]/vendor/symfony/console/Application.php:125
 Symfony\Component\Console\Application->run() at /var/..[composer]/vendor/drush/drush/src/Runtime/Runtime.php:112
 Drush\Runtime\Runtime->doRun() at /var/..[composer]/vendor/drush/drush/src/Runtime/Runtime.php:41
 Drush\Runtime\Runtime->run() at /var/..[composer]/vendor/drush/drush/drush.php:64
 require() at /var/..[composer]/vendor/drush/drush/drush:4

```

```
drush list -d
 [preflight] Config paths: /home/../.drush/drush.yml,/var/..[composer]/vendor/drush/drush/drush.yml
 [preflight] Alias paths: /home/../.drush/sites,/var/..[build]/sites,/var/..[build]/drush/sites,/var/..[composer]/drush/sites
 [preflight] Commandfile search paths: /var/..[composer]/vendor/drush/drush/src
 [bootstrap] Bootstrap to max [0.22 sec, 10.14 MB]
 [debug] Trying to bootstrap as far as we can [0.22 sec, 10.15 MB]
Drush Commandline Tool 9.1.0
! [NOTE] Drupal root not found. Pass --root or a @siteAlias in order to see Drupal-specific commands.

```

Also, additional info: this is the site reference in the `default.site.yml`:

```
dev:
  root: /var/..[build]/htdocs
  uri: http://dev.our.internal.url.com

```

I verified that the root and URI were correct, and that the URI was accessible from the server (it is not a public URI).

EDIT: Adding Drush Status (per request)

```
 drush status -d
 [preflight] Config paths: /home/../.drush/drush.yml,/var/[composer]/vendor/drush/drush/drush.yml
 [preflight] Alias paths: /home/../.drush/sites,/var/[build]/sites,/var/[build]/sites,/var/[composer]/drush/sites
 [preflight] Commandfile search paths: /var/[composer[/vendor/drush/drush/src
 [bootstrap] Bootstrap to max [0.19 sec, 10.14 MB]
 [debug] Trying to bootstrap as far as we can [0.19 sec, 10.15 MB]
 PHP binary    : /usr/bin/php
 PHP config    : /etc/php.ini
 PHP OS        : Linux
 Drush script  : /var/[composer]/vendor/bin/drush
 Drush version : 9.1.0
 Drush temp    : /tmp
 Drush configs : /home/../.drush/drush.yml
                 /var/[composer]/vendor/drush/drush/drush.yml

```

# Answer
I stumbled (and fell) upon the same issue today.

Following your work (missing composer.json at drupal's docroot), I was able to get over this problem, by making sure scaffolding was in place (inside drupal-project's composer.json). i.e.:

```
    "post-install-cmd": [
        "@drupal-scaffold",
        "DrupalProject\\composer\\ScriptHandler::createRequiredFiles"
    ],
    "post-update-cmd": [
        "@drupal-scaffold",
        "DrupalProject\\composer\\ScriptHandler::createRequiredFiles"
    ]

```

This may be quite obvious but got drush 9.2.1 working fine for me.

Good luck
> 0 votes

# Answer
I has this issue and found this to work:

```
rm -Rf vendor/drush
composer install

```

Credit: https://github.com/drush-ops/drush/issues/2959#issuecomment-332054773

This deletes drush and uses the composer.lock file to re-instate drush from the version specified there.

Version of drush is 9.5.2 on my setup (after running above command at time of writing).
> 6 votes

# Answer
I had this issue when upgrading from drush 8 to drush 9.

Drush was failing to find the settings files on the server I deployed to.

When creating the artifact for deployment, I had previously stripped out unnecessary files, including `__PROJECT_ROOT__/composer.json`.

It turns out, when I made sure `__PROJECT_ROOT__/composer.json` was included on the server, drush 9 found the settings files, and the database connection.
> 2 votes

# Answer
This can also happen when `composer.json` is in place, but the additional pieces that move `drupal/core` from `vendor` into the web root are not fully in place.

I ran into this when updating a library that was using the old `drupal/drupal` package to the now standard `drupal/core-recommended`.

Even after adding this to `composer.json` I was still seeing the bootstrap error.

```
    "installer-paths": {
      "web/core": [
        "type:drupal-core"
      ]
    },
    "drupal-scaffold": {
      "locations": {
        "web-root": "web/"
      }
    }

```

The key missing piece was to also add the package `composer/installers` so that Drupal core was moved after downloading:

```
...
"require": {
  ...
    "composer/installers": "^1.2",
    "drupal/core-composer-scaffold": "^9.1",
    "drupal/core-recommended": "^9.1",
  ...

```
> 1 votes

---
Tags: 8, drush, installation
---


title: how to load RTL style in RTL language

text:
# Question
Title: how to load RTL style in RTL language
I have a multi language website, one of languages is a RTL language, in Drupal 7 I put my CSS in `style.css` and RTL CSS to `style-rtl.css` and by default drupal also load style-rtl.css file, Now **in Drupal 8 ,I have a multi language theme, how can I tell Drupal to load my RTL style in RTL language?**

**update** I found this link but I am not sure about that because I have a CSS file with almost 1400 lines, I should put \[dir="rtl"\] before all of any selector ? !!!

# Answer
Drupal 8 uses libraries, and you can load these in templates. One way of achieving language direction dependant libraries would be to use the `html_attributes['dir']` variable in `html.html.twig` and load different libraries depending on the value:

```
{% if html_attributes['dir'] == 'ltr' %}
  {{ attach_library('your_theme_name/styles') }}
{% elseif html_attributes['dir'] == 'rtl' %}
  {{ attach_library('your_theme_name/styles_rtl') }}
{%- endif -%}

```

Set up a couple of libraries:

```
styles:
  version: 8.x-1.0
  css:
    theme:
      css/styles.css: {}

styles_rtl:
  version: 8.x-1.0
  css:
    theme:
      css/styles-rtl.css: {}

```
> 8 votes

# Answer
For those who are looking for an alternative solution:

> You can also define a new `library` in `libraries.yml` file of your theme and point that library to use a certain CSS or JS or whatever you need.

Next step is to use a preprocess such as theme preprocess to tell Drupal8 to use that library in a specific condition.

**Example:** Defining new library beneath your default one in `themename.libraries.yml`

```
rtl:
  version: VERSION
  css:
    theme:
      assets/css/themename.style-rtl.css: {}

```

Next you can detect the current direction of your pages with a preprocess in `themename.theme` file:

```
function themename_preprocess_html (&$variables) {
    // Load specific library for pages with html attribute of RTL
    if ($variables['html_attributes']['dir'] == 'rtl') {
          $variables['#attached']['library'][] = 'themename/rtl';
    }
}

```

Clear the cache and you are good to go
> 2 votes

# Answer
I just wrote a simple module called Twig RTL Detection which extends twig and provides a boolean `is_language_rtl` function for twig so you can simply add rtl libraries if this function returns TURE **in any** html.twig files you want.

```
{{ attach_library('my_theme/front') }}
{% if is_language_rtl() %}
  {{ attach_library('my_theme/front_rtl') }}
{% endif %}

```
> 1 votes

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


title: Pass node field value to page.html.twig

text:
# Question
Title: Pass node field value to page.html.twig
I'm new to Drupal. I've just started a custom theme in Drupal 8 and created a new field under Content Type. This field value is a custom class for each page. From the documentation I should be able to display the field contents of "field\_body\_class" with the following, neither of which display.

```
{{content.field_body_class}}

{{page.content.field_body_class}}

```

I've checked to make sure the field was not hidden, which it was not.

# Answer
You are probably a bit confused.

Variables are only available in specific templates. So the value of a field which is attached to an entity (like a content type) is only available in the template for that entity.

To make the body class field value available in a different template you need to

* make a preprocess function for the template.
* fetch the entity that has the field
* expose it to the template.

For you it could look something like this.

```
function theme_name_preprocess_page(&$variables) {
   // Define {{ body_class }}  in the template.
  if (!empty($variables['node']) && !empty($variables['node']->field_body_class)) {
    $variables['body_class'] = $variables['node']->field_body_class->value;
  }
}

```
> 5 votes

# Answer
The page.html.twig template doesn't get any `content` variable. It gets a `page.content` variable, but that is the rendered content of the *content* region, which means you won't get `page.content.field_body_class`.

To get the field value, you need to implement a preprocess function for the *node* template and set a new variable initialized to the field value.

```
function mytheme_preprocess_node(&$variables) {
  if (!empty($variables['node']->field_body_class)) {
    $variables['body_class'] = $variables['node']->get('field_body_class')->value;
  }
}

```
> 0 votes

---
Tags: theming, 8
---


# Question
Title: Attached all images from taxonomy in view
I am creating a view of a content type and content type is linked with you to taxonomy with has images.

Now, i have added Relaionship as well.

But now if my node is attached to muliple taxmony term it is showing results seperatlety for each row.

i want one main nid against all taxonmy items with images in it within view.

Any idea

# Answer
You can do this with the help of Display modes. You can find them under Structure \> Display modes \> View modes. Don't confuse them with Views module, they use the same word "views" but are two different features. You need to combine those two features to display referenced Taxonomy field fields on Content Views.

1. Create a new View mode for Taxonomy term under Structure \> Display modes \> View modes
2. Enable it on the Manage display page for the Taxonomy vocabulary (the one with images), a new subtab will appear on that page where you can edit which term fields should display under that mode (Disable Description and any other fields you don't want to show, but keep the Image)
3. Edit your Content Views, edit the Taxonomy term field and set the `Formatter` to `Rendered entity`
4. Set the `View mode` to the one you created in step 1. Make sure that you have `Display all values in the same row` under `Multiple field settings` but you probably already have that.
5. Remove the Relationship unless you need it for something else. Display mode pulls in the term image information, you don't need the Relationship to do that.
> 1 votes

---
Tags: 8, views, taxonomy-terms
---


title: Custom form validation is missing

text:
# Question
Title: Custom form validation is missing
I have a registration form :

```
<div class="register-error" id="register-error">{{ form.status_messages_user_register_form }}</div>

<div class="row">

<div class="col-sm-6">{{ form.field_first_name }}</div>

<div class="col-sm-6">{{ form.field_last_name }}</div></div>

<div class="clear"></div>
{{ form.account.mail }}
{{ form.account.name }}
<div class="row">
<div class="col-sm-6">{{ form.account.pass.pass1 }}</div>
<div class="col-sm-6">{{ form.account.pass.pass2 }}</div></div>
<div class="clear"></div>
{{ form.form_build_id }} {# required #}
{{ form.form_token }}{# required #}
{{ form.form_id }} {# required #}
{{ form.actions }}

```

Now i want to add custom validation for the registration.I have a custom ajax handler for registration using form alter:

```
$form['actions']['submit']['#ajax']  = [
         'callback'    => 'custom_register_form_ajax_validate',
         'event'       => 'click',
         '#attributes' => [
           'class' => [
             'use-ajax',
          ],
         ],
       ];
       $form['#attached']['library'][]      = 'core/drupal.dialog.ajax';
       $form['#attached']['library'][]      = 'core/drupal.ajax';

       $form['#prefix']                     = '<div id="email-valid"></div>';

```

And this is my function :

```
function custom_register_form_ajax_validate(&$form, $form_state){

$response = new AjaxResponse();

  $form_state->setTemporaryValue('entity_validated', TRUE);

  $firstname = $form['field_first_name']['widget']['#default_value'];

  $email = $form_state->getValue('mail');

  $pass1 = $form_state->getValue('pass1');

  $pass2 = $form_state->getValue('pass2');

    if($firstname == ''){
         $text = '<h5 style="color:red;">Firstname is required.</h5>';
          $response->addCommand(new InvokeCommand('.form-text', 'css', array('border-bottom', '2px solid red')));
      $response->addCommand(new HtmlCommand('#email-valid', $text));
    }
    if($lastname == ''){
         $text = '<h5 style="color:red;">Lastname is required.</h5>';
          $response->addCommand(new InvokeCommand('.form-email', 'css', array('border-bottom', '2px solid red')));
      $response->addCommand(new HtmlCommand('#email-valid', $text));
    }
    if($email == ''){
         $text = '<h5 style="color:red;">Email field is required.</h5>';
          $response->addCommand(new InvokeCommand('.form-email', 'css', array('border-bottom', '2px solid red')));
          $response->addCommand(new HtmlCommand('#email-valid', $text));
    }
}

```

I want to validate "Firstname is required" condition.But when i submit and validate the form,always showing "Email field is required".

How can i solve this issue?

# Answer
> 0 votes
You're probably not printing something required by the form since you are printing items individually. To start debugging, you can comment your entire form twig out and just use `{{ form }}` and see if it triggers validation.

At the same time, you are copy pasting the wrong thing in each error case:

```
      $response->addCommand(new InvokeCommand('.form-email', 'css', array('border-bottom', '2px solid red')));
      $response->addCommand(new HtmlCommand('#email-valid', $text));

```

This will always apply to elements with .form-email class and #email-valid id.

You're trying to evaluate `$lastname` but that variable is never set. If the email validation error always shows, then validate that you are using the right key in `$form_state->getValue()`.

Since you are applying it to the same id, you are going to overwrite your own message each time as well. Check the documentation on `HtmlCommand`. It implements jQuery's `html(string)`:

> When .html() is used to set an element's content, any content that was in that element is completely replaced by the new content.

You need to provide different divs to print these errors for the users sake, or rethink how you are doing this.

# Answer
> 0 votes
What exactly are you trying to do? It looks like you are trying to do custom validation without actually submitting the form?

---
Tags: 8, users
---


# Question
Title: Get value of a checkbox that is an element in a #rows array
I am building a table with checkboxes without using tableselect for various reasons, but am trying to retrieve the checkbox value similar to how tableselect does. Tableselect will populate the values array in `$form_state` at form submission. A key with the name of the form in values contains the list of selected rows. I attempted to reverse engineer how tableselect populates the values array, but I couldn't really come up with anything other than `#return_value`. The values array using the following element is unpopulated when the form is submitted.

This is some of the form builder I'm using right now. It exists in the `buildForm(array $form, FormStateInterface $form_state)`.

```
$rows[$nid] = [
    'check' => [
        'data' => [
            '#type' => 'checkbox',
            '#title' => 'test2',
            '#return_value' => '$nid',
        ]
    ],
],

// …

$form['table'] = array(
    '#type' => 'table',
    '#header' => $header,
    '#rows' => $rows,
);

```

# Answer
You probably want to use `'#type' => 'tableselect'` as the form field type instead of `'table'`. tableselect is a table type definition that provides a select box to the table.

From there, you can build your options for the table like so:

```
$options[
  <return_value> => [
   'field_name' => 'value',
   'field_name2' => 'value',
  ],
];

```

Or in your case:

```
$options[
  <nodeid> => [
   'field1' => 'value',
   'field2' => 'value',
  ],
];

```

More information on the tableselect type can be found here: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21Element%21Tableselect.php/class/Tableselect/8.2.x

I know you mentioned not wanting to use tableselect, but save yourself the headache and don't reinvent the wheel. That's what tableselect is for :)

The table form aAPI element is a display element used for displaying tabular data, not being used as a valid form input method.
> 0 votes

---
Tags: forms, 9
---


# Question
Title: How to display the first child of a book with the title of the book and keep the url by using a view
Is it possible to display the list of the first child of every book with a view? I couldn't figure that out so I added boolean to the book content type to check which child is the first child. If that's not possible I'll just keep it the way it is, but the main problem is overwriting the the name of the first chapter (keep the url) with the name of the book. I wanted to do that with the custom text field, but I don't see the replacement pattern of the book name, so is that even possible?

I'm using Drupal 8.

Thanks in advance!

# Answer
> 1 votes
It's not at all a problem to override the link text with another field. Title field settings have the `Rewrite results` with the `Override the output of this field with custom text`, with available tokens listed below that under `Replacement patterns`.

1. To get the top level Book information add the Relationship `Top Level Book`.
2. Edit the Title Field and make sure it uses the Relationship, this will display the main Book title for each of the book Pages in the results, instead of the Pages titles. (I'm assuming you've created the Content Views showing Book pages.)
3. Edit the field settings to `Exclude from display` and untick `Link to the Content` while keeping the Formatter `Plain text`, so the main book link doesn't interfere with overriding.
4. Add Field `Link to Content`, configure it under `Rewrite results` with `Override the output of this field with custom text`, `Output this field as a custom link`, enter token for your title field into the Text field, something like `{{ title }}`

Now you have links for each Views result that link to Book Pages but the link text is the main Book title.

## Book pages weight

The real problem is showing only the first Book pages. **Weight** is available as a Field within Views, so you can show and sort the book pages in the results according to their set order. Lowest numbers float to top, large numbers fall to the bottom, as is always the logic with weight in Drupal.

But there doesn't seem to be a Filter available for the Weight, at least I'm not seeing any right now, so it doesn't seem possible to filter out only the first child page of every Book.

It is possible to work around it by creating a separate Views Display for each Book you have in Drupal. Set Sort criteria to Book Weight, and Pager to only show 1 result. This way only the first Book page will be shown, but you'll have a separate Block for each Book to show this.

If you have more than one level of the book pages use the Filter `Depth` with the value `2`. (1 depth is the main Book page and 0 is for book pages that don't belong to any Book.)

You can make it look like it's the same Block with some styling after you display all those Blocks in the same theme region.

---
Tags: 8, views, nodes
---


title: Commerce Invoice Entity Print Styling

text:
# Question
Title: Commerce Invoice Entity Print Styling
I am using Commerce Invoice and Entity Print to generate .pdf-files of invoices. In Entity Print settings, I set the paper size to A4 and selected TCPDF as printing engine.

Then, I customized commerce-invoice.html.twig to my needs, which works fine.

But I cannot get rid of the two black borders that seperate the document header and footer I think.

Would be nice if anyone could give me a hint where these come from. I alread also tried to override entity-print.html.twig and remove the styles from there. Also I unchecked the checkbox in the entity-print settings.

But these borders still appear on every .pdf-generation.

Thank you very much in advance!

# Answer
What I found out is:

Every available printing engine has it's own requirements for the HTML-structure of the generatred invoice.

TCPDF needs a header and footer-tag inside the document. If you dont provide this elements, TCPDF will render them empty, but will in fact attach an hr-tag after the empty header and before the empty footer.

I switched to DOMpdf as printing engine, which also offers the possibility to define a page header and footer, but ignores them when empty and doesn't render any additional HTLM by default.

pro: DOMpdf supports more CSS rules and makes it easier to style the invoice with CSS

con: DOMpdf takes some seconds to render/print the document from the HTML, while TCPDF is very fast.
> 1 votes

---
Tags: theming, commerce, 9
---


# Question
Title: How do I use a term as contextual filter correctly?
I'm using Drupal 8.

I have a book content type that uses a vocabulary called "book type" as an entity reference field.

I have basic page content type which also uses the the vocabulary "book type" as an entity reference field.

So both of the content types are using the same vocabulary.

What I'm trying to do is filter the books by the chosen book type on the basic page content type, but I just can't figure it out. Here's what I tried.

**This is the book content type, which uses the vocabulary "book type" in an entity reference field**

**This is the basic page content type which also use the vocabulary "book type" in an entity reference field**

This is my second try with the help of prkos:

# Answer
You don't need Relationships for matching through ER fields, IDs are enough so it's enough to use the ER field Contextual matching directly.

Instead of the ID Contextual filter add the Contextual filter for the ER field and configure it:
`When the filter value is NOT available`
**Provide default value**
**Taxonomy term ID from URL**
**Load default filter from node page, that's good for related taxonomy blocks**
**Limit terms by vocabulary**
**\[Your vocabulary\]**
**Filter to items that share any term**
`When the filter value IS available or a default is provided`
**Specify validation criteria**
**Taxonomy term ID**
**\[Your vocabulary\]**

Set other options according to your needs.

You can test it by entering a Taxonomy ID into the Views Preview field, you should get only the nodes that reference that term.

When you place the Block in a theme region also configure the Contextual option, it won't work without it.
> 1 votes

---
Tags: 8, views, taxonomy-terms
---


title: Add a link to a tableselect row

text:
# Question
Title: Add a link to a tableselect row
I'm interested in adding a link in a tableselect form row. Utilizing the `#options` key I can only add columns with strings. I am able to add form elements in the `#options` array similar to the `#rows` array.

```
$rows[$nid] = [
    'edit_link' => [
        'class' => 'edit_link',
        'data' => [
            '#type' => 'link',
            '#url' => Url::fromRoute('group_manager.edit'),
            '#title' => 'test',
        ],
    ],
]

//…

$form['table'] = array(
    '#type' => 'tableselect',
    '#header' => $header,
    '#options' => $rows,
);

```

Implementing this example as is doesn't render this column in the table, so I assume it has failed somehow.

The 'edit\_link' element works if the form is changed to a 'table' instead of 'tableselect'.

# Answer
I solved my issue.

The links column was not rendered for the tableselect form because I didn't update my `$header` array with the new element name `edit_link`.

It appears a table form does not map the element names to the header names, meaning I did not have to update the header array for my link columns to appear. As long as the element name was in the header array Tableselect would render the column. I believe this to be the basis of my issue.
> 0 votes

---
Tags: forms, 9
---


# Question
Title: How can I access the paragraph fields from my node via Tokens?
Token Version: 8.x-1.7 Paragraphs Version: 8.x-1.12

I have one main node. In this main node I have referenced another sub-node. This sub-node has two fields with paragraphs. Each of these paragraphs consists of further text fields. I would like to access these fields in the pargraphs by token. Unfortunately, I cannot find a suitable token for this. Neither in my token browser nor under /admin/help/token .

The only token with which I can access the field is the following: \[node:field\_agent\_reference:entity:field\_gratification\_for\_agents\].

But unfortunately this only gives me the whole content of the paragraph and not the fields individually. What am I doing wrong?

All other tokens that start with paragraphs, such as: \[paragraph:field\_agent:entity:field\_gratification\_fur\_agents\] \[paragraph:field\_agent:entity:field\_bonus\_number\_or\_percent\] \[paragraph:field\_percentage\_media\] \[paragraph:field\_percentage\_media:value\]

do not function for me.

Thanks a lot

Bavra

# Answer
> 1 votes
The token browser stops spitting out chained suggestions after a sensible level of nesting - otherwise the memory use and (lack of) UI responsiveness could easily get out of hand. That doesn't mean that chaining stops, just the available hints.

You can keep right on going, e.g.

```
[node:field_agent_reference:entity:field_gratification_for_agents:entity:field_foo:value]

```

# Answer
> 0 votes
Thank you for your feedback. So I have now tried the following, without result: \[node:field\_agentur\_reference:entity:field\_gratifikation\_fur\_agenten:entity:0:field\_auszahlung:value\]

\[node:field\_agentur\_reference:entity:field\_gratifikation\_fur\_agenten:entity:0:field\_auszahlung\]

\[node:field\_agentur\_reference:entity:field\_gratifikation\_fur\_agenten:entity:field\_auszahlung:value\]

\[node:field\_agentur\_reference:entity:field\_gratifikation\_fur\_agenten:0:entity:field\_auszahlung:value\]

\[node:field\_agentur\_reference:entity:field\_gratifikation\_fur\_agenten:0:entity:field\_auszahlung\]

The machine name of the paragraph is: gratifikation\_fur\_agenten The machine name of the two fields in the paragraph is: field\_auszahlung
field\_prozent both from type number(integer)

Thnx

# Answer
> 0 votes
I would like to change the depth/recursion of the token browser for a moment. I know about the risk.

I have played with the following settings in the token.module, but nothing has happened yet:

```
'token_types' => [],
  'global_types' => TRUE,
  'click_insert' => TRUE,
  'show_restricted' => TRUE,
  'show_nested' => TRUE,
  'recursion_limit' => 8,
  'text' => NULL,
  'options' => [],

```

Did I miss something? Thank you and greetings

Bavra

---
Tags: tokens, paragraphs
---


# Question
Title: How can I turn off the caching for a Paragraph type?
I'm rendering an array whose URL is dependent on a $\_GET variable.

Where the variable is present and valid, I want to serve an iframe with the \_GET variable as part of the URL. At the moment the cache is capturing the variable and preventing different value being passed to the page.

In my module I have this:

```
function MY_MODULE_preprocess_paragraph__iframe(&$variables) {
    $query = @$_GET['e'];
    /*...*/
}

```

But the value $query is staying the same until the caches are cleared.

Is there a better way of capturing the $\_GET variable, or a way of preventing the value from being cached?

# Answer
> 1 votes
Declare the dependency on the GET parameter with a cache context:

*/mymodule/mymodule.module*

```
function mymodule_preprocess_paragraph(&$variables) {

  $foo = \Drupal::request()->query->get('foo');
  $variables['content']['foo'] = [
    '#markup' => "foo = $foo",
    '#cache' => ['contexts' => ['url.query_args:foo']],
  ];
}

```

More info https://www.drupal.org/docs/drupal-apis/cache-api/cache-contexts

However, if you have more than a few possible values of `foo` this is a problem with cache performance, especially for nested entities like paragraphs. Each value creates a new cache entry for the paragraph and its parent entities.

To avoid this put a placeholder in the paragaph:

*/mymodule/mymodule.module*

```
function mymodule_preprocess_paragraph(&$variables) {

  $variables['content']['foo_placeholdered'] = [
    '#lazy_builder' => ['\Drupal\mymodule\MymoduleLazyBuilders::getFoo', []],
    '#create_placeholder' => TRUE,
  ];
}

```

and build the content which depends on the GET parameter in a lazy builder:

*/mymodule/src/MymoduleLazyBuilders.php*

```
<?php

namespace Drupal\mymodule;

use Drupal\Core\Render\Element\RenderCallbackInterface;

class MymoduleLazyBuilders implements RenderCallbackInterface {

  public static function getFoo() {
    $foo = \Drupal::request()->query->get('foo');
    return  [
      '#markup' => "foo = $foo",
      '#cache' => ['contexts' => ['url.query_args:foo']],
    ];
  }

}

```

For time consuming calculations such placeholders can be delivered through BigPipe. So if you enable this module you can also improve page speed.

---
Tags: paragraphs, 9
---


# Question
Title: Can't pass variable from theme hook or controller to custom template
On Drupal 8, I want pass a variable to a overrides template from my controller OR from the hook theme. I do several tries :

from my .module file :

```
function ms_story_theme($existing, $type, $theme, $path) {
  $theme = array();
  $theme['page__ms_story__global'] = array(
    'variables' => [
      'toto' => "toto", //try one
    ],
    'base hook' => 'page',
    'render element' => 'elements',
    '#tata' => 'tata', //try two
  );
  return $theme;
}

```

from my .php controller file :

```
class customController extends ControllerBase {
  public function map_global($name) {
    return [
      '#type' => 'markup',
      '#theme' => 'page__ms_story__global',
      '#markup' => $this->t("Implement method: hello with parameter(s): $name"),
      '#tutu' => "tutu", //try three
      'variables' => [
        "tyty" => "tyty", //try four
      ],
    ];
  }
}

```

But when I want display all available variable from my overrided template file (via {{ kint() }} ), I don't see anywhere variables I want add. Variables 'toto' 'tata' tutu' and 'tyty' aren't present in the array structure displayed via kint (I cleared all cache of course)

Where is my mystake ?

Bonus question : how can I add a variable who use not any cache ? (the variable is calculated again every time the user load page ?

# Answer
You cannot use #markup and #theme in the same element. #markup will always take precedence, and #theme is ignored. If you want to output some markup, you need to include that as part of your theme. If the markup is dynamic, then include it as a variable to be passed to your theme (though you need to name the variable as something other than markup).

You've also defined the variable as `toto` in your `hook_theme()` implementation, then passed the value in `#tutu` in your render array. You need to use `'#toto' => 'some value'`.
> 1 votes

# Answer
Each information array must contain either a 'variables' element (for using a #theme element) or a 'render element' element (for render elements), but not both.

Ref: https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!theme.api.php/function/hook\_theme/8.2.x
> 0 votes

---
Tags: theming, 8
---


# Question
Title: Where shall I place "PHP SAML" library so that SAML Authentication module could find it?
I have a multisite Drupal 7 installation (not using Composer), and I can't figure out where shall I place "PHP SAML" library so that the SAML Authentication module would find it.

The instructions within the module simply say to install OneLogin's SAML PHP module (and the only provided instructions set uses Composer). The Libraries API module is installed, but wherever sites/domainname/libraries I try to place the content of the cloned https://github.com/onelogin/php-saml.git, the SAML Authentication module still says the "PHP SAML" isn't installed.

How and where do I place the right files in absence of Composer?

# Answer
> 1 votes
I dabbled with this before. In order to get phpsimplesaml to work you need a module that autoloads composer libraries. I ultimately gave up trying it on d7 because it was a nightmare to get everything working, but I at least had the library recognized.

---
Tags: 7
---


# Question
Title: How do I add conditional fields to a paragraph?
I was able to add conditional fields in a paragraph, following Conditional Fields in Paragraphs Using the Javascript States API for Drupal 8, but it controls and hides only 1 field.

I need to control multiple fields from one select list. I added multiple fields to a variable and created a for loop. The select list has 3 options.

* 3row|3row
* 2row|2row
* 1row|1row

The following is the code for the custom module. When it runs, the last `for` loop is the only one that works. The first 2 select list options don't work. Do I need to add a field value check before each for loop? My module name is conditional\_fields.

```
use Drupal\node\NodeInterface;
use Drupal\node\NodeForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\paragraphs\ParagraphInterface;
use Drupal\paragraphs\Plugin\Field\FieldWidget\ParagraphsWidget;
use Drupal\paragraphs\Entity\Paragraph;

/*
 * Implements hook_field_widget_form_alter().
 */
function conditional_fields_field_widget_paragraphs_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
  $field_definition = $context['items']->getFieldDefinition();
  $paragraph_entity_reference_field_name = $field_definition->getName();

  if ($paragraph_entity_reference_field_name == 'field_topic_paragraphs') {
    $widget_state = \Drupal\Core\Field\WidgetBase::getWidgetState($element['#field_parents'], $paragraph_entity_reference_field_name, $form_state);

    $paragraph_instance = $widget_state['paragraphs'][$element['#delta']]['entity'];
    $paragraph_type = $paragraph_instance->bundle();

    if ($paragraph_type == 'teaser_content') {
      $dependee_field_name = 'field_paragraph_number_of_rows';
      $selector = sprintf('select[name="%s[%d][subform][%s]"]', $paragraph_entity_reference_field_name, $element['#delta'], $dependee_field_name);

      $fields_to_control1 = ['field_description_col_5','field_link_col_5','field_description_col_6','field_link_col_6','field_description_col_7','field_link_col_7','field_description_col_8','field_link_col_8','field_description_col_9','field_link_col_9','field_description_col_10','field_link_col_10','field_description_col_11','field_link_col_11','field_description_col_12','field_link_col_12','field_description_col_13','field_link_col_13','field_description_col_14','field_link_col_14','field_description_col_15','field_link_col_15','field_description_col_16','field_link_col_16'];

      $fields_to_control2 = ['field_description_col_9','field_link_col_9','field_description_col_10','field_link_col_10','field_description_col_11','field_link_col_11','field_description_col_12','field_link_col_12','field_description_col_13','field_link_col_13','field_description_col_14','field_link_col_14','field_description_col_15','field_link_col_15','field_description_col_16','field_link_col_16'];

      $fields_to_control3 = ['field_description_col_13','field_link_col_13','field_description_col_14','field_link_col_14','field_description_col_15','field_link_col_15','field_description_col_16','field_link_col_16'];

      foreach ($fields_to_control3 as $field) {
        $element['subform'][$field]['#states'] = [
          'invisible' => [
            $selector => ['value' => '3row'],
          ],
        ];
      }

      foreach ($fields_to_control2 as $field){
        $element['subform'][$field]['#states'] = [
          'invisible' => [
            $selector => ['value' => '2row'],
          ],
        ];
      }

      foreach ($fields_to_control1 as $field) {
        $element['subform'][$field]['#states'] = [
          'invisible' => [
            $selector => ['value' => '1row'],
          ],
        ];
      }

      unset($element['subform']['field_paragraph_number_of_rows']['widget']['#options']['_none']);
      $element['subform']['field_paragraph_number_of_rows']['widget']['#empty_option']  = t('- 4 Rows -');
    }
  }
}

```

# Answer
I've used form states with these pre-requisites:

* Form states with paragraphs
* The content widget used is: Inline Entity Form - Complex
* The widget should be changed, not the field

There is this content type with the paragraph reference with a two-fields paragraph: content reference and content number. The content reference field cardinality is 5, and the number of content is a select list (1, 2, 3, or 5). So, the logic is used to enable the content input according to the number of content selected.

This was the solution I've used, hopefully, it can help someone else:

```
/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function HOOK_inline_entity_form_entity_form_alter(&$entity_form, &$form_state) {
  if ($entity_form['#entity_type'] === 'paragraph' && $entity_form['#bundle'] === 'PARAGRAPH_BUNDLE') {
    $parents = $entity_form['#parents'];
    // It needs to get the parent form (content type form field) in order to work fine.
    $identifier = $parents[0] . '[' . implode('][', array_slice($parents, 1)) . ']';
    // I need to use the target_id to aim the wdiget.
    // The first input should be shown if I select 1, 2, 3, or 5 content to be added.
    $entity_form["field_content_reference"]["widget"][0]["target_id"]['#states'] = [
      'enabled' => [
        'select[name="' . $identifier . '[field_content_number]"]' => [
          ['value' => 1],
          'or',
          ['value' => 2],
          'or',
          ['value' => 3],
          'or',
          ['value' => 5],
        ],
      ],
    ];
    // The second input should be shown if I select 2, 3, or 5 content to be added.
    $entity_form["field_content_reference"]["widget"][1]["target_id"]['#states'] = [
      'enabled' => [
        'select[name="' . $identifier . '[field_content_number]"]' => [
          ['value' => 2],
          'or',
          ['value' => 3],
          'or',
          ['value' => 5],
        ],
      ],
    ];
    // The third input should be shown if I select 3, or 5 content to be added.
    $entity_form["field_content_reference"]["widget"][2]["target_id"]['#states'] = [
      'enabled' => [
        'select[name="' . $identifier . '[field_content_number]"]' => [
          ['value' => 3],
          'or',
          ['value' => 5],
        ],
      ],
    ];
    // The rest of the input should be shown if I select 5 content to be added.
    $entity_form["field_content_reference"]["widget"][3]["target_id"]['#states'] = [
      'enabled' => [
        'select[name="' . $identifier . '[field_content_number]"]' => ['value' => 5],
      ],
    ];
    $entity_form["field_content_reference"]["widget"][4]["target_id"]['#states'] = [
      'enabled' => [
        'select[name="' . $identifier . '[field_content_number]"]' => ['value' => 5],
      ],
    ];
  }
}

```
> 0 votes

---
Tags: 8, forms
---


title: Getting the media URL in a views field

text:
# Question
Title: Getting the media URL in a views field
I'm using Drupal 8.5. I have a content type with the in-core media module. I'm making a view for content syndication, and I need one of the columns to be the FDQN URI to the media resource-- i.e, not the rendered entity itself (which comes through as an `img` tag), but `https://example.com/sites/default/files/media_image.jpg`.

I've added the media field to my view, but I didn't find any Formatter, View Mode, or Rewrite Pattern that gives me the absolute URL to the resource. I can get the path to the media (e.g. `https://example.com/media/1899`), the entity\_id (e.g. 1899), but no path to the file.

How can I render the path to the media image in my view?

# Answer
> 13 votes
The media field is an entity reference type field. You will need to add a relationship to the media entity. This should add the URI field in media entity to the view selections. You should then be able to select this (with the right reference relationship) and use the standard URL formatters.

# Answer
> 6 votes
The selected answer is perfect. I am adding screenshots since it is easier to understand for new users.

1. Add the relationship to the media field (in my case field\_banner\_media)

2. Click on "Add Fields" and select "Media" in category. Select the "Image" which is our media image field

3. Select the relationship to field\_banner\_image(my case) and formatter to "URL to Image"

---
Tags: views, 8, media
---


# Question
Title: Using Entity Print to generate several PDFs of a Webform submission
This may be too vague a question as I'm just starting to work through this. Would very much appreciate any pointers/experiences if people have done something similar.

Functionality I'm hoping for: User completes a webform survey and upon completion they are able to download two PDFs that have differing data/results form specific sections of the webform.

A more concrete example, the webform first asks profile questions about age and job type, conditionally on that the second half of the form pulls in different questions (ie. if you answered being under 50, you get question set A, if over 50 get question set B). Once the user submits the form they could download two separate PDFs, one a summary of their profile, and the second a summary of their answers to the conditional question sets.

I've got webform and entity print running, and can see the 'view/print pdf' function added to webform submissions, and have been able to link to that PDF on the confirmation page. But I'm not sure about the best way to approach creating two separate PDFs. Views seems the best approach, but how would I link it all together? Is there another way? Like I said, apologies, this is probably too vague, just trying to avoid going down dead-end paths.

Thanks very much.

# Answer
You can use the "Webform Entity Print (PDF) Attachment" module included with the Webform module to create different PDF versions of a submission.

This video includes a little more information about attachment elements.
> 3 votes

---
Tags: webforms, 8
---


# Question
Title: How can I rename a menu machine name in drupal 8
I ve migrated my D6 site to D8. And now I'd like to rename my menu machine names(not the system menus my custom menus) to a different ones. I'd want to do this either on database or from code.

Any ideas??

# Answer
> 1 votes
I also faced the problem when I needed to rename the machine name of my custom menus. In my case, I needed to remove hyphens in the machine name (this is a known issue https://www.drupal.org/project/drupal/issues/1353064), because some modules don't support hyphens. How I fixed it:

1. First of all you need to update already existing menu items (bundle, name, parent and etc.) I did it directly in a database through hook\_update in your\_custom\_module:

```
function your_custom_module_update_8008() {
  $database = \Drupal::database();

  $menus = [
    'example-menu-machine-name-1' => 'examplemenumachinename1',
    'example-menu-machine-name-2' => 'examplemenumachinename2',
  ];

  foreach ($menus as $old_machine_name => $new_machine_name) {
    $database->update('menu_link_content')
      ->expression('bundle', "REPLACE(bundle, :old_value, :new_value)", [
        ':old_value' => $old_machine_name,
        ':new_value' => $new_machine_name,
      ])
      ->execute();
    $database->update('menu_link_content_data')
      ->expression('menu_name', "REPLACE(menu_name, :old_value, :new_value)", [
        ':old_value' => $old_machine_name,
        ':new_value' => $new_machine_name,
      ])
      ->expression('bundle', "REPLACE(bundle, :old_value, :new_value)", [
        ':old_value' => $old_machine_name,
        ':new_value' => $new_machine_name,
      ])
      ->execute();

    $database->update('menu_tree')
      ->expression('menu_name', 'REPLACE(menu_name, :old_value, :new_value)', [
        ':old_value' => $old_machine_name,
        ':new_value' => $new_machine_name,
      ])
      ->expression('id', 'REPLACE(id, :old_value, :new_value)', [
        ':old_value' => $old_machine_name,
        ':new_value' => $new_machine_name,
      ])
      ->expression('parent', 'REPLACE(parent, :old_value, :new_value)', [
        ':old_value' => $old_machine_name,
        ':new_value' => $new_machine_name,
      ])
      ->execute();
  }
}

```
2. Rename these names in configs. Your IDE should help with this. Don't forget also about renaming files for configs. For example: **system.menu.example-menu-machine-name-1.yml** to **system.menu.examplemenumachinename1.yml**
3. If you have custom templates for menus also rename them: **menu--example-menu-machine-name-1.html.twig** to **menu--examplemenumachinename1.html.twig**
4. Adjust classes in CSS|SCSS files, because they will be changed after renaming. Use IDE for this, it will save time :)
5. Run your build process locally and check results.
6. Take the dump of the database from the production and run a build with this database locally. Please compare menus between the local version and the production on the frontend.

# Answer
> -1 votes
I'm not sure but you can try node clone and then clone a menu after that you can set the machine name.

---
Tags: 8
---


# Question
Title: Trouble accessing twig variables passed from custom block
I've looked through many similar questions and can't figure out what I'm missing. I have a custom module with a block...

```
/**
 * Provides the 'Four Words' block
 *
 * @Block(
 *   id = "na_fourwords",
 *   admin_label = @Translation("Four Words Hero"),
 *   category = @Translation("Custom"),
 * )
 */
class NAFourWordsBlock extends BlockBase {

  public function build() {
    return [
      '#theme' => 'block__na_fourwords',
      '#myvar' => 'TESTING',
      '#attached' => ['library' => ['na_fourwords/na_fourwords']],
    ];
  }
}

```

In my .module file:

```
function na_fourwords_theme($existing, $type, $theme, $path){
  return [
    'block__na_fourwords' => [
      'variables' => [
        'myvar' => NULL,
      ],
    ],
  ];
}

```

In my twig, `{{ myvar }}` doesn't render. If I call `{{ kint(elements.content) }}`, I get ...

```
elements.content => Array
(
    [#theme] => block__na_fourwords
    [#myvar] => TESTING
    [#attached] => Array
        (
            [library] => Array
                (
                    [0] => na_fourwords/na_fourwords
                )

        )

)

```

It looks like the data is getting passed through ... why am I unable to access it? I feel like there's something simple I'm overlooking.

Drupal 9.1.7 PHP 7.4.16

Thanks!

# Answer
> 0 votes
So, `block--na-fourwords.html.twig` is an existing Drupal suggestion for a template name for a block with id `na_fourwords`. I was able to override the template file, but my theme function that was trying to talk to that file was being ignored because it already existed. It would be nice if Drupal had some kind of feedback to let you know of conflicting theme hooks like that.

Anyway, hopefully this saves someone similar frustration.

---
Tags: blocks
---


# Question
Title: How can I setup multiple database connections?
Can anyone help me to setup connection with multiple databases connection in Drupal 8? I have database on the same server and I want to access it along with default Drupal 8 database.

# Answer
> 21 votes
This is done in the same way as in Drupal 7: You can add the database credentials in your settings.php file.

```
$databases['default']['default'] = array(
  'database' => 'drupal8',
  'username' => 'username',
  'password' => 'password',
  'prefix' => '',
  'host' => 'localhost',
  'port' => '3306',
  'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
  'driver' => 'mysql',
);

$databases['external']['default'] = array(
  'database' => 'external',
  'username' => 'username',
  'password' => 'password',
  'prefix' => '',
  'host' => 'localhost',
  'port' => '3306',
  'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
  'driver' => 'mysql',
);

```

You will now have two connection options, default and external. You can tell Drupal to use the *external* connection using `\Drupal\Core\Database\Database::setActiveConnection('external')` and switch back to the default one with `\Drupal\Core\Database\Database::setActiveConnection()` once you don't need anymore the *external* connection.

# Answer
> 9 votes
In addition to retrieving a database connection to the external database using `Database::getConnection()`, you can also use dependency injection in your code to retrieve the connection *as a dependency* and declare your connection in a module's services YAML file:

```
database.external:
  class: Drupal\Core\Database\Connection
  factory: 'Drupal\Core\Database\Database::getConnection'
  arguments: ['external']

external_database_dependent_service:
  class: Drupal\MODULE\Some\Class\For\A\ServiceUsingTheExternalDatabase
  arguments: ['@database.external']

```

# Answer
> 6 votes
thank you very much, @googletorp!

here's a slightly more complete example - my code to select users from a D7 database who have created nodes:

```
\Drupal\Core\Database\Database::setActiveConnection('external');

// Get a connection going
$db = \Drupal\Core\Database\Database::getConnection();

$query = $db->select('users', 'u');
$query->fields('u', array('uid', 'name'));
$query->join('node', 'n', 'n.uid = u.uid');
$query->orderBy('uid');
$users = $query->execute()->fetchAllKeyed();

\Drupal\Core\Database\Database::setActiveConnection();

```

# Answer
> 3 votes
**Update on this topic for the most recent version of Drupal 8 at this time (8.9.13)**:

As mentioned by @acrosman in a comment, you do need to provide two parameters, and not in the order that you might expect. In settings.php, the format is like:

```
$databases['default']['default'] = array(
  'database' => 'database',
  'username' => 'user',
  'password' => 'pass',
  'host' => 'localhost',
  'port' => '3306',
  'driver' => 'mysql',
  'prefix' => '',
  'collation' => 'utf8mb4_general_ci'
);

```

So if you've added a second database like:

```
$databases['external']['default'] = array(
  'database' => 'database',
  'username' => 'user',
  'password' => 'pass',
  'host' => 'localhost',
  'port' => '3306',
  'driver' => 'mysql',
  'prefix' => '',
  'collation' => 'utf8mb4_general_ci'
);

```

And you want to get a connection to the second database:

```
$connExternal = \Drupal\Core\Database\Database::getConnection('default', 'external');
$results = $connExternal->select('users', 'u')

```

... and so on until -\>execute() and fetching the data.

Note that the keys are in reverse order. This is also not set globally with ::getConnection(), so subsequent DB queries will revert to the previous default database.

# Answer
> 1 votes
Adding the settings for a new connection is possible by editing the settings.php file used for the site. The successive step is letting Drupal know when it needs to use the new connection, and this depends on which module needs to use it and for what data.

In the case of a custom module which uses procedural code to connect to the new connection (which I assume doesn't contain data accessed from Drupal core or Drupal core modules) for accessing its own database tables, I would use code similar to the following one.

```
$db = Database::getConnection('default', 'external');
$data = $db->->select('table_name','t')->fields('t')->execute();

```

I use `Database::getConnection()` because it allows to use any function/method that could (directly or indirectly) access a database table without first setting the default connection back with `Database::setActiveConnection()`.
There is still the risk that Drupal core invokes a hook when the database is queried (for example, `hook_query_TAG_alter()`), and that hook implementation assumes the database used for the connection contains all the Drupal data.

Instead of relying on the connection being defined in the settings.php file, the module could add the connection information with code similar to the following one.

```
$connection = [
  'database' => 'database',
  'username' => 'user',
  'password' => 'password',
  'host' => 'localhost',
  'port' => '3306',
  'driver' => 'mysql',
  'prefix' => '',
  'collation' => 'utf8mb4_general_ci'
];

Database::addConnectionInfo('external', 'default', $connection);

```

Note that the order of the first two parameters used by `Database::getConnection()` is different from the order of the first two parameters used by `Database::addConnectionInfo()`: For `Database::addConnectionInfo()`, `$key` is the first parameter.

For a module that uses the external database to store its own entities, the module should define its own storage handler (extending `ContentEntityStorageBase`), possibly passing to its constructor the key and the target to use for the database connection. In this way, it can use a different connection for its entity data and the field data associated to its entity.

---
Tags: database, 8
---


# Question
Title: Can I insert the version number in the info file of a module for internal use?
The documentation on the creation of custom modules says,

```
# Note: do not add the 'version' or 'project' properties yourself.
# They will be added automatically by the packager on drupal.org.

```

so I never put a version number in my module. But then I add difficulties writing database update scripts, I never managed to get an `N` in `hook_update_N()` that the update would recognize.

Also, my module *really* doesn't have any utility outside of my organization, since it has very specific domain requirements; therefore it is not, and never will, be released as a contributed module.

So, can I use a version number in my info file, and use it to generate the name of the update function? And if I insert it in an update of my module, will it be correctly managed?

# Answer
> 4 votes
If you host your module outside of drupal.org, including a private Git repository, or a local computer from which the module is copied on the site, you can set the `version` key in the .info.yml file for the module.

If the module updates are handled differently, the module could also implement `hook_update_projects_alter()` to tell the Update Manager not to check for that module updates, for example implementing the code shown in the documentation.

```
function mymodule_update_projects_alter(&$projects) {
  // Hide a site-specific module from the list.
  unset($projects['site_specific_module']);
}

```

As for the number *N* used in `hook_update_N()`, that number isn't related to the module version. It's just a progressive number, used from Drupal to verify which `hook_update_N()` implementation has been already run. `hook_update_N()` explains the convention for the four digits used for N.

* 1 or 2 digits for Drupal core compatibility (for example, 8 for compatibility with Drupal 8, 10 for compatibility with Drupal 10)
* 1 digit for your module's major release version (for example 1 for the 8.x-1.3 release)
* 2 digits for a counting number, starting from *01*

To use an existing project as example, the pathauto.install file for the release 8.x-1.11 defines, as last update hook `pathauto_update_8106()`; the same file for the release 8.x-1.5 has `pathauto_update_8107()` as last update hook, which is the latest update hook also for the release 8.x-1.8.

Note that the digit for the major version release isn't sufficient to describe the version release (which would include also the minor version), but it's not sufficient also for a major version that is higher than 9.
Note also that Drupal core won't report any error whether (for example) a 8.x-2.3 release contains `mymodule_update_8133()` as update hook. What described is a convention for which only the Drupal compatibility digit is required.

---
Tags: 8
---


# Question
Title: Is it possible to pass classes to twig include template
Drupal 9 bootstrap barrio sub-theme.

I would like to use a generic template to build some "card" bootstrap display. This template is called by multiple other templates like this :

`{% include '@my_theme/views/views-view-unformatted--card-template.html.twig %}`

At begining, I started with this template :

```
{% if title %}
  <h3>{{ title }}</h3>
{% endif %}
<div class="card-view row row-cols-1 row-cols-md-2 row-cols-lg-3">
{% for row in rows %}
  {%
    set row_classes = [
      default_row_class ? 'views-row col',
    ]
  %}
  <div{{ row.attributes.addClass(row_classes) }}>
    {{ row.content }}
  </div>
{% endfor %}
</div>

```

But now I see that I must dynamically pass the classes to the template to allow different layouts ("row-cols-1 row-cols-md-2 row-cols-lg-3" or only "row-cols-1 row-cols-md-2" for example).

I saw that we can use the include twig statement with the "with" keyword, so I tried to implement the following :

real template :

```
{%
  set classes = [
    "card-view",
    "row",
    "row-cols-1",
    "row-cols-md-2",
  ]
%}
{% include '@my_theme/views/views-view-unformatted--card-template.html.twig' with {'card_view_classes': classes} %}

```

and the generic template :

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

```

But it don't work. No classes are added.

Maybe someone can point me how to achieve this build ? Or maybe it's not possible to do it like this ?

Thanks in advance for any answer.

# Answer
Yes @Clive, it's correct. I can simply declare a variable called "card\_classes" and it is passed to the sub-template. During my tests I targeted an incorrect base template. It was my problem :-/

In the included template :

```
{% if card_classes is not defined %}
  {% set card_classes = [
    'card-view',
    'row',
    'row-cols-1',
    'row-cols-md-2',
    'row-cols-lg-3',
    ]
  %}
{% endif %}

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

```

By checking if card\_classes variable is defined or not, I can set default classes in the included template itself, or override the default classes in the base template.

And now in base templates :

```
{# use default classes #}
{{ include('@my_theme/views/views-view-unformatted--card-template.html.twig') }}

```

or to override

```
{# override default classes by another set of classes #}
{%
  set card_classes = [
    'card-view',
    'row',
    'row-cols-1',
    'row-cols-md-2'
  ]
%}

{{ include('@my_theme/views/views-view-unformatted--card-template.html.twig') }}

```
> 1 votes

---
Tags: theming, 9, bootstrap-theme
---