# Question
Title: How can I make a custom module link appear on /admin/config?
I have a custom module I'm working on and I'd like to make it configurable via the admin menu. I'm having difficulty getting a form to appear in the admin page.

Visting admin/config/MYMODULE does show the form, it's just not visible on the /admin/config page.

Here is my file structure so far (excluding irrelevant files):

\*The form file is just an example form to try to get it to appear on the admin page.

**MYMODULE.routing.yml**

```
MYMODULE.settings:
  path: '/admin/config/system/MYMODULE'
  defaults:
    _form: '\Drupal\MYMODULE\Form\myModuleSettingsForm'
    _title: 'myModule Settings'
  requirements:
    _permission: 'administer site configuration'

```

**MYMODULE.schema.yml**

```
MYMODULE.settings:
  type: config_object
  label: 'myModule Settings'
  mapping:
    path_to_sound:
      type: string
      label: 'Path to Sound'

```

**MYMODULE.links.menu.yml**

```
MYMODULE.settings:
  title: 'myModule Settings'
  description: 'Alter myModule Settings'
  route_name: MYMODULE.settings
  parent: system.admin_config_system

```

**MYMODULE.settings.yml**

```
path:
  path_to_sound: '/modules/custom/MYMODULE/myModule.mp3'

```

**myModuleSettingsForm.php**

```
<?php

namespace Drupal\MYMODULE\Form;

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

/**
 * Configure example settings for this site.
 */
class myModuleSettingsForm extends ConfigFormBase {

  /**
   * Config settings.
   *
   * @var string
   */
  const SETTINGS = 'MYMODULE.settings';

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'MYMODULE_admin_settings';
  }

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return [
      static::SETTINGS,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this->config(static::SETTINGS);

    $form['example_thing'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Things'),
      '#default_value' => $config->get('example_thing'),
    ];

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

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Retrieve the configuration.
    $this->configFactory->getEditable(static::SETTINGS)
      // Set the submitted configuration setting.
      ->set('example_thing', $form_state->getValue('example_thing'))
      // You can set multiple configurations at once by making
      // multiple calls to set().
      ->save();

    parent::submitForm($form, $form_state);
  }

}

```

It's my understanding that I should now be able to see this form on the config page, but I do not, regardless of cache clearing, etc. I followed documentation to do this and even cross referenced other popular modules, so I'm really not sure what I'm doing wrong.

# Answer
> 1 votes
To use `parent: system.admin_config` for a menu link it needs a route that has `_controller: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage'` as a controller. And only now you can add children to that link.

`parent: system.admin_config` is for creating new thematic blocks. While you could use `parent: system.admin_config_content`, `parent: system.admin_config_system` etc. to add your link to an existing block.

So either switch `parent: system.admin_config` to `parent: system.admin_config_content` for example in your links Yaml and in your routing Yaml the path to `path: '/admin/config/content/MYMODULE'` to add your link to the "Content authoring" block.

Or adjust your MYMODULE.routing.yml and MYMDOULE.links.menu.yml to look like shown below instead to create a new thematic block and let your link be a child of that.

MYMODULE.routing.yml:

```
MYMODULE.settings:
  path: '/admin/config/MYMODULE'
  defaults:
    _controller: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage'
    _title: 'MyModule'
  requirements:
    _permission: 'access administration pages'

MYMODULE.example_thing:
  path: '/admin/config/MYMODULE/example-thing'
    _form: '\Drupal\MYMODULE\Form\myModuleSettingsForm'
    _title: 'Example thing'
  options:
    _admin_route: TRUE
  requirements:
    _permission: 'access administration pages'

```

MYMODULE.links.menu.yml

```
MYMODULE.settings:
  title: 'MyModule'
  route_name: MYMODULE.settings
  parent: system.admin_config
  description: 'Configure MyModule'
  weight: -10

MYMODULE.example_thing:
  title: 'Example thing'
  parent: MYMODULE.settings
  description: 'Example thing configuration'
  weight: 0
  route_name: MYMODULE.example_thing

```

---
Tags: routes, 9
---


title: Extend core select widget

text:
# Question
Title: Extend core select widget
Please help with the following:

I need a new widget (just a slightly altered select) that can be setup from the UI by anyone. I have done the following:

1. Created a new custom module and enabled it.
2. Created a new widget.

```
<?php

namespace Drupal\filtered_select\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsSelectWidget;
use Drupal\Core\Form\FormStateInterface;

/**
 * Plugin implementation of the 'filtered_select' widget.
 *
 * @FieldWidget(
 *   id = "filtered_select",
 *   label = @Translation("Filtered Select"),
 *   field_types = {
 *      "entity_reference"
 *   },
 *   multiple_values = FALSE
 * )
 */
class FilteredSelectWidget extends OptionsSelectWidget {

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $element = parent::formElement($items, $delta, $element, $form, $form_state);
    // Use the parent select functionality,
    // just switch the element.
    $element['#type'] = 'fselect';

    return $element;
  }

}

```
3. Created new element so I can switch the theme. (not sure if this is necessary)

```
<?php

namespace Drupal\filtered_select\Element;

use Drupal\Core\Render\Element\Select;

/**
 * Provides the filtered select element.
 *
 * @FormElement("fselect")
 */
class FilteredSelect extends Select {

  /**
   * {@inheritdoc}
   */
  public function getInfo() {
    $info = parent::getInfo();

    // Theme switch.
    $info['#theme'] = 'fselect';

    return $info;
  }
}

```
4. It did not work otherwise so I also got a hook\_theme up in my module file like this:

```
/**
 * Implements hook_theme().
 */
function filtered_select_theme($existing, $type, $theme, $path): array {
    return [
        'fselect' => [
            'render element' => 'element',
            'template' => 'fselect',
        ],
    ];
}

```
5. I just copied the template from core into my custom module and it works in the sense that it prints the right template, I have not yet altered this one, I just want to get the same old core functionality working under another name first.

**Issue**: My new render element seems to be missing the options array and I can't figure out why. I've done really basic overwrites and I cannot understand why it does not build the options array.

Twig Var Dumps:

--- THIS IS THE CORE SELECT ---

```
array:15 [▼
  "element" =>array:41 [▶]
  "theme_hook_original" => "select"
  "attributes" =>Drupal\Core\Template\Attribute {#7543 ▶}
  "title_attributes" =>Drupal\Core\Template\Attribute {#7932 ▶}
  "content_attributes" =>Drupal\Core\Template\Attribute {#7896 ▶}
  "title_prefix" => []
  "title_suffix" => []
  "db_is_active" =>true
  "is_admin" =>true
  "logged_in" =>true
  "user" =>Drupal\Core\Session\AccountProxy {#2354 ▶}
  "directory" => "core/themes/seven"
  "options" =>array:3 [▼0 =>array:4 [▶]
    1 =>array:3 [▶]
    2 =>array:3 [▶]
  ]
  "#cache" =>array:1 [▶]
  "theme_hook_suggestions" => []
]

```

--- THIS IS MY 'NEW' Filtered Select ---

```
array:14 [▼
  "element" =>array:41 [▶]
  "theme_hook_original" => "fselect"
  "attributes" =>Drupal\Core\Template\Attribute {#7543 ▶}
  "title_attributes" =>Drupal\Core\Template\Attribute {#8034 ▶}
  "content_attributes" =>Drupal\Core\Template\Attribute {#7708 ▶}
  "title_prefix" => []
  "title_suffix" => []
  "db_is_active" =>true
  "is_admin" =>true
  "logged_in" =>true
  "user" =>Drupal\Core\Session\AccountProxy {#2354 ▶}
  "directory" => "core/themes/seven"
  "#cache" =>array:1 [▶]
  "theme_hook_suggestions" => []
]

```

As one can see, I'm missing the 'options' array and I cannot understand why. Please advise.

# Answer
> 1 votes
You are missing template\_preprocess\_select(). You could copy the code to your own preprocess hook for `fselect` or, which might be a better idea, extend `select` as base hook and use double underscores `select__fselect` for the extended template name. See How do I define a custom html.html.twig file?

---
Tags: theming
---


# Question
Title: TypeError: Argument 1 passed to ........ ::__construct() must implement interface Drupal\Core\Cache\CacheBackendInterface, array given, called in
I'm getting an error when I wrote the code using Dependency injection:

> TypeError: Argument 1 passed to Drupal\sydneypro\_exchange\_rates\_block\Plugin\Block\ExchangeRatesBlock::\__construct() must implement interface Drupal\Core\Cache\CacheBackendInterface, array given, called in /var/www/web/core/lib/Drupal/Core/Plugin/Factory/ContainerFactory.php on line 25 in Drupal\sydneypro\_exchange\_rates\_block\Plugin\Block\ExchangeRatesBlock-\>\__construct() (line 55 of modules/custom/sydneypro\_exchange\_rates\_block/src/Plugin/Block/ExchangeRatesBlock.php).

**ExchangeRatesBlock.php:**

```
<?php

namespace Drupal\sydneypro_exchange_rates_block\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Render\Markup;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use Psr\Container\ContainerInterface;

/**
 * Provides a block with Exchange Rates.
 *
 * @Block(
 *   id = "block_exchange_rates",
 *   admin_label = @Translation("Exchange rates block"),
 * )
 */
class ExchangeRatesBlock extends BlockBase {

  /**
   * Cache for Data.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cacheBackend;

  /**
   * Guzzle Http Client.
   *
   * @var \GuzzleHttp\Client
   */
  protected $httpClient;

  /**
   * Configuration for module.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected $config;

  /**
   * ExchangeRatesBlock constructor.
   *
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   The cacheBackendInterface.
   * @param \GuzzleHttp\Client $http_Client
   *   The httpclient.
   * @param \Drupal\Core\Config\ImmutableConfig $immutable_config
   *   The configuration.
   */
  public function __construct(CacheBackendInterface $cache_backend, Client $http_Client, ImmutableConfig $immutable_config) {
    $this->cacheBackend = $cache_backend;
    $this->httpClient = $http_Client;
    $this->config = $immutable_config;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('cache.default'),
      $container->get('http_client'),
      $container->get('config.factory')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    $client = $this->httpClient;
    $access_key = $this->config->get('exchange.settings')->get('exchange_access_key');
    $cid = 'sydneypro_exchange_rates_block';

    try {
      if ($cache = $this->cacheBackend->get($cid)) {
        $data = $cache->data;
      }
      else {
        $response = $client->get('http://api.exchangeratesapi.io/v1/latest?access_key=' . $access_key);
        $response_data = $response->getBody();
        $data = json_decode($response_data);
        $this->cacheBackend->set($cid, $data);
      }

      $properties = [
        'uah' => [
          'label' => $this->t('Hryvnia'),
          'value' => round($data->rates->UAH, 2),
        ],
        'usd' => [
          'label' => $this->t('Dollar'),
          'value' => round($data->rates->USD, 2),
        ],
        'gbp' => [
          'label' => $this->t('Pound sterling'),
          'value' => round($data->rates->GBP, 2),
        ],
      ];

      $build = [];

      foreach ($properties as $exchange_property => $data) {
        $build[$exchange_property] = ['#type' => 'container'];
        $build[$exchange_property]['label'] = ['#markup' => $data['label']];
        $build[$exchange_property]['separator'] = ['#markup' => ': '];
        $build[$exchange_property]['value'] = ['#markup' => $data['value']];
      }
      $build[] = [
        '#attached' => [
          'library' => [
            'sydneypro_exchange_rates_block/sydneypro_exchange_rates_block',
          ],
        ],
      ];

      return $build;
    }
    catch (ConnectException $e) {
      return [
        '#markup' => Markup::create('<h1>Internet, DNS, or other connection error</h1>'),
      ];
    }
    catch (RequestException $e) {
      return [
        '#markup' => Markup::create('<h1>Sorry, no data available</h1>'),
      ];
    }
  }

  /**
   * Disable cache for a block because my own cache doesn't work with it.
   *
   * @return int
   *   return cacheMaxAge 0
   */
  public function getCacheMaxAge() {
    return 0;
  }

}

```

How to fix it?

# Answer
The constructor of a class that extends `Drupal\Component\Plugin\PluginBase`, such as in your case (as `Drupal\Core\Block\BlockBase` extends that class) receives the following arguments.

* `array $configuration`
* `$plugin_id`
* `$plugin_definition`

That's what that error message means: You defined the first parameter of the constructor to implement `Drupal\Core\Cache\CacheBackendInterface`, but it receives an array.

The `create()` method defined for your block is ignored by Drupal. If you need to pull dependencies from the container, a plugin (such as a block plugin) needs to implement `ContainerFactoryPluginInterface`, which is what the `BookNavigationBlock` class does. (The following is only part of the class code.)

```
class BookNavigationBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * Constructs a new BookNavigationBlock instance.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The current route match.
   * @param \Drupal\book\BookManagerInterface $book_manager
   *   The book manager.
   * @param \Drupal\Core\Entity\EntityStorageInterface $node_storage
   *   The node storage.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match, BookManagerInterface $book_manager, EntityStorageInterface $node_storage) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->routeMatch = $route_match;
    $this->bookManager = $book_manager;
    $this->nodeStorage = $node_storage;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition, $container->get('current_route_match'), $container->get('book.manager'), $container->get('entity_type.manager')->getStorage('node'));
  }

}

```

In your case, the class should use the following code. (I am showing what needs to be changed in the code shown in the question.)

```
namespace Drupal\sydneypro_exchange_rates_block\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\Markup;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a block with Exchange Rates.
 *
 * @Block(
 *   id = "block_exchange_rates",
 *   admin_label = @Translation("Exchange rates block"),
 * )
 */
class ExchangeRatesBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * ExchangeRatesBlock constructor.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   The cacheBackendInterface.
   * @param \GuzzleHttp\Client $http_Client
   *   The httpclient.
   * @param \Drupal\Core\Config\ImmutableConfig $immutable_config
   *   The configuration.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, CacheBackendInterface $cache_backend, Client $http_Client, ImmutableConfig $immutable_config) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->cacheBackend = $cache_backend;
    $this->httpClient = $http_Client;
    $this->config = $immutable_config;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition,
      $container->get('cache.default'),
      $container->get('http_client'),
      $container->get('config.factory')
    );
  }

}

```
> 2 votes

---
Tags: 9, plugins, dependency-injection
---


# Question
Title: How do I add additional social media platforms to the social media block in this theme?
I have found the zymphonies.com theme: `composer require 'drupal/drupal8_parallax_theme:^2.0` a useful addition to my toolkit.

It comes with a banner slideshow built in, is designed to be mobile-first responsive, and being built on top of the bootstrap framework has proven useful to helping me learn a small bit of how to use bootstrap to easily enhance the stock framework provided by the theme/framework. Many questions are easily resolved by adding bootstrap to my query strings in search engines, leading to half or one hour fixes to address client requests.

One of the features offered out of the box by this theme is a block exposed in the footer region with icons linking a site visitor to the sites' channels on various social media platforms.

And that leads me to this question, and the answer I offer below for its resolution.

How do I add support for additional social media platforms not available out-of-the-box?

# Answer
> 1 votes
I started by using a regressive grep query of the theme to learn how the platforms supported by the existing code base are accounted for.

```
jenkins@efc9c26-01112:~/sites/my_client/web/themes/contrib/drupal8_parallax_theme$ grep linkedin -R .
Binary file ./includes/fontawesome/fonts/FontAwesome.otf matches
Binary file ./includes/fontawesome/fonts/fontawesome-webfont.ttf matches
./includes/fontawesome/css/font-awesome.css:.fa-linkedin-square:before {
./includes/fontawesome/css/font-awesome.css:.fa-linkedin:before {
./templates/layout/page.html.twig:            {% if linkedin_url %}
./templates/layout/page.html.twig:              <a href="{{ linkedin_url }}" class="linkedin" target="_blank"><i class="fa fa-linkedin"></i></a>
./drupal8_parallax_theme.theme:  $variables['linkedin_url'] = theme_get_setting('linkedin_url');
./drupal8_parallax_theme.theme:  $form['drupal8_parallax_theme_settings']['social_icon']['linkedin_url'] = array(
./drupal8_parallax_theme.theme:    '#default_value' => theme_get_setting('linkedin_url'),
./config/install/drupal8_parallax_theme.settings.yml:linkedin_url: 'http://www.linkedin.com/company/zymphonies'

```

That provided the necessary clues to reverse-engineering what exists so I can replicate what I need to add. It also reveals what files I must touch to get the job done.

I turned my attention to my subtheme where my customizations get stored in a git repo so I need not reproduce these changes on every rebuild. I still have not sorted out how to make my customizations over-ride the base theme, and have resorted to copying them into the base theme on each upgrade, but hope soon enough to get a better handle of a more graceful means of getting this work done.

This work is done at this path:

```
~/sites/my_client/web/themes/contrib/drupal8_parallax_theme_my_client

```

Support for youtube was easy:

In the file: `drupal8_parallax_theme_my_client.theme`, I added this line: `$variables['youtube_url'] = theme_get_setting('youtube_url');`

And then add this stanza, adapted from the base theme, to be copied into tthe corresponding file in the base theme as part of the `drupal8_parallax_theme_form_system_theme_settings_alter()` function:

```
    $form['drupal8_parallax_theme_settings']['social_icon']['youtube_url'] = array(
        '#type' => 'textfield',
        '#title' => t('YouTube URL'),
        '#default_value' => theme_get_setting('youtube_url'),
    );

```

This should expose a configuration option at: `admin/appearance/settings/drupal8_parallax_theme_my_client`.

In the `templates/layout/page.html.twig` file, immediately after the facebook stanza.

```
    {% if youtube_url %}
        <a href="{{ youtube_url }}"  class="youtube" target="_blank" ><i class="fa fa-youtube"></i></a>
    {% endif %}

```

This should reveal the configured icon in the social media block exposed in the footer.

Next `drush cr`, configure the url in the user interface at the path mentioned above, and another `drush cr`, should expose the changes to an anonymous user.

This works because youtube's icon is already supported in the default version of fontAwesome packaged with the theme. Additional icons are apparently being added to the fontAwsome package on the regular. But waiting on he fa team's release cycle was a non-starter for a client who needs that functionality now. Upgrading the fa package at the moment apparently incurs a license fee plus the overhead of sorting out how to automate the upgrade into my build process.

So I put in a call to Adam Muehlhausen, in Indiana, with whom I was collaborating on the front-end demands for the site-under-development. I was hoping for a phone conversation with him to inform me on integrating these changes into the version-controlled sub-theme, to extend the `./includes/fontawesome/css/font-awesome.css` file included as a part of the base theme. What I got instead was an email asking me to inspect the results of his work.

We had already been making use of a module permitting one to store css and js in the database configuration, to be integrated on page build as needed. ( `composer require 'drupal/asset_injector:^2.10'` ). Without access to the backend, Adam proceeded to use his existing gui access, the firebug/ inspect-element tool in his browser and an hour or so of experimentation to add this to the .css, supported by icons he harvested from each site and uploaded into a published, but unlinked node created for this purpose.

```
/* social icons not in font-awesome */
.footer-menu .fa-gettr {
  background: url('/sites/default/files/inline-images/gettr.png') center no-repeat;
}

.footer-menu .fa-gettr {
  background-size: contain;
  width: 12px;
  height: 12px;
  vertical-align: middle;
}

.footer-menu .gettr:hover{
  -webkit-filter: invert(100%) grayscale(100%) brightness(50%) sepia(60%) hue-rotate(250deg) saturate(700%);
  -moz-filter: invert(100%) grayscale(100%) brightness(50%) sepia(60%) hue-rotate(250deg) saturate(700%);
  filter: invert(100%) grayscale(100%) brightness(50%) sepia(60%) hue-rotate(250deg) saturate(700%);
}

```

By replicating this, we were able to expose linked icons for a total of eight social media platforms, three supported by the default theme, another not, but nonetheless supported by the fontAwesome project aand another four so new as to be supported by neither.

---
Tags: theming
---


# Question
Title: What is the difference between Translation language, Translation source, and Original language?
Would anyone be able to explain to me what the difference is between "Original language", "Translation language", and "Translation source"? I think I have a pretty good idea, but for example I've added all of the above to my content overview admin view, and I translated one entity from English to German. The row for that translation in the overview table has:

* original language -\> German
* translation language -\> German
* translation source -\> English

Translation language and Translation source I assume is the language content was translated to, and Translation source was what content the translation was derived from. So, is Original language just the language that the specific content was created in? If so, how does Original language differ from Translation language? Thanks for helping me understand.

# Answer
> 1 votes
There's an open issue about "Original language" and "Translation language" at https://www.drupal.org/project/drupal/issues/2450195. Its current issue summary includes an explanation of how they're supposed to work:

> All translatable entities have a field called Original Language, which is \[base table\].langcode (e.g., node.langcode for Node entities). They also have a field called Translation Language, which is \[field data table\].langcode (e.g., node\_field\_data.langcode for Node entities). Also keep in mind that in translatable entity Views currently, each row of the view output is one translation of the entity.

So, taking nodes as the easiest example, "Original language" is supposed to be the language the node was created in (node.langcode), "Translation language" is supposed to be the language of whatever translation the view has pulled in (node\_field\_data.langcode), and "Translation source" is whatever language was used as the source for the translation (node\_field\_data.content\_translation\_source).

As of right now, that issue is seven years old and still unresolved. Until it's fixed, when you use the "Original language" field, what you'll actually get is node\_field\_data.langcode, which is the same as "Translation language". ("Original language" when used as a filter or sort does give you node.langcode, which is what it's supposed to do.)

---
Tags: i18n-l10n, 9
---


# Question
Title: Why a form doesn't keep the value created during construction
Here is a form using DI for `$this->entity_type_manager`

There is also a radio-button with Ajax (I have added the code as it is maybe the reason of my problem)

```
class myForm extends FormBase {

  private ?EntityTypeManagerInterface $entity_type_manager=NULL;

  public function __construct(Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager) {

    $this->entity_type_manager=$entity_type_manager;
  }

  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
    );
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    // keep the value in $form_state to be used in submit
    $form_state->set('entity_type_manager', $this->entity_type_manager);
    ...
    // Maybe the Ajax component is the problem
    $form['container'] = [
      '#type' => 'container',
      '#prefix' => '<div id="ajax-wrapper">',
      '#suffix' => '</div>',
      'my_radio' => [
        '#type' => 'radios',
        '#options' => ["option1","option2"],
        '#required' => TRUE,
        '#default_value' => $type_of_bo,
        '#ajax' => [
          'callback' => [$this, 'ajaxGetInvestmentHandler'],
          'wrapper' => 'ajax-wrapper',
          'event' => 'click input',
        ],
      ],
      ...
    ];
  }

  static public function ajaxGetInvestmentHandler(array $form, FormStateInterface $form_state) {
    return $form['container'];
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    // $this->entity_type_manager is NULL
    // $form_state->get('entity_type_manager') is also NULL
    ...
  }

  ...

}

```

As you can see in the `submit`, `$this->entity_type_manager` is NULL and `$form_state->get('entity_type_manager')` is also NULL.

What is wrong?

# Answer
> 2 votes
*As you can see in the submit, $this-\>entity\_type\_manager is NULL*

You need to declare the service property `protected`. Private properties can't be restored. See https://www.drupal.org/docs/drupal-apis/services-and-dependency-injection/dependency-injection-for-a-form#s-considerations-for-dependency-injection

*.. and $form\_state-\>get('entity\_type\_manager') is also NULL*

The form\_state is not cached between the first form build and the submit request. See buildForm: how differentiate between page reload and ajax callback?. And when you run the form build in later Ajax requests you overwrite the form state value with NULL.

---
Tags: forms, ajax
---


# Question
Title: How to get exposed filters for entity reference to render?
I am using a entity reference view and I am able to filter via taxonomy terms directly, but when I set it to exposed and let the user decide, it does not display on the form. How can I get the expose functionality to actually work?

It works on other things like pages and blocks, but not entity reference.

I have Views Entity Reference Filter and Better Exposed Filters already installed, but that didn't seem to fix the issue.

# Answer
Instead of a Views filter you can filter via the widget autocomplete if you add a relationship for the taxonomy field, add the taxonomy *Name* field to the field list and then select the *Name* field as search field in Format:Entity Reference list | Settings.
> 0 votes

---
Tags: views, forms, 9
---


# Question
Title: What problem does the entity reference module solve?
From the relevant documentation in drupal.org:

> Provides a field type that can reference arbitrary entities

That doesn't help understand the purpose of this feature and what problem it was created to solve.

We can already associate two entity types (say, content type and taxonomy type) by creating a node which contains both a text field and a taxonomy (type) term/s field, so, how's an "entity reference" association is different and for what common purpose?

I prefer to ask a Drupal developer here instead of reaching my own conclusion about this as a Drupal site builder.

# Answer
> 2 votes
From the perspective of site building, consider the following.

Say you allow all authenticated users to post articles, and you want to let the users categorize the articles.

To do this, you could take one of two approaches. (Of course there are more options, but we will pick two here to keep it simple.)

* Add a field of type **List (text)** to the article content type and enter all the categories in the field settings.
* Add a field of type **entity reference (taxonomy)** and set the reference to a "tags" taxonomy.

With the text list approach, you have a fixed set of categories. If you want to expand the list of categories, you can edit the list-- but users can't add their own categories unless they have permission to edit the field settings. In the real world, you would never give users such permission because then a malicious user could mess up the site by deleting all the categories or adding some profanity, etc.

However, with the entity reference approach, users can now create a category by adding a new taxonomy term-- all they need is permission to add terms to the "tags" category.

This is the advantage of entity reference-- you can make sets of entities to create useful structures, which you can then manipulate in modules like Views. What is important here is that entity reference allows you to separate concerns-- for example, you can make articles as node entities, and tags as taxonomy term entities-- instead of trying to smash everything together in one giant entity.

You can create specialized entities to accurately model each kind of data you have, and then link those together logically with entity references. This is much more maintainable over the long term than putting everything on a single entity type, which is what you would have to do if you didn't have a module like Entity Reference.

# Answer
> 1 votes
Drupal Commerce provides a good example of why entity references are necessary.

In Drupal Commerce, you have entities for lots of things, like

* Stores (you can have multiple stores or a single store)
* Products
* Orders
* Payment methods

All of these are separate entity types because a store and a product represent different things.

In Drupal, a good basic strategy is to create a different "entity" type for each "thing" you want to represent.

However, if you do that, you quickly notice there is a problem-- you have lots of "things", but how are they linked? The link is often an entity reference.

For example, when you make a order, the order should contain a reference to the products that were ordered. You also need to know what payment method was used, and which store the order was made from. Entity references are what enables you to do this.

---
Tags: entities
---


# Question
Title: Base field defined as entity reference with cardinality unlimited, only allowing one entry
I have defined a custom entity type "Event" and I want a field on it called "Attendees" which should allow the user to enter multiple attendees.

I have defined the field thus:

```
   $fields['attendees'] = BaseFieldDefinition::create('entity_reference')
  ->setLabel(t('Attendees'))
  ->setDescription(t('People attending this event.'))
  ->setSetting('target_type', 'oc_actor')
  ->setSetting('handler', 'default')
  ->setTranslatable(TRUE)
  ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
  ->setDisplayOptions('view', [
    'type' => 'string',
    'weight' => 50,
  ])
  ->setDisplayOptions('form', [
    'type' => 'entity_reference_autocomplete_tags',
    'weight' => 50,
  ])
  ->setRequired(FALSE);

```

However, the resulting field does not have unlimited cardinality. It only allows the user to enter one attendee. Compare and contrast with the "Test" field that I added beneath it using the GUI:

I have done a fresh install of the whole site since I last touched this code so it is not a matter of needing to add an update hook or clear the cache or anything like that.

Any ideas?

# Answer
You have it set to entity\_reference\_autocomplete\_tags which means the multiple values end up comma separated. You probably want just entity\_reference\_autocomplete.
> 3 votes

---
Tags: entities, 9
---


# Question
Title: How do I translate view's page path alias?
I'm able to translate views titles and menus thanks to `config_translation` core module. I would like to have path aliases translated as well but it seems to lack this feature. Any other way to do it?

# Answer
> 11 votes
On my multilingual Drupal 8 sites, I go to `/admin/config/search/path/add` for adding URL alias, which asks you to select a language for this alias.

Is this what you were looking for?

# Answer
> 2 votes
I was looking exactly for that and finally I contrib with the fixed path alias module, just create the alias for the views page as mentioned before and set it as fixed to be exported into config. The alias will be re-created on the fly when required if not found.

# Answer
> 1 votes
You can manage your translated aliases with the Pathauto module, which will automatically create a translated URL Alias from the translated node Title. The URL alias will be constructed from a pre-configured Pathauto "Pattern" and will be automatically managed and updated.

# Answer
> 1 votes
I had same issue and I have done this way:

first create view page with alias, for example "alias-test"

then go to admin/config/search/path and click "add alias"

choose language you want to translate, in my case I choose "PT"

on "existing system path" write your path "alias-test" and in "path alias" added alias translation "teste-alias"

This works with language swticher, if you have more than 2 languages you have to repeat this process to all languages you want to translate

# Answer
> 1 votes
Please try https://www.drupal.org/project/tvp and see if it helps. I have built this module for similar use case.

---
Tags: views, 8, path-aliases
---


# Question
Title: How do I dynamically (AJAX) show radios in form API?
A form like the following is expected to show additional fields when user selected "Yes" in the "Show more" radio button. When shown, the more section has a "Name" text field, and a "Gender" radios set.

But it never works as expected. The "Gender" label will be there, but the radio buttons are never rendered. I know changing "Gender" into radios would work, but for some reason, I need to use multiple radio buttons. Is there any way I can make this work?

```
<?php

namespace Drupal\mymodule\Form;

use Drupal\Core\Form\FormBase;

class DonationPrepareForm extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'my_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(
    array $form,
    FormStateInterface $form_state
  ) {
    $form['show_more'] = [
      '#type' => 'radios',
      '#title' => 'Show more',
      '#options' => [
        'Y' => 'Yes',
        'N' => 'No',
      ],
      '#ajax' => [
        'callback' => '::ajaxBuildForm',
        'wrapper' => 'edit-more-wrapper',
        'progress' => [
          'type' => 'throbber',
          'message' => $this->t('Loading...'),
        ],
      ],
    ];
    $form['more'] = [
      '#type' => 'container',
      '#prefix' => '<div id="edit-more-wrapper">',
      '#suffix' => '</div>',
    ];

    return $form;
  }

  public function ajaxBuildForm(array &$form, FormStateInterface $form_state)
  {
    if ($form_state->getValue('show_more') === 'Y') {
      $form['more']['name'] = [
        '#type' => 'textfield',
        '#title' => 'Name',
        '#required' => TRUE,
      ];
      $form['more']['gender'] = [
        '#type' => 'radios',
        '#title' => 'Gender',
        '#options' => [
          'M' => 'Male',
          'F' => 'Female',
        ],
        '#required' => TRUE,
      ];
    }
    return $form['more'];
  }
}

```

Same question extends to other composite form elements (e.g. Checkboxes). Is there any way to make AJAX work for them?

# Answer
Move form building to buildForm(). You can't build form elements in an Ajax callback (I've also renamed the callback method to make this clear):

```
<?php

namespace Drupal\mymodule\Form;

use Drupal\Core\Form\FormBase;

class DonationPrepareForm extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'my_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
     $form['show_more'] = [
      '#type' => 'radios',
      '#title' => 'Show more',
      '#options' => [
        'Y' => 'Yes',
        'N' => 'No',
      ],
      '#ajax' => [
        'callback' => '::ajaxCallback',
        'wrapper' => 'edit-more-wrapper',
        'progress' => [
          'type' => 'throbber',
          'message' => $this->t('Loading...'),
        ],
      ],
    ];
    $form['more'] = [
      '#type' => 'container',
      '#prefix' => '<div id="edit-more-wrapper">',
      '#suffix' => '</div>',
    ];

    if ($form_state->getValue('show_more') === 'Y') {
      $form['more']['name'] = [
        '#type' => 'textfield',
        '#title' => 'Name',
        '#required' => TRUE,
      ];
      $form['more']['gender'] = [
        '#type' => 'radios',
        '#title' => 'Gender',
        '#options' => [
          'M' => 'Male',
          'F' => 'Female',
        ],
        '#required' => TRUE,
      ];
    }

    return $form;
  }

  public function ajaxCallback(array &$form, FormStateInterface $form_state) {
    return $form['more'];
  }
}

```
> 1 votes

# Answer
Actually it is significantly easier to use form element #states property to make an element visible , invisible , enabled , disabled , required or ... rather than using ajax

A code like this will do the job:

```
<?php

namespace Drupal\mymodule\Form;

use Drupal\Core\Form\FormBase;

class DonationPrepareForm extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'my_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(
    array $form,
    FormStateInterface $form_state
  ) {
    $form['show_more'] = [
      '#type' => 'radios',
      '#title' => 'Show more',
      '#options' => [
        'Y' => 'Yes',
        'N' => 'No',
      ],
    ];

    $form['more']['name'] = [
      '#type' => 'textfield',
      '#title' => 'Name',
      '#states' => array(
        'visible' => array(
          ':input[name="show_more"]' => array('value' => 'Y'),
        ),
        'required' => array(
          ':input[name="show_more"]' => array('value' => 'Y'),
        )
      ),
    ];
    $form['more']['gender'] = [
      '#type' => 'radios',
      '#title' => 'Gender',
      '#options' => [
        'M' => 'Male',
        'F' => 'Female',
      ],
      '#states' => array(
        'visible' => array(
          ':input[name="show_more"]' => array('value' => 'Y'),
        ),
        'required' => array(
          ':input[name="show_more"]' => array('value' => 'Y'),
        )
      ),
    ];

    return $form;
  }

```

}
> 2 votes

---
Tags: forms, ajax, 9
---


title: Set Body Class if Facet is active

text:
# Question
Title: Set Body Class if Facet is active
I need to set a body class if a facet filter is active.

It should be done in yourtheme\_preprocess\_html

```
if Facet is active
then
$variables['attributes']['class'][] = 'facet-active';

```

for fulltext search terms it works like that

```
  $variables['attributes']['class'][] = 'search-' . \Drupal::request()->query->get('search_api_fulltext');

```

Anyone know how to dig out the information if a facet is active or not.

thanks in advance

Matthias

# Answer
> 2 votes
You don't know when the HTML template is rendered whether a facet is active or not. So in mytheme\_preprocess\_html() assume it is not:

```
$variables['attributes']['class'][] = 'facet-is-not-active-class';

```

In the facets block replace the placeholder class if the block is visible:

```
function mytheme_preprocess_block(&$variables) {
  if ($variables['configuration']['provider'] == 'facets') {
    if (!in_array('hidden', (array) $variables['attributes']['class'])) {
      $variables['#attached']['placeholders']['facet-is-not-active-class'] = [
        '#markup' => 'facet-active',
      ];
    }
  }
}

```

Important is that the placeholder string `facet-is-not-active-class` is unique, use a longer name or even a hash. Placeholders are replaced for all occurrences of the string on the page.

**Issue with nested placeholders**

This works only for blocks not auto-placeholdered. The facet block, unfortunately, is always placeholdered. It sets cache max-age 0 which meets the default condition for auto-placeholdering. See https://www.drupal.org/docs/drupal-apis/render-api/auto-placeholdering#s-what

To prevent that you can set #create\_placeholder to FALSE:

```
/**
 * Implements hook_block_build_BASE_BLOCK_ID_alter().
 */
function mymodule_block_build_facet_block_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
  $build['#create_placeholder'] = FALSE;
}

```

Caveat: This is a real performance killer, it doubles the page loading times in my tests. So if performance is important you probably should look for a client-side solution, better CSS or a javascript library which adds the necessary classes.

---
Tags: theming
---


# Question
Title: Where do source trees for different versions of contrib modules reside?
I made a contrib module that has a 7.x version. I just created an 8.x version. Do I create a branch within the existing 7.x version for the new code, or create a separate version for the 8.x? If they share the same module, do I switch to the 8.x branch, then delete the 7.x code and add the 8.x code?

# Answer
It is ordinary and expected to use a single Git repo for multiple release versions. The release naming conventions are documented. That includes branch naming.

You will check out the Drupal 7 branch of the project then type `git checkout -b <new-branch-name>`, where the new branch name is according to the conventions above (and is probably `1.x` or `1.0.x` because semantic versioning is now possible). Then you will upgrade the code to be compatible with Drupal 9, commit, and push the new branch.
> 1 votes

---
Tags: version-control
---


title: Content Type Hierarchy

text:
# Question
Title: Content Type Hierarchy
I'm fairly new to Drupal have content types that loop in children content types using fields. The result is something like this.

```
Office Content Type
Field: Office Content Type
- Office Content Type
- Field: Person Content Type
- Field: Person Content Type
- Field: Person Content Type
- Office Content Type
-- Field: Office Content Type
-- Field: Person Content Type
-- Field: Person Content Type

```

I need a content type to be able to recognize it has a parent or grandparent. However this directory was created using content types for the offices instead of taxonomies. Is it possible to pull hierarchical information from nested content types? Should the Office Content Type have been created as a taxonomy instead?

Links to details and documentation is welcome.

I'm using Drupal 9.3.x

# Answer
I came to a solution using a preprocess function. A key/value pair is added to the parent node. Named "headline\_level" it is later referenced by the child and +1 is added. That number is assigned to a twig variable as the headline's number, "headline\_level" is increased by 1 for the child if itself has children.

In this image we see a parent "office" pulling in child nodes as fields.

Level Diagram

```
Parent (h1)
|_ Child (h2) (see image)
   |_ Grandchild (h3)
      |_ Great GrandChild (h4)

```

Preprocess Function for theme

```
function THEME_preprocess_HOOK(&$variables) {
  $node = $variables['node'];

    /**
     * Parent Headline Level
     * Displays logical headline structure
     * Applies higher value to 'headline_level' for subordinate content types; used in '/templates/node--HOOK.html.twig'
     */
    if ($node->_referringItem) {
      // Variables
      $counter = 1; // start level at 1

      // Append 'headline_level' to HOOK node
      $node->headline_level = $counter;
      $parentHeadline = $node->_referringItem->getEntity()->headline_level;

      // Check node for $parentHeadline else $counter, set twig variable
      if (isset($parentHeadline)) {
        // Increase 'headline_level' by 1
        ++$parentHeadline; // add 1
        $node->headline_level = $parentHeadline;
        $variables['office_headline_level'] = $parentHeadline;
      } else {
        $variables['headline_level'] = $counter;
      }
    }

```

Twig Template for Content Type

```
  <div>
    <h{{ headline_level ?: 2 }}>{{ label }}</h{{ headline_level ?: 2 }}>
    {{ content.field_people }}
  </div>

```

As mentioned in the comments, these Offices should have been a Taxonomy. However, they were created as content types and referenced by fields.
> 0 votes

---
Tags: 9
---


# Question
Title: Access A Referenced Node's Fields - Field Level Templating
I have a content type with a reference field to another content type. This allows an unlimited amount of entries.

I've created a template for this field: `field--node--field-my-fields.html.twig`

I want to be able to access the fields of my referenced node. Usually you can do this by accessing the entity, but I can't seem to do this.

```
{% for item in items %}
  {{ kint(item.content) }}
{% endfor %}

```

I feel like this should be really simple, but I just can't find a way to get access to the fields!

Thanks in advance for any answers.

# Answer
> 5 votes
In `item.content` is a render array and usually you can access a referenced entity in a '#' key (for most display settings):

```
{{ item.content['#node'].field_name.value }}

```

**Field Object**

Another way to get the field values is using the field object in `element['#items']` and loop through the FieldItemList:

```
{% for item in element['#items'] %}
    {{ item.entity.field_name.value }}
{% endfor %}

```

Then you are independent from the display settings of the field.

For background information see this blog post from Berdir https://www.md-systems.ch/blog/techblog/2017/02/20/twig-and-entity-field-api-or-how-to-take-control-of-nodehtmltwig for the difference between formatted output and the underlying objects. In a field template you don't need to go back to the parent node object, because you can access directly the field object. You can get the parent node from `element['#object']` though, if you want to access other fields.

# Answer
> 0 votes
Using preprocess function on MYTHEME.theme file you can :

```
function MYTHEME_preprocess_field(&$variables, $hook) {
  ...
  $element = $variables['element'];
  $title  = $element['#object']->getTitle();
  $variables['title']['#markup'] = $title;
  ...
}

```

At this point, in field.twig you have the `{{ title }}` variable

# Answer
> 0 votes
If you require to Access A Referenced Node's title in fields twig template just do this

```
{{ item.content['#node'].title.value }}

```

for the images it is better go for Twig tweak snippets like i did:

```
{% set public_url = item.content['#node'].field_image[0]|file_uri %}
{{ drupal_image(public_url,'', {alt: 'Promo Event image'|t, title: ''|t}) }}

```

---
Tags: theming, entities
---


# Question
Title: Different bar colors for each poll choice?
I know how to change ALL of the bar colors - but how do I code it so each choice bar is a different color? I basically just need code to append the number to the "bar" class, so it would read "bar-1" , "bar-2" etc.

# Answer
jQuery can help you in this regard if you not going to edit templates.

```
(function(){
   var i=0;
   jQuery('div.poll .bar .foreground').each(function(){
        i++;
        switch(i){
            case 1:
                $(this).css('background-color', '#color')
            break;
             ...
         }

    });
})();

```
> 0 votes

# Answer
This is not simple without patchs in `poll.module` and `poll-bar.tpl.php`.

**PATCH: poll.module** Adding an additional parameter (i.e. choice id)

```
/**
 * Implementation of hook_theme()
 */
function poll_theme() {
  return array(
    ....
    'poll_bar' => array(
      'template' => 'poll-bar',
      'arguments' => array(
          'title' => NULL,
          'votes' => NULL,
          'total_votes' => NULL,
          'vote' => NULL,
          'block' => NULL,
          'choice_id' => null), // An additional param
    ),
  );
}

```

Changes where theme('poll\_bar') is invoked. NOTE: `$i` is passed as last param

```
  foreach ($node->choice as $i => $choice) {
    if (!empty($choice['chtext'])) {
      $chvotes = isset($choice['chvotes']) ? $choice['chvotes'] : NULL;
      $poll_results .= theme('poll_bar',
                $choice['chtext'],
                $chvotes,
                $total_votes,
                isset($node->vote) && $node->vote == $i,
                $block,
                $i, // The additional param
                );
    }
  }

```

**PATCH: poll-bar.tpl.php** Adding classes to div.bar as `choice-x`

```
<div class="text"><?php print $title; ?></div>
<div class="bar choice-<?php print $choice_id;?>">
  <div style="width: <?php print $percentage; ?>%;" class="foreground"></div>
</div>
<div class="percent">
  <?php print $percentage; ?>% (<?php print format_plural($votes, '1 vote', '@count votes'); ?>)
</div>

```
> 0 votes

# Answer
Consider trying CSS Pseudo-classes. Specifically have a look at :nth-of-type() where you can specify specific colors for each instance of a class or tag in the theme's CSS.
> 0 votes

---
Tags: polls
---


# Question
Title: How do I read element attribute from $form_state?
I am trying to hide entity id from my autocomplete fields. I downloaded a jquery script that removes the bracketed id and updates the autocomplete element with the new element. It then writes the entire value to the element's data like this

```
$(event.target).data('real-value','6');

```

I even updated this to use attr instead of data, I cant read this information from my Drupal form\_state.

I set a data attribute on my autocomplete element using jquery like this

```
$(event.target).attr('real-value','6');

```

How do I get this value from my $formstate or $form object in my form submit function? Using `dpm($form['elementname'])` doesn't even show this atrribute.

I've tried `$formstate->getValue()`. Doesn't work?

Here's the script I'm using...

hide autocomplete id jquery

Just wondering why does the jquery successfully change the value of the autocomplete textbox, but cant change an attribute on the same element?

# Answer
This is impossible as written. Drupal's Form system does not have information about attributes added solely by JavaScript.

Drupal's Form system does not have information about attributes *modified* solely by JavaScript.
> 1 votes

---
Tags: 8, forms
---


title: Cannot make page--node--nid to work

text:
# Question
Title: Cannot make page--node--nid to work
I created the *page--node-112.html.twig* template file for a Page\* node whose ID is 112. Drupal is still using the *page--page.html.twig* template file.

How can I make Drupal use the template file I created?

# Answer
> 1 votes
None of the Drupal core modules and themes suggests `'page__' . $bundle`. If that suggestion is added by a module (or a theme) after the suggestions added by `system_theme_suggestions_page()`, which is the hook that suggests `'page__node__' . $nid`, that suggestion is picked up first, since suggestions are checked from the last to the first.

The code that checks for which of the suggestions there is a template file is in `ThemeManager::render()`.

```
  // Check if each suggestion exists in the theme registry, and if so,
  // use it instead of the base hook. For example, a function may use
  // '#theme' => 'node', but a module can add 'node__article' as a suggestion
  // via hook_theme_suggestions_HOOK_alter(), enabling a theme to have
  // an alternate template file for article nodes.
  foreach (array_reverse($suggestions) as $suggestion) {
    if ($theme_registry->has($suggestion)) {
      $info = $theme_registry->get($suggestion);
      break;
    }
  }

```

Without a module adding that suggestion, *page--node-112.html.twig* is not a template file Drupal core would pick up.

# Answer
> 0 votes
Enable Twig Debugging, that will add comments including template file names that can be used to override less specific templates.

The comments look something like this and you can view them in source or your browser's inspector.

```
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'page' -->
<!-- FILE NAME SUGGESTIONS:
   * page--node--6178.html.twig
   * page--node--%.html.twig
   * page--node--article.html.twig
   * page--node.html.twig
   x page.html.twig
-->

```

In the above example you can see my page is being rendered using page.html.twig but I have alternatives above that which could be used specific to my content type (article) or node a single id.

---
Tags: theming
---


# Question
Title: Modify cart view to allow direct quantity updates
In want to modify the cart view so that when costumer change quantity of item in cart, it will update cart and total price automatically and immediately through AJAX (instead of when pressing button update cart through page reload).

# Answer
The short, general, answer is: use the Forms Ajax API. It’s difficult to provide a longer answer here. Another respondent may know of a commerce module that does this.
> 0 votes

---
Tags: 7, commerce, ajax
---


# Question
Title: How to check which module db updates have been applied?
For a specific module, how can I check which database updates have been applied in Drupal 9? I've downloaded a database from a server and I want to check what the current module schema is.

In Drupal 7, this was in the `system` database table, but that no longer exists.

# Answer
> 3 votes
### For Drupal 9.3+/10:

`drush php-eval "echo \Drupal::service('update.update_hook_registry')->getInstalledVersion('mymodule');"`

Source: Change record

### For Drupal 8/9 up to 9.3:

`drush php-eval "echo drupal_get_installed_schema_version('mymodule');"`

Source: gist

---
Tags: database, 9
---


# Question
Title: Ajax callback not working with 'language_select' in drupal 8 forms
I'm trying to implement an ajax callback whenever language gets changed. Following code I have used:

```
public function buildForm(array $form, FormStateInterface $form_state) {
$language = \Drupal::languageManager()->getCurrentLanguage()->getId();
$langcode = $from_database->lid;
$form['langcode'] = array(
           '#title' => $this->t('Language'),
           '#type' => 'language_select',
           '#default_value' => !empty($langcode) ? $langcode : $language,
           '#languages' => Language::STATE_ALL,
           '#ajax' => array(
        'callback' => ::ajax_example_autocheckboxes_callback',
        'wrapper' => 'checkboxes-div',

       ) ,
       );

$form['checkboxes_fieldset'] = array(
  '#title' => t("Generated Checkboxes"),
  // The prefix/suffix provide the div that we're replacing, named by
  // #ajax['wrapper'] above.
  '#prefix' => '<div id="checkboxes-div">',
  '#suffix' => '</div>',
  '#type' => 'fieldset',
  '#description' => t('This is where we get automatically generated    checkboxes'),
 );
}

function ajax_example_autocheckboxes_callback($form, $form_state) {
  return $form['checkboxes_fieldset'];
}

```

But ajax callback is not working. Suggest a way to implement ajax on language select.

# Answer
Try adding a container. It works for me:

```
public function buildForm(array $form, FormStateInterface $form_state){
    $current_user = \Drupal::currentUser();
    $user_preferred_langcode = $current_user->getPreferredLangcode();

    // The status messages that will contain any form errors.
    $form['status_messages'] = [
     '#type' => 'status_messages',
     '#weight' => -10,
    ];

    $form['title'] = [
      '#type' => 'html_tag',
      '#tag' => 'h2',
      '#value' => t('Change Language'),
    ];

    $form['preferred_langcode'] = [
      '#type' => 'language_select',
      '#languages' => LanguageInterface::STATE_CONFIGURABLE,
      '#default_value' => $user_preferred_langcode,
      '#ajax' => [
        'callback' => [$this, 'languageCallback'],
        'event' => 'change',
        'wrapper' => 'language-wrapper',
      ],
    ];

    $form['language_wrapper'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'language-wrapper'],
    ];

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

   if(empty($preferred_langcode) || $user_preferred_langcode ==
$preferred_langcode) {
      $form['language_wrapper']['default_language'] = [
        '#type' => 'html_tag',
        '#tag' => 'p',
        '#value' => $this->t('Your Current Language'),
      ];
    }

    $form_state->setCached(FALSE);

    return $form;
  }

  public function languageCallback(array $form, FormStateInterface $form_state) {
    return $form['language_wrapper'];
  }

```
> 0 votes

# Answer
**If using a non-trivial form element like `language_select`, you need to supply the AJAX `event` attribute.** This is because `RenderElement::preRenderAjaxForm()` knows default `event` values for very basic field types only. This also holds for Drupal 9.

```
$form['preferred_langcode'] = [
  '#title' => $this->t('Language'),
  '#type' => 'language_select',
  '#languages' => LanguageInterface::STATE_CONFIGURABLE,
  '#ajax' => [
    'callback' => [$this, 'languageCallback'],
    'event' => 'change',
  ],
];

```
> 0 votes

---
Tags: forms, 8, ajax
---


# Question
Title: What does "Entity API >= 8.x-1.0-alpha3 module is now a dependency and needs to be installed before running updates" during drush updatedb mean?
I am doing a Drupal 8.6.18 to 8.9.19 update via composer.

After upgrading the packages via composer, I updated the database, which shows a warning:

```
$ vendor/bin/drush updatedb
<a href="https://www.drupal.org/project/entity">Entity API >= 8.x-1.0-alpha3</a>
 module is now a dependency and needs to be installed before running updates.
 (Currently using Media entity Entity API missing)
 [error]
Requirements check reports errors. Do you wish to continue? (y/n):

```

Continuing works, but I am a little scared.

What is the background of this message?

drupal/entity is already at version 1.3.0:

```
$ composer show drupal/entity
[...]
versions : * 1.3.0

```

What is interesting, is that `pm:info` does not show a version information for the `entity` module. Is this maybe the reason?

```
$ vendor/bin/drush pm:info entity
 Extension        :  entity
 Project          :  Unknown
 Type             :  module
 Title            :  Entity
 Description      :  Provides expanded entity APIs, which will be moved to Drupal core one day.
 Package          :  Other
 PHP              :  7.0.8
 Status           :  enabled
 Path             :  modules/contrib/entity
 Schema version   :  8000
 Requires         :  none
 Required by      :  media_entity, media_entity_document, media_entity_embeddable_video, media_entity_image, video_embed_media, foodservice_core, foodservice_globalelement, foodservice_product, foodservice_recipe, foodservice_video
 Permissions      :  none
 Configure        :  None

```

I have already read https://www.drupal.org/project/media\_entity/issues/2722073, which comes to the conclusion that the entity module needs to be enabled. But it is in my case.

# Answer
> 2 votes
I think I found the reason. I was having `docroot/modules/contrib/entity` checked out from `https://git.drupalcode.org/project/entity.git` via composer. The git version does not seem to have a version field and then causes problems.

The underlying reason is, that before the update I was having this requirement:

```
"drupal/entity": "1.x-dev",

```

This instructs composer to clone the dev repo.

When updating I changed this to

```
"drupal/entity": "^1.2",

```

No composer could theoretically download the release-ZIP, but because the folder is already there it seems to just checkout the new version.

Deleting that folder `docroot/modules/contrib/entity` and `composer install` \+ cache rebuild solved the problem.

---
Tags: 8, drush
---


# Question
Title: How to change the position of status message for an embedded node?
I have an embedded node that uses JavaScript.

I have added a message.

```
const messages = new Drupal.Message();
messages.add(
  Drupal.t('Please select option'),
  { type: 'error' }
);

```

The message is shown at the top of the page. How can i move the message to the top of the embedded node instead?

(embedded node is at the bottom of the original node)

# Answer
> 1 votes
I was unable to use status message block. I found out that i could change the position of message like this:

```
const messages =  new Drupal.Message(document.querySelector('#data-gallup-messages'))
messages.add(
    Drupal.t('Please select option'),
    { type: 'error' }
  );
}

```

and of-course the div i assign the message to needs to exist in twig.

```
<div id='data-gallup-messages'></div>

```

# Answer
> 0 votes
Drupal status messages are shown in the **Status messages** block. You can configure where that block is placed at `/admin/structure/block`.

The exact placement of the block depends on your theme's available regions.

---
Tags: 9
---


# Question
Title: 'Edit Own Content' permission missing in custom entity
I have generated a custom entity using Drupal Console.

```
drupal generate:entity:content

```

The entity doesn't have the permission `edit own content` which we usually have in node types etc... The entities `entity_name.permissions.yml` the file has the following enteries.

```
add company entities:
  title: 'Create new Company entities'

administer company entities:
  title: 'Administer Company entities'
  description: 'Allow to access the administration form to configure Company entities.'
  restrict access: true

delete company entities:
  title: 'Delete Company entities'

edit company entities:
  title: 'Edit Company entities'

access company overview:
  title: 'Access the Company overview page'

view published company entities:
  title: 'View published Company entities'

view unpublished company entities:
  title: 'View unpublished Company entities'

```

I tried understanding, how this is done in node. But in node types permission file also I couldn't find this permission entered.

# Answer
> 3 votes
Like other content entities, the Node entity has an access control class, `NodeAccessControlHandler`, whose purpose is giving users the permission to view, edit, delete (in `NodeAccessControlHandler::access()`), or create a node (in `NodeAccessControlHandler::createAccess()`).
`NodeAccessControlHandler::checkAccess()` (indirectly called from `NodeAccessControlHandler::access()`) uses the values returned from `hook_node_grants()` and `hook_node_access_records()` to extend or restrict the permissions users have on a node.

`NodePermissions::nodeTypePermissions()`, which is added in the node.permissions.yml file as permission callback, defines additional permissions for the content types.
That method calls `NodePermissions::buildPermissions()`, which returns an array of permissions.

```
  return [
    "create {$type_id} content" => [
      'title' => $this->t('%type_name: Create new content', $type_params),
    ],
    "edit own {$type_id} content" => [
      'title' => $this->t('%type_name: Edit own content', $type_params),
    ],
    "edit any {$type_id} content" => [
      'title' => $this->t('%type_name: Edit any content', $type_params),
    ],
    "delete own {$type_id} content" => [
      'title' => $this->t('%type_name: Delete own content', $type_params),
    ],
    "delete any {$type_id} content" => [
      'title' => $this->t('%type_name: Delete any content', $type_params),
    ],
    "view {$type_id} revisions" => [
      'title' => $this->t('%type_name: View revisions', $type_params),
      'description' => t('To view a revision, you also need permission to view the content item.'),
    ],
    "revert {$type_id} revisions" => [
      'title' => $this->t('%type_name: Revert revisions', $type_params),
      'description' => t('To revert a revision, you also need permission to edit the content item.'),
    ],
    "delete {$type_id} revisions" => [
      'title' => $this->t('%type_name: Delete revisions', $type_params),
      'description' => $this->t('To delete a revision, you also need permission to delete the content item.'),
    ],
  ];

```

The Node module has also its own `hook_ENTITY_TYPE_access()`, `node_node_access()`. That hook changes which users are allowed to update or delete a node.

What the Node module does to give access to nodes is probably not the best example to follow when creating a new entity. The Node module uses `hook_node_grants()` and `hook_node_access_records()` for backward compatibility; new entity classes could just use an access handler that implements the `access()` and `checkAccess()` methods, and eventually define a permission handler in the *.permission.yml* file.

# Answer
> 3 votes
A little surprised how easy this was to fix; but it seems to be working.

Console originally created permissions similar to what @esefwan posted and in MyEntityAccessConrtolHandler.php it created this code:

```
  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
    /** @var \Drupal\reserve\Entity\MyEntityInterface $entity */
    switch ($operation) {
      case 'view':
        if (!$entity->isPublished()) {
          return AccessResult::allowedIfHasPermission($account, 'view unpublished myentity');
        }
        return AccessResult::allowedIfHasPermission($account, 'view published myentity');

      case 'update':
        return AccessResult::allowedIfHasPermission($account, 'edit myentity entities');

      case 'delete':
        return AccessResult::allowedIfHasPermission($account, 'delete myentity entities');
    }

    // Unknown operation, no opinion.
    return AccessResult::neutral();
  }

```

Looking at the code in node.module under node\_node\_access() i ended up modifying the above to this:

```
  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
    /** @var \Drupal\reserve\Entity\ReserveReservationInterface $entity */
    switch ($operation) {
      case 'view':
        if (!$entity->isPublished()) {
          $access = AccessResult::allowedIfHasPermission($account, 'view unpublished myentity');
        }
        $access = AccessResult::allowedIfHasPermission($account, 'view published myentity');
        break;

      case 'update':
        $access = AccessResult::allowedIfHasPermission($account, 'edit any myentity');
        if (!$access->isAllowed() && $account->hasPermission('edit own myentity')) {
          $access = $access->orIf(AccessResult::allowedIf($account->id() == $entity->getOwnerId())->cachePerUser()->addCacheableDependency($entity));
        }
        break;

      case 'delete':
        $access =  AccessResult::allowedIfHasPermission($account, 'delete any myentity');
        break;

      // Unknown operation, no opinion.
      default:
        $access = AccessResult::neutral();
    }

    return $access;
  }

```

# Answer
> 1 votes
I'm not sure if Drupal Console has been updated since you asked the question, but what you'll find now is that it defines a set of permissions, but also adds an annotation to the class that defines your entity, something like this:

```
  handlers = {...
    "access" = "Drupal\my_module\MyModuleAccessControlHandler"
    ...
  }

```

The AccessControlHandler file will be in your src directory and if you add permissions in the permissions.yml file, you can edit responses to those, using the node\_node\_access function as an example, as explained in Milos's comment.

# Answer
> 1 votes
I tested this in ***Drupal 9.3.0*** (View, Edit and Delete operations):

```
  /**
   * {@inheritdoc}
   */
  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
    /** @var \Drupal\password_locker_entities\Entity\PasswordInterface $entity */

    switch ($operation) {
      case 'view':
        $access = AccessResult::allowedIfHasPermission($account, 'view any password entities');
        if (!$access->isAllowed() && $account->hasPermission('view own password entities')) {
          $access = $access->orIf(AccessResult::allowedIf($account->id() == $entity->getOwnerId())->cachePerUser()->addCacheableDependency($entity));
        }
        break;

      case 'update':
        $access = AccessResult::allowedIfHasPermission($account, 'edit any password entities');
        if (!$access->isAllowed() && $account->hasPermission('edit own password entities')) {
          $access = $access->orIf(AccessResult::allowedIf($account->id() == $entity->getOwnerId())->cachePerUser()->addCacheableDependency($entity));
        }
        break;

      case 'delete':
        $access =  AccessResult::allowedIfHasPermission($account, 'delete any password entities');
        if (!$access->isAllowed() && $account->hasPermission('delete own password entities')) {
          $access = $access->orIf(AccessResult::allowedIf($account->id() == $entity->getOwnerId())->cachePerUser()->addCacheableDependency($entity));
        }
        break;

      // Unknown operation, no opinion.
      default:
        $access = AccessResult::neutral();
    }

    return $access;
  }

```

# Answer
> 0 votes
I added two additional permissions in my permissions.yml file (view own and edit own...) and altered the checkAccess by adding the following conditions in the switches. Everything was initially created by drush generate.

<pre><code>  /**
   * {@inheritdoc}
   */
  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {

    $uid = $entity->getOwnerId();

    switch ($operation) {
      case 'view':
        if ($account->id() != $uid) {
          return AccessResult::allowedIfHasPermission($account, 'view company');
        }
        elseif ($account->id() == $uid) {
          return AccessResult::allowedIfHasPermissions($account, ['view company, view own company'], 'OR');
        }
        break;
      case 'update':
        if ($account->id() != $uid) {
          return AccessResult::allowedIfHasPermissions($account, ['edit company', 'administer company'], 'OR');
        }
        elseif ($account->id() == $uid) {
          return AccessResult::allowedIfHasPermissions($account, ['edit own company', 'administer company', 'edit company'], 'OR');
        }
        break;
      case 'delete':
        return AccessResult::allowedIfHasPermissions($account, ['delete company', 'administer company'], 'OR');

      default:
        // No opinion.
        return AccessResult::neutral();
    }

  }```
</code></pre>

# Answer
> 0 votes
On custom entities, you usually would want something like "create / edit / delete" own entities, with access purely based on own entities. To do this, check the

modules/custom/mymodule/mymodule.permissions.yml with the following:

```
administer own mycustomentityname:
 title: 'Create/edit/delete own mycustomentityname'

```

Then in your **src/MyEntityAccessHandler.php** checkAccess method:

```
 case 'edit':
   if ($account->hasPermission('administer own mycustomentityname')) {
     $access = AccessResult::allowedIf($account->id() == $entity->getOwnerId())->cachePerUser()->addCacheableDependency($entity);
   }

```

Source: Start with custom entities & Learn Drupal as a framework

It is nice to have a entity generator like drush does, but from my experience you can set it up with less files quickly and you have more control.

---
Tags: 8, entities
---


# Question
Title: Is it possible to export a website into a native application?
Say I have built a web application which does a certain well defined procedure such as medical self diagnosis with Drupal core only and I want to export it as a \*nix executable (Android?) native application.

Is there any way to do it Drupal 9 (or should be, in Drupal 10)?

# Answer
> 2 votes
No, you cannot "export" Drupal into a native app.

A fairly common scenario is to use Drupal as the **backend** for native mobile apps-- in that case, you have a webserver running Drupal and then you make some apps (iOS, Android, etc.) and connect them to Drupal via REST, JSON:API, or GraphQL.

In this case, you have two or more codebases:

* Drupal
* Your apps that talk to Drupal (could be iOS, Android, or a frontend like React, Angular, etc.)

Can you use Drupal as the app itself though for Android or iOS? No, not really. You would have to run Drupal on some kind of webserver that would be bundled into the app, which is probably disallowed by Apple and Google and, in any case, is an unnecessarily complicated way of making a mobile app.

I have been building iOS and Android apps with Drupal using Ionic and had good results. Ionic lets you use a frontend such as Angular, React, or Vue, and then you can create one codebase that lets you generate Android and iOS apps as well as a PWA. This can talk to Drupal via JSON:API and works reasonably well, but it's a bunch of additional work on top of getting the Drupal site working-- you have to build the Ionic app using a non-Drupal technology stack.

---
Tags: 9
---


# Question
Title: Change order of elements in a Webform Variant
I am trying to figure out if it is possible to change the order of elements in a webform variant.

Using a very simple example form with two elements, I created a new variant and then overrode the "Elements" yaml two different ways, neither which changed the order of the elements on the form.

First, I simply switched the order of the elements in the yml, which didn't change anything. Second, I added a `#weight` attribute to each element with different values - this had no effect as well.

Is it possible to change the order of elements in a variant?

thanks,
-mike

# Answer
Your need to reorder elements makes sense. The #weight attribute is currently ignored because it can cause unpredictable rendering. I don't think a Variant can reorder elements without patching the webform module.
> 1 votes

# Answer
Albeit brute-force, theoretically you might be able to do this via a custom variant plugin type.

```
class MyVariant extends WebformVariantBase {
  // ...
  // ...

  /**
   * {@inheritdoc}
   */
  public function applyVariant() {
    $webform = $this->getWebform();
    $elements = $webform->getElementsDecoded();

    $element_to_move = $elements['element_to_move'];
    $new_position = array_search('element_to_insert_after', array_keys($elements), TRUE);
    $before = array_slice($elements, 0, $new_position);
    $after = array_slice($elements, $new_position, count($elements) - $new_position);
    $new_elements = $before + ['element_to_move' => $element_to_move] + $after;
    $webform->setElements($new_elements);

    return TRUE;
  }
}

```
> 0 votes

---
Tags: webforms
---


# Question
Title: Display decimal field without right side zeros
I have a decimal field for length (cm) with precision 2. If I enter number without '.' it should display as it is only. For example If I enter 23 it should display 23 only not 23.00. If I enter 23.14 it should display 23.14. How can I do that? Am I missing any thing here?

Sorry, editing my question:

It should display the numbers like following (in Full node view, Views, Forms and wherever it appears)

If any one entered 93 it should be displayed 93 only not 93.00 (cause of the scale 2).

If entered 93.40 it should be displayed 93.4

If entered 93.14 it should be displayed as 93.14 only

I know that the value will be saved with scale 2(As given in Fields Form) in the database. But the value should be displayed as a whole number etc

# Answer
You can format the field from Manage Display as follow:

1. Go to manage display of the respective entity
2. Click on settings button of the field to do formatting
3. Change the value of Scale dropdown to zero
4. Click update
5. Click Save button at bottom
> 0 votes

# Answer
I needed the same thing. After some experimenting, I found that if you can change the Decimal field to a **Float**, you can then select *Unformatted* display format. That shows whole numbers without the trailing decimal and zero.
> 0 votes

---
Tags: nodes
---


# Question
Title: How do you correctly filter on taxonomy terms to get all nodes matching term or parent term?
I have a vocabulary (channel) with two levels. An article node can be added to the first or second level (via field\_channel). The hierarchy looks like:

* channel-1
    + subchannel-1.1
    + subchannel-1.2
    + subchannel-1.3
* channel-2 *(i.e. \[node/1, node/2\])*
    + subchannel-2.1 *(i.e. \[node/4, node/5\])*
    + subchannel-2.2 *(i.e. \[node/6\])*

I want to filter all nodes that belongs to a term of level 1 (the ones which where assigned directly to the term and the ones which where assigned to one of its child terms).

In other words, filtering all nodes for a given channel (i.e. channel-2) should contain the nodes assigned to that channel directly and all nodes assigned to a sub-channel whose parent channels is that channel. In the example all nodes from 1 to 6.

The JSON:API request looks like:

```
{{base_url}}/node/article?
include=field_channel,field_channel.parent&
fields[node--article]=title,field_channel&
fields[taxonomy_term--channel]=name,parent&
filter[or-group][group][conjunction]=OR&
filter[channel][condition][path]=field_channel.name&
filter[channel][condition][value]=channel-2&
filter[channel][condition][memberOf]=or-group&
filter[channel-parent][condition][path]=field_channel.parent.name&
filter[channel-parent][condition][value]=channel-2&
filter[channel-parent][condition][memberOf]=or-group

```

I don't see the error, but it only contains the nodes matching the channel-parent condition. If I remove that condition, the ones matching the channel condition are there. What is wrong with the request.

I also tried the short form:

```
{{base_url}}/node/article?
fields[node--article]=title,field_channel&
include=field_channel,field_channel.parent&
fields[taxonomy_term--channel]=name,parent&
filter[or-group][group][conjunction]=OR&
filter[field_channel.name][value]=channel-2&
filter[field_channel.name][memberOf]=or-group&
filter[field_channel.parent.name][value]=channel-2&
filter[field_channel.parent.name][memberOf]=or-group

```

Which gives me an error in the where clause (the empty group at the beginning):

> WHERE (() and (taxonomy\_term\_field\_data.name LIKE :db\_condition\_placeholder\_0 ESCAPE '\\\')

BTW: The example could be easily build by using the drupal thunder distribution.

# Answer
As the problem may appear for entity types other than taxonomy-terms I briefly explain how to investigate the issue:

I found, that the same query worked well for the admin user, but not for the limited jsonapi consumer. Granting taxonomy related permissions helped, when the jsonapi consumer had the permission "administer taxonomy", which led me to the following hook\_jsonapi\_ENTITY\_TYPE\_filter\_access implementation in docroot/core/modules/jsonapi/jsonapi.module

```
/**
 * Implements hook_jsonapi_ENTITY_TYPE_filter_access() for 'taxonomy_term'.
 */
function jsonapi_jsonapi_taxonomy_term_filter_access(EntityTypeInterface $entity_type, AccountInterface $account) {
  // @see \Drupal\taxonomy\TermAccessControlHandler::checkAccess()
  return ([
    JSONAPI_FILTER_AMONG_ALL => AccessResult::allowedIfHasPermission($account, 'administer taxonomy'),
    JSONAPI_FILTER_AMONG_PUBLISHED => AccessResult::allowedIfHasPermission($account, 'access content'),
  ]);
}

```

Then I implemented the same hook in my custom module with custom permissions and now it works as expected.

I had problems with filtering on paragraphs in past, which has a similar solution, see issue on paragraphs module It is not possible to filter paragraphs via JSON:API.

Looking at hook\_jsonapi\_ENTITY\_TYPE\_filter\_access() implementations in jsonapi.module suggests that this problem might occur for other entities if the api consumer does not have the corresponding permissions.
> 0 votes

---
Tags: taxonomy-terms
---


# Question
Title: How to do twig calculation for mathematical operation in view
I have two fields. Marks obtained as `field_marks_obtained` Total Marks as `field_total_marks` Now I have added both in view and added a custom text in which i am writing custom twig to output the percentage. I have tried with

`{{ field_marks_obtained }}` which gives me output as 359.00

`{{ field_marks_obtained + field_total_marks}}` giving result as 2.

`{{ field_marks_obtained * field_total_marks}}` giving result as 1

How can i do arithmetic operation with twig. I have also tried with

`{% set marks = field_marks_obtained * 1 %}{{ marks }}` which also returns 1

# Answer
`{% set marks = field_marks_obtained|trim %}`

`{% set total = field_total_marks|trim %}`

You can do any complex calculation in twig like this.

`{{ (marks/total)*100 }}`
> 7 votes

# Answer
Use raw database values for calculation. Most times rendered output doesn't work, because it contains strings or render arrays, not numbers.

I think you are referring to field rewriting in the Views fields UI, then open REPLACEMENTS PATTERN and you'll find this information:

> You must add some additional fields to this display before using this field. These fields may be marked as Exclude from display if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.
>
> The following replacement tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.
>
> * {{ field\_number }} == Number
> * {{ field\_number\__value }} == Raw value

So you need to add `__value` to each field name.
> 1 votes

# Answer
In Drupal view, below solution worked for me

{% set wgt = weight | trim %} {% set qty = quantity | trim %} {{ wgt\*qty }}
> -1 votes

---
Tags: views, theming
---


title: Dependency injection in FieldItemList

text:
# Question
Title: Dependency injection in FieldItemList
I'm creating a few custom classes that extend FieldItemList and they need some services injected.

I've had a look at core classes that extend that class and none of them do dependency injection, they all call \Drupal::service().

Is there a way to inject services here or should I follow the core pattern?

# Answer
> 1 votes
The field type plugin manager instantiates both, FieldItem and FieldItemList via the typed data manager:

*Drupal\Core\Field\FieldTypePluginManager*

```
  public function createFieldItemList(FieldableEntityInterface $entity, $field_name, $values = NULL) {
    // Leverage prototyping of the Typed Data API for fast instantiation.
    return $this->typedDataManager->getPropertyInstance($entity->getTypedData(), $field_name, $values);
  }

  public function createFieldItem(FieldItemListInterface $items, $index, $values = NULL) {
    // Leverage prototyping of the Typed Data API for fast instantiation.
    return $this->typedDataManager->getPropertyInstance($items, $index, $values);
  }

```

To be able to inject services you need to wait until this issue Allow typed data plugins to receive injected dependencies is resolved.

---
Tags: 9, dependency-injection
---


title: Multiple forms on page

text:
# Question
Title: Multiple forms on page
I am trying to get multiple forms to work in a views display. All of the forms uses AJAX, but they appear to be interfering with each other.

One form is the Views Bulk Operations form that turns the views table into a 'viewsForm'. The second form is a 'quick edit' form available on each row in the view. The problem is when I submit any of the forms from the quick edit, it tries to also submit the 'viewsForm' form (which it shouldn't be doing), resulting in validation errors on that form. It's also not picking up my ajax callback for my custom form, as witnessed by the 'ajax callback is empty or not callable' in the dblog.

If I disable views bulk operations, this works as intended, but with multiple forms on the page, I can't figure out how to tell the 'submit' button I am using to only submit the form belonging to the submit button.

I have provided my formbuilder class for reference

```
<?php

namespace Drupal\request_system\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Ajax\HightlightCommand;

/**
 * Provides a Request System form.
 */
class QuickEditForm extends FormBase {

  public $sub_id = 0;
  public $entity_id = 0;

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'request_system_quick_edit-' . $this->sub_id;
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    $entity = \Drupal::entityTypeManager()->getStorage('lms_request')->load($this->entity_id);

    $options = [];

    $options['_none'] = '- Select One -';

    if ($entity->bundle() == 'book_request') {
      $statuses = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
        'vid' => 'book_request_status',
      ]);
    }

    // Only show 'available from vendor' and 'Pending'
    foreach ($statuses as $status) {
      if ($status->getName() == 'Pending' || $status->getName() == 'Available From Vendor') {
        $options[$status->id()] = $status->getName();
      }

      if ($status->id() == $entity->field_request_status->getString()) {
        $options[$status->id()] = $status->getName();
      }
    }

    $form['quick_edit'] = [
      '#type' => 'container',
      '#id' => 'quick-edit-wrapper-'. $this->sub_id,
    ];

    $form['quick_edit']['status'] = [
      '#type' => 'fieldset',
      '#title' => 'Status Updates',
      '#name' => 'update-wrapper',
    ];

    if (!$entity->field_aph_shipment_number->isEmpty() || !$entity->field_library_shipment_number->isEmpty()) {
      $form['quick_edit']['status']['value'] = [
        '#type' => 'item',
        '#title' => 'Request Status: ',
        '#markup' => \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($entity->field_request_status->getString())->getName(),
      ];

      // Display message indicating item is part of a shipment
      $form['quick_edit']['status']['shipment_number'] = [
        '#markup' => 'This request is part of a shipment.',
      ];
    }
    else {
      // Disable this field if the request status is not 'Pending' or 'Available from Vendor', or if the item belongs to a shipment
      $form['quick_edit']['status']['value'] = [
        '#type' => 'select',
        '#title' => 'Status',
        '#options' => $options,
        '#default_value' => $entity->field_request_status->getString(),
      ];

      if ($entity->field_request_status->getString() != \Drupal\request_system\Controller\RequestSystemController::getStatus('Pending') && $entity->field_request_status->getString() != \Drupal\request_system\Controller\RequestSystemController::getStatus('Available From Vendor')) {
        $form['quick_edit']['status']['value']['#disabled'] = TRUE;
      }
    }

    $form['quick_edit']['status']['message'] = [
      '#type' => 'textarea',
      '#title' => $this->t('Message'),
    ];

    $form['quick_edit']['status']['notify_user'] = [
      '#type' => 'checkbox',
      '#title' => 'Notify Borrower',
    ];

    // Allow editing of the APH catalog #

    $form['quick_edit']['other'] = [
      '#type' => 'fieldset',
      '#title' => 'Other',
      '#name' => 'other-wrapper',
    ];

    $form['quick_edit']['other']['aph_catalog_number'] = [
      '#type' => 'textfield',
      '#title' => 'APH Catalog #',
      '#default_value' => $entity->field_attached_copy_aph_number->getString(),
      '#description' => $entity->field_attached_copy_main_record->isEmpty() ? '' : 'Unable to change APH catalog number when a main record is assigned.',
      '#disabled' => $entity->field_attached_copy_main_record->isEmpty() ? FALSE : TRUE,
    ];

    $form['quick_edit']['id'] = [
      '#type' => 'hidden',
      '#value' => $this->entity_id,
    ];

    $form['quick_edit']['actions'] = [
      '#type' => 'actions',
    ];
    $form['quick_edit']['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save'),
      '#ajax' => [
        'callback' => '::quickEditAjax',
        'wrapper' => 'quick-edit-wrapper-'. $this->sub_id,
      ],
      '#validate' => '::validate',
      '#limit_validation_errors' => [['id'],['status']],
      '#submit' => ['::quickEditAjaxSubmit'],
    ];

    // $form['quick_edit']['actions']['cancel'] = [
    //   '#type' => 'submit',
    //   '#value' => 'Cancel',
    // ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();

    $entity = \Drupal::entityTypeManager()->getStorage('lms_request')->load($values['id']);

    if ($values['status'] == \Drupal\request_system\Controller\RequestSystemController::getStatus("Shipped From Loan Library")) {
      if (count($entity->field_imcid->referencedEntities()) == 0) {
        $form_state->setErrorByName('status','Cannot mark this item shipped since no library item is attached.');
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {

  }

  public function quickEditAjax(&$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();

    if ($form_state->hasAnyErrors()) {
      $form['status_messages'] = [
        '#type' => 'status_messages',
        '#weight' => -1000,
      ];
      $form['#sorted'] = FALSE;
    }

    $response = new AjaxResponse();

    $status = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($values['status']);
    $response->addCommand(new ReplaceCommand('.request-status-'. $values['id'],$status->getName()));
    $response->addCommand(new ReplaceCommand('#quick-edit-wrapper-'. $this->sub_id,$form));
    $response->addCommand(new HightlightCommand('#row-'. $values['id']));

    return $response;
  }

  public function quickEditAjaxSubmit(&$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();

    // First load the entity
    $entity = \Drupal::entityTypeManager()->getStorage('lms_request')->load($values['id']);

    $entity->set('field_request_status',$values['status']);
    $entity->save();

    $form_state->setRebuild();
  }

}

```

And the way I am rendering the form is via

```
$form = \Drupal::classResolver()->getInstanceFromDefinition('Drupal\request_system\Form\QuickEditForm');
$form->sub_id = $entity->id();
$form->entity_id = $entity->id();
$build['form'] = \Drupal::formBuilder()->getForm($form);

```

It appears that when the view is rendered, it's combining all of the forms into a single , so when you click 'Save' on the sub-form, it's actually submitting the views bulk operations form. I am not sure how to resolve this or to get it to stop doing this.

I have been banging my head on this for two weeks trying to get this resolved, and can't figure out what the problem is.

Any help would be GREATLY appreciated.

EDIT: I have attached a screenshot of what we are trying to achieve. Checkbox on the left is views bulk operation, 'quick edit' form is on the far right via 'expandable table column'

# Answer
> If I disable views bulk operations, this works as intended, but with multiple forms on the page, I can't figure out how to tell the 'submit' button I am using to only submit the form belonging to the submit button.

Without reviewing the entire code, if you have multiple Ajax forms on a page it should help to use unique submit form keys the same way you do this for the wrapper:

```
$form['quick_edit']['actions']['submit' . $this->sub_id] = [
  ...
  '#ajax' => [
    'callback' => '::quickEditAjax',
    'wrapper' => 'quick-edit-wrapper-'. $this->sub_id,
  ],

```

---

In the other case, you can't nest forms as discussed in the comments.

In general you need to place your form elements inside the existing form, which then can do their own thing using submit and ajax callbacks and ignoring the rest of the form. This can be done in a simple form alter hook or a more complicated system. For entity forms Drupal has subforms implemented in field widget plugins, for Views bulk forms field plugins implementing `viewsForm($form, $form_state)`. If you use one of those then go along with the way they do it.
> 0 votes

---
Tags: forms, ajax, 9
---


# Question
Title: Node access based on the user reference field
I have a content type that is used for temporary access. The node is created and has an expiration date; it's deleted after that date. On this node there is a user reference field; only the users added to this field should have access to viewing this node. I can't find a hook to handle this access. In Drupal 7 I used `hook_node_access()`, but it doesn't seem to exist for Drupal 9.

The only information I'm looking for is how to tap into the access privileges for a given node type. After that I can handle the logic of what users are contained in the reference field.

# Answer
Drupal 9 still uses `hook_node_access()`. It's documented under `hook_ENTITY_TYPE_access()` because it's invoked for every existing entity, not just for the Node entity.
If *mymodule* is the module that implements that hook for the Node entity, the function implementing the hook would be `mymodule_node_access()`, exactly as in Drupal 7. The Drupal 7 code still needs to be ported to Drupal 9, as many details changed between Drupal 7 and Drupal 9.

If then you need to check the access for different entities, you could implement `hook_entity_access()`.
> 0 votes

---
Tags: 9
---